TicTacToe Game with classes.

Hello fellow coders,

I'm working on a project in which I'm utilizing classes to code a tictactoe game. Everything runs smoothly up until the moment i check for winners. The program seems to be finding the winner, but instead of displaying the message, it's exiting immediately. I don't know what could be causing the problem.
This is my first project and I'd like to make it as nice as possible. What do you think is causing the problem?

Any other thoughts/recommendations on what I should improve or fix are accepted.

Below is my class, function definitions and main. I intend to make separate files once im done with the whole thing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  #include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;

class tictactoe {
public: 
	tictactoe();
	//default CTOR, initializes our board and moves counter.
	void displayBoard()const;
	//displays our board through each iteration.
	void getMove(char player);
	//asks the user for his move, once received, checks if move is valid
	//and if so stores move in board for next iteration.
	void playGame();
	//creates a loop in order to play the game.
private: 
	static const int BSIZE = 3; //board size
	static const int maxMoves = 9; //max moves possible in a game of ttt
	static const int minMovesToWin = 5; //min moves before checking for win
	char board[BSIZE][BSIZE]; //our board
	int totalMoves; //moves counter
	bool checkForWins(char player)const;
	//takes in the player sign
	//checks board (rows, colums and diagonals) to see if we have foudn a winner
	bool checkForDraw()const;
	//checks to see if max number of moves has been reached.
	// if so it's a tie
	void fill_board();
	//fills our 3*3 array of blank spaces
	char togglePlayer(char player);
	//changes the player sign at the end of the turn
	
};

tictactoe::tictactoe(){
	totalMoves = 0;
	fill_board();
	}

void tictactoe::fill_board() {
	for (int row = 0; row < BSIZE; row++) {
		for (int col = 0; col < BSIZE;col++) {
			board[row][col] = ' ';
		}
	}
}
void tictactoe::displayBoard()const {
	cout << " --------------\n";
	for (int row = 0; row < BSIZE; row++) {
		cout << " | ";
		for (int col = 0; col < BSIZE; col++) {
			cout <<  board[row][col] << "  |";
		}
	
		cout << "\n --------------\n";
	}
}
void tictactoe::getMove(char player){
	//variables
	string input; //stores our input
	char char_entered; //takes the character entered for evaluation
	int num_entered, row, col, index; //help set our play on the board.
	
	while (true) {
		cout << player << " Where do you want to play? Select a number from 1-9: " << endl;
		getline(cin, input);

		if (input != "") {
			//Since we are checking for a correct move
			//we convert string into a cstring for easier comparison.
			char_entered = input.c_str()[0];
			if (char_entered >= '1' && char_entered <= '9') {
				//If the input is between the desired range, convert it into an int.
				num_entered = char_entered - '0';
				//Use this number to find index and store the move into our board.
				index = num_entered - 1; //this way if user enters 1 it means index 0 of board.

				//we can use division and the remainder, in order to find the correct row and column. 
				row = index / 3; 
				col = index % 3; 
				//check if the position on the board is empty (correct move), else it's wrong move.
				char b_pos = board[row][col];
				if (b_pos != 'X' && b_pos != 'O') {
					//if correct move, place mark on board and we can move onto the next turn
					board[row][col] = player;
					totalMoves++;
					break; 
				}
				else
					cout << "Wrong move. Position is already taken. Try again" << endl;
			}
			else
				cout << "You must enter a number between 1-9 to make your move." 
				<< "Try again. \n";
		}
		else 
			cout << "You must enter something!!" << endl;
	}
	cout << "Total moves: " << this->totalMoves << endl;
}

char tictactoe::togglePlayer(char player) {
	
	player = player == 'X' ? 'O' : 'X';
	return (player);
}

bool tictactoe::checkForWins(char player)const{
	
	//only check for a winner once the min moves to win has been reached.
	if (totalMoves >= minMovesToWin) {
		//check rows for winner
		if (board[0][0] == player && board[0][1] == player && board[0][2] == player) {
			return true;
		}
		if (board[1][0] == player && board[1][1] == player && board[1][2] == player)
		{
			return true;
		}
		if (board[2][0] == player && board[2][1] == player && board[2][2] == player)
		{
			return true;
		}
		//columns 
		if (board[0][0] == player && board[1][0] == player && board[2][0] == player)
		{
			return true;
		}
		if (board[0][1] == player && board[1][1] == player && board[2][1] == player)
		{
			return true;
		}
		if (board[0][2] == player && board[1][2] == player && board[2][2] == player)
		{
			return true;
		}
		//Accross
		if (board[0][0] == player && board[1][1] == player && board[2][2] == player)
		{
			return true;
		}
		if (board[0][2] == player && board[1][1] == player && board[2][0] == player)
		{
			return true;
		}

	}
	return false;

}

bool tictactoe::checkForDraw()const{
	return totalMoves == maxMoves;
}

void tictactoe::playGame(){
	char player = 'X'; //initialize the player.
	bool gameOver = false;
	//single game iteration
	do {
		displayBoard();
		getMove(player);
		if (checkForWins(player)) {
			cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
			 << player << "WINS!!";
			gameOver = true;
		}
		else if (checkForDraw()) {
			cout << "IT'S A DRAW! Play again!" << endl;
			gameOver = true;
		}
		player = togglePlayer(player);
	} while (!gameOver);

	displayBoard();
}




int main() {
	tictactoe game;
	game.playGame();
	return 0;
}
Last edited on
When I run it from the shell it worked.
What input did you try ?

--------------
 |    |   |   |
 --------------
 |    |   |   |
 --------------
 |    |   |   |
 --------------
X Where do you want to play? Select a number from 1-9: 
1
Total moves: 1
 --------------
 | X  |   |   |
 --------------
 |    |   |   |
 --------------
 |    |   |   |
 --------------
O Where do you want to play? Select a number from 1-9: 
4
Total moves: 2
 --------------
 | X  |   |   |
 --------------
 | O  |   |   |
 --------------
 |    |   |   |
 --------------
X Where do you want to play? Select a number from 1-9: 
2
Total moves: 3
 --------------
 | X  |X  |   |
 --------------
 | O  |   |   |
 --------------
 |    |   |   |
 --------------
O Where do you want to play? Select a number from 1-9: 
5
Total moves: 4
 --------------
 | X  |X  |   |
 --------------
 | O  |O  |   |
 --------------
 |    |   |   |
 --------------
X Where do you want to play? Select a number from 1-9: 
3
Total moves: 5

 *********** WE HAVE A WINNER!! ***********
XWINS!! --------------
 | X  |X  |X  |
 --------------
 | O  |O  |   |
 --------------
 |    |   |   |
 --------------
There is nothing wrong with your program. It works just fine. However, when the program completes, the program closes so fast that you can't see the end of it. You will need to put a pause into your program. There are a couple of ways to do this...

One trick is this line...
1
2
system("pause");
return 0;


Adding a system pause before return 0 will cause a pause. But this method is operating system dependent. It works on a microsoft windows computer.

Another trick...
1
2
cin.get();
return 0;


Putting the get before return 0 will make the program wait for the player to press enter before closing.
Thanks for the reply! Will definitely try that and see what happens. I’ll let you know if I run into any other issue.
Hello, I've continued to add some new things to the game such as a simple rand AI and a menu, and now I've run into a few bugs:

#1 After the user makes the choice for playing vs ai or user and the game starts, it's taking that input and immediately reading it as a player move, it is displaying: "you must enter something!!"

#2 At the end of the playVsAI loop, if the game ends up beign a draw, the board doesnt display the last move made unlike the playGame (play vs human) loop.

Any ideas on how to fix this??
Updated code below!
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using std::cout;
using std::cin;
using std::endl;
using std::string;

class tictactoe {
public: 
	tictactoe();
	//default CTOR, initializes our board and moves counter.
	void displayBoard()const;
	//displays our board through each iteration.
	void getUserMove(char player);
	//asks the user for his move, once received, checks if move is valid
	//and if so stores move in board for next iteration.
	
	void compMove(char player);
	//simulates the computer move (turn)
	
	void playGame();
	//creates a loop in order to play the game.

	void playVsAI();
	//Simulates a single game iteration vs the computer.
	//initialize srand for computer choice.
    friend char menu();
	//
	friend void command();

private: 
	static const int BSIZE = 3; //board size
	static const int maxMoves = 9; //max moves possible in a game of ttt
	static const int minMovesToWin = 5; //min moves before checking for win
	char board[BSIZE][BSIZE]; //our board
	int totalMoves; //moves counter
	bool checkForWins(char player)const;
	//takes in the player sign
	//checks board (rows, colums and diagonals) to see if we have foudn a winner
	bool checkForDraw()const;
	//checks to see if max number of moves has been reached.
	// if so it's a tie
	void fill_board();
	//fills our 3*3 array of blank spaces
	char togglePlayer(char player);
	//changes the player sign at the end of the turn
	
};

tictactoe::tictactoe(){
	totalMoves = 0;
	fill_board();
	}

void tictactoe::fill_board() {
	for (int row = 0; row < BSIZE; row++) {
		for (int col = 0; col < BSIZE;col++) {
			board[row][col] = ' ';
		}
	}
}
void tictactoe::displayBoard()const {
	cout << " --------------\n";
	for (int row = 0; row < BSIZE; row++) {
		cout << " | ";
		for (int col = 0; col < BSIZE; col++) {
			cout <<  board[row][col] << "  |";
		}
	
		cout << "\n --------------\n";
	}
}
void tictactoe::getUserMove(char player){
	//variables
	string input; //stores our input
	char char_entered; //takes the character entered for evaluation
	int num_entered, row, col, index; //help set our play on the board.
	int player_turn;
	if (player == 'X') {
		player_turn = 1;
	}
	 else {
		player_turn = 2;
	}
	while (true) {
		cout << "Player " << player_turn << " Where do you want to play? Select a number from 1-9: " << endl;
		getline(cin, input);

		if (input != "") {
			//Since we are checking for a correct move
			//we convert string into a cstring for easier comparison.
			char_entered = input.c_str()[0];
			if (char_entered >= '1' && char_entered <= '9') {
				//If the input is between the desired range, convert it into an int.
				num_entered = char_entered - '0';
				//Use this number to find index and store the move into our board.
				index = num_entered - 1; //this way if user enters 1 it means index 0 of board.

				//we can use division and the remainder, in order to find the correct row and column. 
				row = index / 3;
				col = index % 3;
				//check if the position on the board is empty (correct move), else it's wrong move.
				char b_pos = board[row][col];
				if (b_pos != 'X' && b_pos != 'O') {
					//if correct move, place mark on board and we can move onto the next turn
					board[row][col] = player;
					totalMoves++;
					break;
					//otherwise let the user know.
				}
				else
					cout << "Wrong move. Position is already taken. Try again" << endl;
			}
			else
				cout << "You must enter a number between 1-9 to make your move."
				<< "Try again. \n";
		}
		else
			cout << "You must enter something!!" << endl;
	}
	cout << "Total moves: " << totalMoves << endl; //no need for this-> since var can be accessed by memfunctions
}

char tictactoe::togglePlayer(char player) {
	
	player = player == 'X' ? 'O' : 'X';
	return (player);
}

bool tictactoe::checkForWins(char player)const{
	
	//only check for a winner once the min moves to win has been reached.
	if (totalMoves >= minMovesToWin) {
		//check rows for winner
		if (board[0][0] == player && board[0][1] == player && board[0][2] == player) {
			return true;
		}
		if (board[1][0] == player && board[1][1] == player && board[1][2] == player)
		{
			return true;
		}
		if (board[2][0] == player && board[2][1] == player && board[2][2] == player)
		{
			return true;
		}
		//columns 
		if (board[0][0] == player && board[1][0] == player && board[2][0] == player)
		{
			return true;
		}
		if (board[0][1] == player && board[1][1] == player && board[2][1] == player)
		{
			return true;
		}
		if (board[0][2] == player && board[1][2] == player && board[2][2] == player)
		{
			return true;
		}
		//Accross
		if (board[0][0] == player && board[1][1] == player && board[2][2] == player)
		{
			return true;
		}
		if (board[0][2] == player && board[1][1] == player && board[2][0] == player)
		{
			return true;
		}

	}
	return false;

}

bool tictactoe::checkForDraw()const{
	return totalMoves == maxMoves;
}

void tictactoe::playGame(){
	char player = 'X'; //initialize the player.
	bool gameOver = false;
	//single game iteration
	do {
		displayBoard();
		getUserMove(player);
		if (checkForWins(player)) {
			cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
			 << player << " WINS!!" << endl;
			gameOver = true;
		}
		else if (checkForDraw()) {
			cout << "IT'S A DRAW! Play again!" << endl;
			gameOver = true;
		}
		player = togglePlayer(player);
	} while (gameOver != true);

	displayBoard();
}
void tictactoe::compMove(char player) {
	srand(time_t(NULL)); //place seed for our rand choice.
	while (true) {

		int computer_choice = (rand() % 9) + 1;
		int row = (computer_choice - 1) / 3;
		int col = (computer_choice - 1) % 3;
		char bpos = board[row][col]; //position on the board.
		//check if position is empty or not
		if (bpos == 'X' || bpos == 'O') { //if taken then lets make another choice.
			continue;
		}
		else { //otherwise place comp places its mark!
			cout << "Computer will play at: " << computer_choice << endl;
			board[row][col] = player;
			totalMoves++;
			break;
		}
	}
	cout << "Total moves: " << totalMoves << endl;
}
void tictactoe::playVsAI() {
	char player = 'X'; //initialize the player.
	bool gameOver = false;
	//single game iteration vs computer
	
	do {
		displayBoard();
		getUserMove(player);// human player
		if (checkForWins(player)) { //check human win
			cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
				<< player << " WINS!!" << endl;
			gameOver = true;
		}
		else if (checkForDraw()) {
			cout << "IT'S A DRAW! Play again!" << endl;
			gameOver = true;
		}
		player = togglePlayer(player);
		compMove(player); //comp player
		if (checkForWins(player)) { //check human win
			cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
				<< player << " WINS!!" << endl;
			gameOver = true;
		}
		else if (checkForDraw()) {
			cout << "IT'S A DRAW! Play again!" << endl;
			gameOver = true;
		}
		player = togglePlayer(player);

	} while (gameOver!= true);
	displayBoard();
}

char menu() {
	char choice;
	cout << "******WELCOME TO TICTACTOE BY EMILIANO G.******" << endl;
	cout << "Press 1 to play vs another human player." << endl;
	cout << "Press 2 to play vs AI" << endl;
	cout << "Press 0 to quit game" << endl;
	cin >> choice;
	return choice;
}
void command(){
	char command;
	tictactoe *game;
	do {
		command = menu();
		switch (command) {
		case '1':
			game = new tictactoe;
			game->playGame();
			break;
		case '2':
			game = new tictactoe;
			game->playVsAI();
			break;
		}
		system("pause");
	} while (command != '0');
	exit(0);
}

//menu will initialize and display options to play vs ai or human player.
//depending on choice, it will create an object of the class
//access function playGame if human, playVsAI if user wants to play 
//vs ai
//play vs ai ft will initiliaze a srand(time(NULL)) for the pc's move

int main() {

	//display menu
	command();
	//prevents game from exiting too fast and not displaying the winner.
	cin.get();
	return 0;
}
You have leftover junk in your buffer that the getline is grabbing.
You can fix like so...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void command() {
	char command;
	tictactoe *game;
	do {
		command = menu();
		switch (command) {
		case '1':
			cin.ignore(); //add here
			game = new tictactoe;
			game->playGame();
			break;
		case '2':
			cin.ignore(); //add here
			game = new tictactoe;
			game->playVsAI();
			break;
		}
		system("pause");
	} while (command != '0');
	exit(0);
}
Topic archived. No new replies allowed.