Tic Tac Toe Algorithm Trouble

Pages: 12
Hi everybody. I just made a topic here and it took posting that to figure out what was wrong with my last problem, but now I have an entirely different problem.
I'm making a game of Tic Tac Toe in which you are pitted against an AI opponent. All seems to work properly except for one very crucial part;
The AI seems to give up after 2 or 3 turns.

I've stepped through my code, and it appears to be running through the move algorithms, but it doesn't make a move. If anyone could shed some light onto this, it would be very much appreciated

Here is the code:

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
// This is the .h
#include <iostream>

int gameSquares[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
bool compFirst = false;
bool lineMade = false;
int movesMade = 0;

void FirstGo()
{
	char answer;
	std::cout << "Now that you know how to play, would you like to\nmake the first move?y/n\n\n\n";
	std::cin >> answer;
	if (answer == 'y' || answer == 'Y') compFirst = false;
	else if (answer == 'n' || answer == 'N') compFirst = true;
}

bool GameWon()
{
	if (gameSquares[0] != 0 && gameSquares[0] == gameSquares[1] && gameSquares[1] == gameSquares[2] ||
		gameSquares[0] != 0 && gameSquares[0] == gameSquares[3] && gameSquares[3] == gameSquares[6] ||
		gameSquares[1] != 0 && gameSquares[1] == gameSquares[4] && gameSquares[4] == gameSquares[7] ||
		gameSquares[2] != 0 && gameSquares[2] == gameSquares[4] && gameSquares[4] == gameSquares[6] ||
		gameSquares[2] != 0 && gameSquares[2] == gameSquares[5] && gameSquares[5] == gameSquares[8] ||
		gameSquares[3] != 0 && gameSquares[3] == gameSquares[4] && gameSquares[4] == gameSquares[5] ||
		gameSquares[6] != 0 && gameSquares[6] == gameSquares[7] && gameSquares[7] == gameSquares[8] ||
		gameSquares[8] != 0 && gameSquares[8] == gameSquares[4] && gameSquares[4] == gameSquares[0]) return true;
	else return false;
}

bool PossibleWin()
{
	if (gameSquares[0] != 0 && gameSquares[0] == gameSquares[1] || gameSquares[0] != 0 && gameSquares[0] == gameSquares[2] ||
		gameSquares[0] != 0 && gameSquares[0] == gameSquares[3] || gameSquares[0] != 0 && gameSquares[0] == gameSquares[4] ||
		gameSquares[0] != 0 && gameSquares[0] == gameSquares[6] || gameSquares[0] != 0 && gameSquares[0] == gameSquares[8] ||
		gameSquares[1] != 0 && gameSquares[1] == gameSquares[2] || gameSquares[1] != 0 && gameSquares[1] == gameSquares[4] ||
		gameSquares[1] != 0 && gameSquares[1] == gameSquares[7] || gameSquares[2] != 0 && gameSquares[2] == gameSquares[4] ||
		gameSquares[2] != 0 && gameSquares[2] == gameSquares[5] || gameSquares[2] != 0 && gameSquares[2] == gameSquares[6] ||
		gameSquares[2] != 0 && gameSquares[2] == gameSquares[8] || gameSquares[3] != 0 && gameSquares[3] == gameSquares[4] ||
		gameSquares[3] != 0 && gameSquares[3] == gameSquares[5] || gameSquares[3] != 0 && gameSquares[3] == gameSquares[6] ||
		gameSquares[4] != 0 && gameSquares[4] == gameSquares[5] || gameSquares[4] != 0 && gameSquares[4] == gameSquares[6] ||
		gameSquares[4] != 0 && gameSquares[4] == gameSquares[7] || gameSquares[4] != 0 && gameSquares[4] == gameSquares[8] ||
		gameSquares[5] != 0 && gameSquares[5] == gameSquares[8] || gameSquares[6] != 0 && gameSquares[6] == gameSquares[7] ||
		gameSquares[6] != 0 && gameSquares[6] == gameSquares[8] || gameSquares[7] != 0 && gameSquares[7] == gameSquares[8]) return true;
	else return false;
}

void WinBlock()
{
	if(gameSquares[0] != 0 && gameSquares[0] == gameSquares[1]) gameSquares[2] = 1;
	else if(gameSquares[0] != 0 && gameSquares[0] == gameSquares[2]) gameSquares[1] = 1;
	else if(gameSquares[0] != 0 && gameSquares[0] == gameSquares[3]) gameSquares[6] = 1;
	else if(gameSquares[0] != 0 && gameSquares[0] == gameSquares[4]) gameSquares[8] = 1;
	else if(gameSquares[0] != 0 && gameSquares[0] == gameSquares[6]) gameSquares[3] = 1;
	else if(gameSquares[0] != 0 && gameSquares[0] == gameSquares[8]) gameSquares[4] = 1;
	else if(gameSquares[1] != 0 && gameSquares[1] == gameSquares[2]) gameSquares[0] = 1;
	else if(gameSquares[1] != 0 && gameSquares[1] == gameSquares[4]) gameSquares[7] = 1;
	else if(gameSquares[1] != 0 && gameSquares[1] == gameSquares[7]) gameSquares[4] = 1;
	else if(gameSquares[2] != 0 && gameSquares[2] == gameSquares[4]) gameSquares[6] = 1;
	else if(gameSquares[2] != 0 && gameSquares[2] == gameSquares[5]) gameSquares[8] = 1;
	else if(gameSquares[2] != 0 && gameSquares[2] == gameSquares[6]) gameSquares[4] = 1;
	else if(gameSquares[2] != 0 && gameSquares[2] == gameSquares[8]) gameSquares[5] = 1;
	else if(gameSquares[3] != 0 && gameSquares[3] == gameSquares[4]) gameSquares[5] = 1;
	else if(gameSquares[3] != 0 && gameSquares[3] == gameSquares[5]) gameSquares[4] = 1;
	else if(gameSquares[3] != 0 && gameSquares[3] == gameSquares[6]) gameSquares[0] = 1;
	else if(gameSquares[4] != 0 && gameSquares[4] == gameSquares[5]) gameSquares[3] = 1;
	else if(gameSquares[4] != 0 && gameSquares[4] == gameSquares[6]) gameSquares[2] = 1;
	else if(gameSquares[4] != 0 && gameSquares[4] == gameSquares[7]) gameSquares[1] = 1;
	else if(gameSquares[4] != 0 && gameSquares[4] == gameSquares[8]) gameSquares[0] = 1;
	else if(gameSquares[5] != 0 && gameSquares[5] == gameSquares[8]) gameSquares[2] = 1;
	else if(gameSquares[6] != 0 && gameSquares[6] == gameSquares[7]) gameSquares[8] = 1;
	else if(gameSquares[6] != 0 && gameSquares[6] == gameSquares[8]) gameSquares[7] = 1;
	else if(gameSquares[7] != 0 && gameSquares[7] == gameSquares[8]) gameSquares[6] = 1;
}

void BestMove()
{
	if (gameSquares[4] == 0) gameSquares[4] = 1;
	else if (gameSquares[8] == 0) gameSquares[8] = 1;
	else if (gameSquares[6] == 0) gameSquares[6] = 1;
	else if (gameSquares[2] == 0) gameSquares[2] = 1;
	else if (gameSquares[0] == 0) gameSquares[0] = 1;
	else if (gameSquares[7] == 0) gameSquares[7] = 1;
	else if (gameSquares[5] == 0) gameSquares[5] = 1;
	else if (gameSquares[1] == 0) gameSquares[1] = 1;
}

void ComputerTurn()
{
	for (int i = 0; i < 1; i++)
	{
		if (GameWon()) std::cout << "Game over!!\n";
		else if (!GameWon())
		{
			if (PossibleWin())
			{
				WinBlock();
				break;
			}
			else
			{
				BestMove();
				break;
			}
		}
	}
	movesMade++;
}

void PrintBoard()
{
	for (int i = 0; i <=8; i++)
	{
		if ((i+1)%3 != 0)
		{
			if (gameSquares[i] == 1) std::cout << " X |";
			else if (gameSquares[i] == 2) std::cout << " O |";
			else if (gameSquares[i] == 0) std::cout << "   |";
		}
		else
		{
			if (gameSquares[i] == 1) std::cout << " X\n";
			else if (gameSquares[i] == 2) std::cout << " O\n";
			else if (gameSquares[i] == 0) std::cout << "  \n";
			if ((i+1)%9 != 0) std::cout << "---+---+---\n";
		}
	}
}

void PlayerTurn()
{
	int move = 0;
	std::cout << "Your move, player. You won't defeat me!\n";
	std::cin >> move;
	if (gameSquares[move-1] == 1 || gameSquares[move-1] == 2) 
	{
		std::cout << "That is an invalid move. Try again.\n";
		std::cin >> move;
	}
	else if (gameSquares[move-1] == 0) gameSquares[move-1] = 2;
	movesMade++;
}

void HowTo()
{
	std::cout << "Welcome to Tic Tac Toe! I hope you're ready to lose!!\n"
		<< "Here's how to play:\n"
		<< "You must select a number from 0 to 8, which will represent\n"
		<< "a space in the grid\n"
		<< "Let me show you what number represents which square!\n\n"
		<< " 1 | 2 | 3 \n"
		<< "---+---+---\n"
		<< " 4 | 5 | 6 \n"
		<< "---+---+---\n"
		<< " 7 | 8 | 9 \n";
}



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
// And the main() function
#include "TicTacToe.h"

int main()
{
	HowTo();
	FirstGo();
	if (compFirst)
	{
		while (movesMade <= 9)
		{
			ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I win! You cannot defeat me, I am superior!\n";
				break;
			}
			if (movesMade != 9) PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "What? This is impossible! I am superior!!\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You cannot win, this game is futile\n";
	}

	else if (!compFirst)
	{
		while (movesMade <= 9)
		{
			PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "This is impossible! You got lucky!\n";
				break;
			}
			if (movesMade != 9) ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I knew you couldn't win. Bow to your machine master\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You done better than expected.\n";
	}

	system("pause");

}


I apologize for the long read, there is probably a simpler way to handle the algorithm but I couldn't figure one out.
Thanks again for any help
All you assign is 1 (for the player) and never 2 (for the computer) in WinBlock() and BestMove(). It needs a parameter that tells who does the move.
I'm not sure I follow. 1 is always X, which is always the computer's move. WinBlock and BestMove wouldn't need the option for a player because its only called for the computer
Have you thought about having a 2d array for your board - this might make it easier to do things with for loops.

To check for a win, check each row, each column, and both diagonals.

I am guessing your numbering system for the board is making the logic harder. Example - one of the diagonals is [0][0], [1][1], [2][2] rather than 0,4,8. Can you see how that makes it easier to do nested for loops?

Your code was a good effort, I think, but you are right in that it can be improved. The telling thing for me was all the repetitive else if's. If you find yourself writing code like this - then there is probably a much better way.

I hope you see this as constructive criticism, and learn from it. Don't worry there have been lot's of coders who have done something one way, only to find a much more elegant way.

The other thing is not to put code into header files. Headers are for declarations, not code. You could however have more than one cpp file - you just have to figure out how to compile & link it. Should be easy if you have an IDE. You will need to declare which functions you are using as extern, before main().

Hope all this has been useful to you,look forward to helping out more if needed.



Thanks, TheIdeasMan, I never thought of using two arrays to represent the rows and columns of the board. That was the elegant solution I was very much hoping someone would point out to me :)

However, I'm not going to mark this as solved just yet, I'm going to try to restructure my code in the way you have suggested and then see if it fixes it, or if it gives me an easier look at the problem / solution.

I was also thinking of making another .cpp for the definitions of the .h file, I just wanted to get the actual game working first before I clean it all up.

Thanks for the definitely constructive criticism :)
OK, no worries.

Just one thing:

I never thought of using two arrays to represent the rows and columns of the board.


I meant one 2 dimensional array -

1
2
3
4
5
6
7
8
9
unsigned Board[3][3];

unsigned row;
unsigned col;

//initialise the board to zeros
for (row = 0; row < 3; row++)
   for(col = 0; col < 3; col++)
       Board[row][col] = 0;


Hi there again, I decided not to use a 2D array in the end as, while it seems simpler to do so, I figured out how to make it work pretty well with a normal array. However, now I have a new problem.

For some reason, the computer now chooses the squares 1 to 9 backwards, with no thought about the best place to move. It always starts with 9, and works its way back to 1, unless it is intercepted, in which case it skips the square that has been claimed by the player.

If you have 2 squares in a line, it makes no effort to try and block your move.

Here is the code now:

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
#include "TicTacToe.h"

void FirstGo()
{
	char answer;
	std::cout << "Now that you know how to play, would you like to\nmake the first move?y/n\n\n\n";
	std::cin >> answer;
	if (answer == 'y' || answer == 'Y') compFirst = false;
	else if (answer == 'n' || answer == 'N') compFirst = true;
}

bool GameWon()
{
	if (board[0] != 0 && board[0] == board[1] && board[1] == board[2] ||
		board[0] != 0 && board[0] == board[3] && board[3] == board[6] ||
		board[1] != 0 && board[1] == board[4] && board[4] == board[7] ||
		board[2] != 0 && board[2] == board[4] && board[4] == board[6] ||
		board[2] != 0 && board[2] == board[5] && board[5] == board[8] ||
		board[3] != 0 && board[3] == board[4] && board[4] == board[5] ||
		board[6] != 0 && board[6] == board[7] && board[7] == board[8] ||
		board[8] != 0 && board[8] == board[4] && board[4] == board[0]) return true;
	else return false;
}

int MarkValue(int Xs, int Os)
{
	int Value = 0;
	int numXs = 0, numOs = 0;
	int i = 0;

	for (i = 0; i < 8; i++)
	{
		if (board[i] == 1) numXs++;
		else if (board[i] == 2) numOs++;

		if ((i+1)%3 == 0)
		{
			if(numXs == Xs && numOs == Os) Value++;

			numXs = 0;
			numOs = 0;
		}
	}

	numXs = 0;
	numOs = 0;
	int next = 0;
	while (next <= 2)
	{
		for (i = 0; i <= 8; i += 3)
		{
			if (board[i] = 1) numXs++;
			else if (board[i] = 2) numOs++;
		}
		if (numXs == Xs && numOs == Os)
		{
			numXs = 0;
			numOs = 0;
			Value++;
		}
		next++;
		i = next;
		numXs = 0;
		numOs = 0;
	}

	numXs = 0;
	numOs = 0;

	for (i = 0; i <= 8; i += 4)
	{
		if (board[i] == 1) numXs++;
		else if (board[i] == 2) numOs++;
	}
	if (numXs == Xs && numOs == Os)
	{
		numXs = 0;
		numOs = 0;
		Value++;
	}

	numXs = 0;
	numOs = 0;

	for (i = 2; i <= 6; i += 2)
	{
		if (board[i] == 1) numXs++;
		else if (board[i] == 2) numOs++;
	}
	if (numXs == Xs && numOs == Os)
	{
		numXs = 0;
		numOs = 0;
		Value++;
	}
	return Value;
}

bool CheckBadMoves()
{
	if (board[4] == 1 && (board[0] == 2 && board[8] == 2) || (board[2] == 2 && board[6] == 2) &&
		(board[1] == 0 && board[3] == 0) || (board[5] == 0 && board[7] == 0))
		return true;
	else if (board[4] == 1 && board[8] == 1 && board[2] == 2 && board[3] == 2)
		return true;
	else if (board[4] == 1 && board[6] == 1 && board[0] == 2 && board[5] == 2)
		return true;
	else if (board[4] == 1 && board[6] == 1 && board[1] == 2 && board[8] == 2)
		return true;
	else if (board[4] == 1 && board[8] == 1 && board[1] == 2 && board[6] == 2)
		return true;
	else if (board[4] == 1 && board[8] == 1 && board[1] == 2 && board[3] == 2)
		return true;
	else if (board[4] == 1 && board[0] == 1 && board[6] == 1 && board[7] == 1 && 
		board[1] == 2 && board[2] == 2 && board[3] == 2 && board[8] == 2)
		return true;
	else return false;
}

int EvaluatePosition()
{
	if (MarkValue(3,0)) return 30;
	else if (MarkValue(0,3)) return 30;
	else if (CheckBadMoves()) return -30;
	else
	{
		int X2 = MarkValue(2,0);
		int X1 = MarkValue(1,0);
		int O2 = MarkValue(0,2);
		int O1 = MarkValue(0,1);
		return 3*X2 + X1 - (3*O2 + O1);
	}
}



void ComputerTurn()
{
	int boardBackUp[9];
	memcpy(boardBackUp, board, sizeof(board));
	int bestValue = 0;
	int bestPosition = 0;

	for (int i = 0; i <= 8; i++)
	{
		if (board[i] != 1 && board[i] != 2)
		{
			board[i] = 1;
			int returnedValue = EvaluatePosition();
			if (returnedValue >= bestValue)
			{
				bestValue = returnedValue;
				bestPosition = i;
			}
		}
		memcpy(board, boardBackUp, sizeof(board));
	}
	board[bestPosition] = 1;
	movesMade++;
}

void PrintBoard()
{
	for (int i = 0; i <=8; i++)
	{
		if ((i+1)%3 != 0)
		{
			if (board[i] == 1) std::cout << " X |";
			else if (board[i] == 2) std::cout << " O |";
			else if (board[i] == 0) std::cout << "   |";
		}
		else
		{
			if (board[i] == 1) std::cout << " X\n";
			else if (board[i] == 2) std::cout << " O\n";
			else if (board[i] == 0) std::cout << "  \n";
			if ((i+1)%9 != 0) std::cout << "---+---+---\n";
		}
	}
}

void PlayerTurn()
{
	int move = 0;
	std::cout << "Your move, player. You won't defeat me!\n";
	std::cin >> move;
	if (board[move-1] == 1 || board[move-1] == 2) 
	{
		std::cout << "That is an invalid move. Try again.\n";
		std::cin >> move;
	}
	else if (board[move-1] == 0) board[move-1] = 2;
	movesMade++;
}

void HowTo()
{
	std::cout << "Welcome to Tic Tac Toe! I hope you're ready to lose!!\n"
		<< "Here's how to play:\n"
		<< "You must select a number from 0 to 8, which will represent\n"
		<< "a space in the grid\n"
		<< "Let me show you what number represents which square!\n\n"
		<< " 1 | 2 | 3 \n"
		<< "---+---+---\n"
		<< " 4 | 5 | 6 \n"
		<< "---+---+---\n"
		<< " 7 | 8 | 9 \n";
}

int main()
{
	HowTo();
	FirstGo();
	if (compFirst)
	{
		while (movesMade <= 9)
		{
			ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I win! You cannot defeat me, I am superior!\n";
				break;
			}
			if (movesMade != 9) PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "What? This is impossible! I am superior!!\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You cannot win, this game is futile\n";
	}

	else if (!compFirst)
	{
		while (movesMade <= 9)
		{
			PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "This is impossible! You got lucky!\n";
				break;
			}
			if (movesMade != 9) ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I knew you couldn't win. Bow to your machine master\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You done better than expected.\n";
	}

	system("pause");

}


Again, sorry for the messy layout, I'll sort all that out once I'm done getting the computer to work properly.

Thanks for any help anyone can give
By not using a 2d array, makes you code long winded because the logic is much more involved.

You have 260 lines of code, some of the other examples of the same problem on this forum are only 100. I haven't looked at these other examples - it may be possible that these could be written with less as well.

One thing I do all the time is write my methodology as comments. This can be done iteratively, so start out with very general ideas first, then go back and put in more detail. Continue until you are ready to write code, leave the comments as they are documentation.

This will help you organise your thoughts logically, help identify what should be in functions etc.

The normal structure of a file looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//includes
//using statements - another way to deal with std things
using std::cout;
using std::cin;
using std::endl;
using std::string; //etc
// or just use std:: for every std thing like you have done

//function declarations

int main() {


return 0;
}

//function definitions


That way we don't have to scroll all the way to the bottom to see what main does.

Now for some other observations:

You can make use of the toupper or tolower functions so you don't have a double test for y or Y.

The GameWon function could call the CheckRows, CheckCols, CheckDiags functions.

This code:
for (i = 0; i < 8; i++)

only checks up to i == 7. The normal idiom is this:

for (i = 0; i < 9; i++)

elsewhere you also had :

for (i = 0; i <= 8; i++)

just stick to the normal idiom.

With this part startin line 55:

1
2
3
4
5
6
7
8
9
10
if (numXs == Xs && numOs == Os)
		{
			numXs = 0;
			numOs = 0;
			Value++;
		}
		next++;
		i = next;
		numXs = 0;
		numOs = 0;


numXs & numOs are set to zero anyway, so why set them inside the if?

There are a lot of these repeated in your code:
1
2
numXs = 0;		
numOs = 0;



This part:
1
2
next++;
		i = next;


can be shortened to:
1
2
i = ++next; //placement of the ++ is important during assignment
                   //next is incremented before being assigned to i          


The CheckBadMoves function will be a lot easier with the 2d array. You can check adjacent squares by adding / subtracting 1 from Row or Col.

This part :

1
2
if (MarkValue(3,0)) return 30;
	else if (MarkValue(0,3)) return 30;


can be shortened to :

1
2
if (MarkValue(3,0)) || (MarkValue(0,3)) return 30;
	


In main(), if the FirstGo function returned a bool, the answer could be assigned to the compfirst variable, which could be declared in main, so now compfirst isn't a global variable.

The if and else if blocks are very similar, can you figure out how to write this more elegantly?

Hint: Play all the moves until the game is finished, then print out who won.

Hope this helps, but seriously consider rewriting with the 2d array



I don't mean to sound like an ass here because I appreciate all the advice for cleaning up my code, but the problem I'm having is more to do with what the computer player is doing.

I don't see why it is starting with 9 every turn then working its way backwards towards 1. Can you see specifically what I'm doing wrong in the logic?
I found a 1d array much easier for tic-tac-toe.

The behavior comes from the loop in ComputerTurn() always resulting in "bestPosition" being the highest valid move. This means that EvalutePosition() isn't doing it's job correctly.

Looking at EvalutePosition(), the values are hard coded so it is going to return the same thing no matter what.

MarkValue() is hard to understand.

I also noticed that the computer is 'X' even though I went first.
Last edited on
Aha, that would make sense. Looking at EvaluatePosition(), though, I don't see a way in which I could make the values anything but hard coded. Is there an easy fix for the problem I'm having?

MarkValue() is something I picked up from googling my problem. What it basically does is it looks through the array and counts up the amount of Xs and Os there are in each line, then in each diagonal, and should return a value dependant on the outcome of each placement.

Also, I wasn't entirely sure about the rules of Tic Tac Toe, whenever I play it, we pick who goes first, then they either use an X or an O. This to say that I wasn't aware of any rule that suggests Xs go first or the like, so I just set the computer's value to X to avoid the hassle of changing it depending on who goes first.
Shameful self bump but I am absolutely at a loss here :/
Last edited on
The first thing I did was split the AIs moves into two categories, things that have to happen, and choices. Choices are more complicated, but not too bad in tic-tac-toe.

The things that have to happen are: "did I loose", "can I win", "should I block". I dont want to go too far into things you don't know, but an enumerator might help you:
enum STATE { FREE, LOST, CANWIN, BLOCK };

which lets you do things like:
1
2
3
4
STATE state = FREE;
if (state == LOST)
  myFunction(state);
//etc 


With AI, I would start by getting it only to recognize when it lost, then try to get it to block your two-in-a-row, and then to see if it can win (winning takes precendence over blocking)

edit: Assume that pos1, pos2, and pos3 refer to an array, I didn't really code that in too well (ie, some parts don't make sense).

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
void computerMoved(void);
void isForced(int pos1, int pos2, int pos3, STATE state, int& nextMove);

void computerMove(void)
{
  STATE myState = FREE;
  int nextMove;
  isForced(0, 1, 2, myState, nextMove); 
  isForced(3, 4, 5, myState, nextMove); 
  isForced(6, 7, 8, myState, nextMove); 
  isForced(0, 3, 6, myState, nextMove); 
  isForced(1, 4, 7, myState, nextMove); 
  isForced(2, 5, 8, myState, nextMove); 
  isForced(0, 4, 8, myState, nextMove); 
  isForced(2, 4, 6, myState, nextMove); 

  if (myState == LOST) cout << "You win\n";
  else if (myState == CANWIN)
  {
     functionMove(nextMove);
     cout << "I win\n";
  }
  else if (myState == BLOCK)
  {
    functionMove(nextMove);
    cout << "Nice Try\n";
  }
  else
  {
     functionFigureItOut();  // There wasn't anything pressing to do
  }
}

void isForced(int pos1, int pos2, int pos3, STATE& state, int& nextMove)
{
  if (state == LOST) return;
 
  int result = 0;
  if (pos1 == 1) //or however you know the player's move
    result += 1;
  if (pos2 == 1) result += 2;
  if (pos3 == 1) result += 4;

  //result now has unique values for all combinations of board states

  if (result == 7)
  {
    state = LOST;
    return;
  }
  
  if (state == CANWIN) return;  // no need to figure anything else out

  // result is set up to figure out forces, so we do that first

  if (result == 3) // pos1 and pos2 are player and pos3 isn't
  {
    state = BLOCK;
    nextMove = pos3;
  }
  else if (result == 5) // pos1 and pos3
  {
    state = BLOCK;
    nextMove = pos2;
  }
  else if (result == 6) // pos2 and pos3
  {
    state = BLOCK;
    nextMove = pos1;
  }

   // now figure out if can win

  result = 0;
  if (pos1 == 2) // The computers piece
    result += 1;
  if (pos2 == 2) result += 2;
  if (pos3 == 2) result += 4;
 

  if (result == 3)
  {
    state = CANWIN;
    nextMove = pos3;
  }
  else if (result == 5)
  {
    state = CANWIN;
    nextMove = pos2;
  }
  else if (result == 6)
  {
    state = CANWIN;
    nextMove = pos1;
  }
}


Hope that helps a little, I've got to go to work now though.



Last edited on
So out of interest i coded the complete game. Inclusive a unbeatable ai.

Yes 1d array is the better choice (as mostly)

what i'm missing within your code is a function that collects positions of the free fields. If you had such a function you could easily rand() your next move out of those positions. And that would be a very basic but working game

Why is there no rand() in your code? I mean there're usually a range of possible moves from where you have to pick one.

Yes, it's a good idea to have a back up board to simulate the next move. But for both, the computer and the player -> if the simulation results in a win for either the computer (first) or the player (block) take that position.

From that you can make your computer more 'intelligent'. I can tell you how, if you're willing to follow my suggestions...
Thanks for the insight into enum, LowestOne, but I don't actually know anything about that and don't really want to straight up copy code, I'd rather have some understanding of what I'm actually doing

Coder777, I first thought about doing the Rand() thing and having the computer throw in a random move, but upon doing that I realised that the game was too easy to win, since there was no logic being used by the computer player.

From there, I implemented a series of if statements that would lead the computer to cycle through the best tactical moves, starting from the middle and then working through the corners. However, this also proved to lead to easy wins, and then I started thinking about how I would make the computer play like a human. This is where I'm having trouble.

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
#include "TicTacToe.h"

int main()
{
	HowTo();
	FirstGo();
	if (compFirst)
	{
		while (movesMade < 9)
		{
			ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I win! You cannot defeat me, I am superior!\n";
				break;
			}
			if (movesMade < 9) PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "You win! Well played\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You cannot win, this game is futile\n";
	}

	else if (!compFirst)
	{
		while (movesMade < 9)
		{
			PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "You win! You got lucky!\n";
				break;
			}
			if (movesMade < 9) ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I win. Bow to your machine master\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You done better than expected.\n";
	}

	system("pause");

}

void FirstGo()
{
	char answer;
	std::cout << "Now that you know how to play, would you like to\nmake the first move?y/n\n\n\n";
	std::cin >> answer;
	if (answer == 'y' || answer == 'Y') compFirst = false;
	else if (answer == 'n' || answer == 'N') compFirst = true;
}

bool GameWon()
{
	if (board[0] != 0 && board[0] == board[1] && board[1] == board[2] ||
		board[0] != 0 && board[0] == board[3] && board[3] == board[6] ||
		board[1] != 0 && board[1] == board[4] && board[4] == board[7] ||
		board[2] != 0 && board[2] == board[4] && board[4] == board[6] ||
		board[2] != 0 && board[2] == board[5] && board[5] == board[8] ||
		board[3] != 0 && board[3] == board[4] && board[4] == board[5] ||
		board[6] != 0 && board[6] == board[7] && board[7] == board[8] ||
		board[8] != 0 && board[8] == board[4] && board[4] == board[0]) return true;
	else return false;
}

int BestMove()
{
	if (board[4] == 0) return 4;
	else if (board[8] == 0) return 8;
	else if (board[6] == 0) return 6;
	else if (board[2] == 0) return 2;
	else if (board[0] == 0) return 0;
	else if (board[1] == 0) return 1;
	else if (board[3] == 0) return 3;
	else if (board[5] == 0) return 5;
	else if (board[7] == 0) return 7;
}

int WinBlock()
{
	if(board[0] != 0 && board[0] == board[1]) return 2;
	else if(board[0] != 0 && board[0] == board[2]) return 1;
	else if(board[0] != 0 && board[0] == board[3]) return 6;
	else if(board[0] != 0 && board[0] == board[4]) return 8;
	else if(board[0] != 0 && board[0] == board[6]) return 3;
	else if(board[0] != 0 && board[0] == board[8]) return 4;
	else if(board[1] != 0 && board[1] == board[2]) return 0;
	else if(board[1] != 0 && board[1] == board[4]) return 7;
	else if(board[1] != 0 && board[1] == board[7]) return 4;
	else if(board[2] != 0 && board[2] == board[4]) return 6;
	else if(board[2] != 0 && board[2] == board[5]) return 8;
	else if(board[2] != 0 && board[2] == board[6]) return 4;
	else if(board[2] != 0 && board[2] == board[8]) return 5;
	else if(board[3] != 0 && board[3] == board[4]) return 5;
	else if(board[3] != 0 && board[3] == board[5]) return 4;
	else if(board[3] != 0 && board[3] == board[6]) return 0;
	else if(board[4] != 0 && board[4] == board[5]) return 3;
	else if(board[4] != 0 && board[4] == board[6]) return 2;
	else if(board[4] != 0 && board[4] == board[7]) return 1;
	else if(board[4] != 0 && board[4] == board[8]) return 0;
	else if(board[5] != 0 && board[5] == board[8]) return 2;
	else if(board[6] != 0 && board[6] == board[7]) return 8;
	else if(board[6] != 0 && board[6] == board[8]) return 7;
	else if(board[7] != 0 && board[7] == board[8]) return 6;
	else BestMove();
}

bool CheckBadMoves()
{
	if (board[4] == 1 && (board[0] == 2 && board[8] == 2) || (board[2] == 2 && board[6] == 2) &&
		(board[1] == 0 && board[3] == 0) || (board[5] == 0 && board[7] == 0))
		return true;
	else if (board[4] == 1 && board[8] == 1 && board[2] == 2 && board[3] == 2)
		return true;
	else if (board[4] == 1 && board[6] == 1 && board[0] == 2 && board[5] == 2)
		return true;
	else if (board[4] == 1 && board[6] == 1 && board[1] == 2 && board[8] == 2)
		return true;
	else if (board[4] == 1 && board[8] == 1 && board[1] == 2 && board[6] == 2)
		return true;
	else if (board[4] == 1 && board[8] == 1 && board[1] == 2 && board[3] == 2)
		return true;
	else if (board[4] == 1 && board[0] == 1 && board[6] == 1 && board[7] == 1 && 
		board[1] == 2 && board[2] == 2 && board[3] == 2 && board[8] == 2)
		return true;
	else return false;
}

void ComputerTurn()
{
	int boardBackUp[9];
	memcpy(boardBackUp, board, sizeof(board));
	int bestValue = 0;
	int bestPosition = 0;

	for (int i = 0; i <= 8; i++)
	{
		if (board[i] != 1 && board[i] != 2)
		{
			board[i] = 1;
			int returnedValue = WinBlock();
			if (returnedValue >= bestValue)
			{
				bestValue= returnedValue;
				bestPosition = i;
			}
		}
		memcpy(board, boardBackUp, sizeof(board));
	}
	board[bestPosition] = 1;
	movesMade++;
}

void PrintBoard()
{
	for (int i = 0; i <=8; i++)
	{
		if ((i+1)%3 != 0)
		{
			if (board[i] == 1) std::cout << " X |";
			else if (board[i] == 2) std::cout << " O |";
			else if (board[i] == 0) std::cout << "   |";
		}
		else
		{
			if (board[i] == 1) std::cout << " X\n";
			else if (board[i] == 2) std::cout << " O\n";
			else if (board[i] == 0) std::cout << "  \n";
			if ((i+1)%9 != 0) std::cout << "---+---+---\n";
		}
	}
	std::cout << "\n\n";
}

void PlayerTurn()
{
	int move = 0;
	std::cout << "Your move, player. You won't defeat me!\n";
	std::cin >> move;
	if (board[move-1] == 1 || board[move-1] == 2) 
	{
		std::cout << "That is an invalid move. Try again.\n";
		std::cin >> move;
	}
	else if (board[move-1] == 0) board[move-1] = 2;
	movesMade++;
}

void HowTo()
{
	std::cout << "Welcome to Tic Tac Toe! I hope you're ready to lose!!\n"
		<< "Here's how to play:\n"
		<< "You must select a number from 1 to 9, which will represent\n"
		<< "a space in the grid\n"
		<< "Let me show you what number represents which square!\n\n"
		<< " 1 | 2 | 3 \n"
		<< "---+---+---\n"
		<< " 4 | 5 | 6 \n"
		<< "---+---+---\n"
		<< " 7 | 8 | 9 \n"
		<< "I will be Xs, you will be Os\n\n";
}


That's what I'm currently working with. I went back to the messy if/else method as it produced the best results, but now the computer seems to be grabbing at random numbers for a while, then going back to picking the highest to lowest open spots, without considering the tactical effect of each move
Looks like line 116 needs to be: else return BestMove();

I don't think you need the loop in ComputerTurn() at all. By the time you're in ComputerTurn you already know that there is a valid move left (!gameWon). WinBlock() is already returning the best move to do.

I don't think you really need to simulate next moves. Tic-Tac-Toe is pretty simple: If the center is free go there, otherwise take a corner, then take a side. You have to check whether or not you can win/block, but not much thinking.

Every game should end in a draw. I can still beat your AI, but maybe I let you find that :)
It seems to work a little better after making those changes, so thanks for that, but its still having its problems. Now, if I block the computer's winning move, it kind of just freezes up and doesn't make any more moves, then declares the game to be a draw.

Very peculiar.

Are you having this problem at all or is my computer just giving up?

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
#include "TicTacToe.h"

int main()
{
	HowTo();
	FirstGo();
	if (compFirst)
	{
		while (movesMade < 9)
		{
			ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I win! You cannot defeat me, I am superior!\n";
				break;
			}
			if (movesMade < 9) PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "You win! Well played\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You cannot win, this game is futile\n";
	}

	else if (!compFirst)
	{
		while (movesMade < 9)
		{
			PlayerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "You win! You got lucky!\n";
				break;
			}
			if (movesMade < 9) ComputerTurn();
			PrintBoard();
			if (GameWon())
			{
				std::cout << "I win. Bow to your machine master\n";
				break;
			}
		}
		if (!GameWon()) std::cout << "It is a draw. You done better than expected.\n";
	}

	system("pause");

}

void FirstGo()
{
	char answer;
	std::cout << "Now that you know how to play, would you like to\nmake the first move?y/n\n\n\n";
	std::cin >> answer;
	if (answer == 'y' || answer == 'Y') compFirst = false;
	else if (answer == 'n' || answer == 'N') compFirst = true;
}

bool GameWon()
{
	if (board[0] != 0 && board[0] == board[1] && board[1] == board[2] ||
		board[0] != 0 && board[0] == board[3] && board[3] == board[6] ||
		board[1] != 0 && board[1] == board[4] && board[4] == board[7] ||
		board[2] != 0 && board[2] == board[4] && board[4] == board[6] ||
		board[2] != 0 && board[2] == board[5] && board[5] == board[8] ||
		board[3] != 0 && board[3] == board[4] && board[4] == board[5] ||
		board[6] != 0 && board[6] == board[7] && board[7] == board[8] ||
		board[8] != 0 && board[8] == board[4] && board[4] == board[0]) return true;
	else return false;
}

int BestMove()
{
	if (board[4] == 0) return 4;
	else if (board[8] == 0) return 8;
	else if (board[6] == 0) return 6;
	else if (board[2] == 0) return 2;
	else if (board[0] == 0) return 0;
	else if (board[1] == 0) return 1;
	else if (board[3] == 0) return 3;
	else if (board[5] == 0) return 5;
	else if (board[7] == 0) return 7;
	else return rand()%9;
}

int WinBlock()
{
	if(board[0] != 0 && board[0] == board[1]) return 2;
	else if(board[0] != 0 && board[0] == board[2]) return 1;
	else if(board[0] != 0 && board[0] == board[3]) return 6;
	else if(board[0] != 0 && board[0] == board[4]) return 8;
	else if(board[0] != 0 && board[0] == board[6]) return 3;
	else if(board[0] != 0 && board[0] == board[8]) return 4;
	else if(board[1] != 0 && board[1] == board[2]) return 0;
	else if(board[1] != 0 && board[1] == board[4]) return 7;
	else if(board[1] != 0 && board[1] == board[7]) return 4;
	else if(board[2] != 0 && board[2] == board[4]) return 6;
	else if(board[2] != 0 && board[2] == board[5]) return 8;
	else if(board[2] != 0 && board[2] == board[6]) return 4;
	else if(board[2] != 0 && board[2] == board[8]) return 5;
	else if(board[3] != 0 && board[3] == board[4]) return 5;
	else if(board[3] != 0 && board[3] == board[5]) return 4;
	else if(board[3] != 0 && board[3] == board[6]) return 0;
	else if(board[4] != 0 && board[4] == board[5]) return 3;
	else if(board[4] != 0 && board[4] == board[6]) return 2;
	else if(board[4] != 0 && board[4] == board[7]) return 1;
	else if(board[4] != 0 && board[4] == board[8]) return 0;
	else if(board[5] != 0 && board[5] == board[8]) return 2;
	else if(board[6] != 0 && board[6] == board[7]) return 8;
	else if(board[6] != 0 && board[6] == board[8]) return 7;
	else if(board[7] != 0 && board[7] == board[8]) return 6;
	else return BestMove();
}

void ComputerTurn()
{
	board[WinBlock()] = 1;
	movesMade++;
}

void PrintBoard()
{
	for (int i = 0; i <=8; i++)
	{
		if ((i+1)%3 != 0)
		{
			if (board[i] == 1) std::cout << " X |";
			else if (board[i] == 2) std::cout << " O |";
			else if (board[i] == 0) std::cout << "   |";
		}
		else
		{
			if (board[i] == 1) std::cout << " X\n";
			else if (board[i] == 2) std::cout << " O\n";
			else if (board[i] == 0) std::cout << "  \n";
			if ((i+1)%9 != 0) std::cout << "---+---+---\n";
		}
	}
	std::cout << "\n\n";
}

void PlayerTurn()
{
	int move = 0;
	std::cout << "Your move, player. You won't defeat me!\n";
	std::cin >> move;
	if (board[move-1] == 1 || board[move-1] == 2) 
	{
		std::cout << "That is an invalid move. Try again.\n";
		std::cin >> move;
	}
	else if (board[move-1] == 0) board[move-1] = 2;
	movesMade++;
}

void HowTo()
{
	std::cout << "Welcome to Tic Tac Toe! I hope you're ready to lose!!\n"
		<< "Here's how to play:\n"
		<< "You must select a number from 1 to 9, which will represent\n"
		<< "a space in the grid\n"
		<< "Let me show you what number represents which square!\n\n"
		<< " 1 | 2 | 3 \n"
		<< "---+---+---\n"
		<< " 4 | 5 | 6 \n"
		<< "---+---+---\n"
		<< " 7 | 8 | 9 \n"
		<< "I will be Xs, you will be Os\n\n";
}


Updated code.
I don't think you really need to simulate next moves.
Maybe not, but it's fun.

ok, your approach seem different from mine. So i can post my code:
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
#include <iostream>
#include <algorithm>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>

enum EWho
{
  None, Computer, Player
};

EWho gameSquares[] = { None, None, None, None, None, None, None, None, None };

int movesMade = 0;

bool FirstGo()
{
  bool compFirst = false;
  char answer;
  std::cout << "Now that you know how to play, would you like to\nmake the first move? y/n" << std::endl;
  std::cin >> answer;
  if ((answer == 'n') || (answer == 'N')) compFirst = true;
  std::cout << std::endl << std::endl;
  return compFirst;
}

EWho GameWon(const EWho *const board = gameSquares)
{
  EWho result = None;
  for(int i = 0; (None == result) && (i < 3); ++i)
  {
    if((board[i*3] == board[(i*3)+1]) && (board[i*3] == board[(i*3)+2])) // horizontal
      result = board[i*3];
    else if((board[i] == board[i+3]) && (board[i] == board[i+6])) // vertical
      result = board[i];
  }
  if(None == result)
  {
    if((board[0] == board[4]) && (board[0] == board[8])) // diagonal
      result = board[0];
    else if((board[2] == board[4]) && (board[2] == board[6])) // diagonal
      result = board[2];
  }
  return result;
}

int GetPossibleMoves(int possible_idx[9], EWho who, const EWho *const board = gameSquares)
{
  int possible_moves = 0;
  for(int i = 0; i < 9; ++i)
  {
    if(None == board[i])
    {
      possible_idx[possible_moves] = i;
      ++possible_moves;
    }
  }
  if((possible_moves > 1) && (possible_moves < 9))
  {
    for(int i = 0; i < possible_moves; ++i)
    {
      EWho board2[9] = { None };
      memcpy(board2, board, sizeof(board2));
      board2[possible_idx[i]] = who;
      if(who == GameWon(board2))
      {
        possible_idx[0] = possible_idx[i];
        possible_moves = 1;
        break;
      }
      else
      {
        bool good = false;
        for(int j = 0; j < 9; ++j)
        {
          if(None == board2[possible_idx[j]])
          {
            board2[possible_idx[j]] = who;
            good = (who == GameWon(board2));
            if(good)
              break;
            else
              board2[possible_idx[j]] = None;
          }
        }
        if(good)
          ;
        else
        {
          --possible_moves;
          std::swap(possible_idx[i], possible_idx[possible_moves]);
          --i;
        }
      }
    }
  }
  return possible_moves;
}

int GetWinIndex(const EWho who)
{
  int result = -1;

  EWho board[9] = { None };
  int possible_idx[9] = { 0 };
  const int possible_moves = GetPossibleMoves(possible_idx, who);
  for(int i = 0; i < possible_moves; ++i)
  {
    memcpy(board, gameSquares, sizeof(board));
    board[possible_idx[i]] = who;
    if(who == GameWon(board))
    {
      result = possible_idx[i];
      break;
    }
    else
      board[possible_idx[i]] = None;
  }
  return result;
}

void ComputerTurn()
{
  int index = -1;
  int win_idx = GetWinIndex(Computer);
  if(win_idx < 0)
    win_idx = GetWinIndex(Player);
  if(win_idx < 0)
  {
    bool done = false;
    if((Player == gameSquares[0]) || (Player == gameSquares[2]) || (Player == gameSquares[6]) || (Player == gameSquares[8]))
    {
      if(None == gameSquares[4])
      {
        done = true;
        index = 4;
      }
    }
    if(done)
      ;
    else
    {
      int c_possible_idx[9] = { 0 };
      const int c_possible_size = GetPossibleMoves(c_possible_idx, Computer);
      int p_possible_idx[9] = { 0 };
      const int p_possible_size = GetPossibleMoves(p_possible_idx, Player);

      int possible_idx[9] = { 0 };
      int possible_size = 0;
      for(int i = 0; i < c_possible_size; ++i)
      {
        int *p_end = p_possible_idx + p_possible_size;
        if(std::find(p_possible_idx, p_end, c_possible_idx[i]) != p_end)
        {
          possible_idx[possible_size] = c_possible_idx[i];
          ++possible_size;
        }
      }
      if(possible_size > 0)
        index = possible_idx[rand() % possible_size];
      else if(c_possible_size > 0)
        index = c_possible_idx[rand() % c_possible_size];
      else if(p_possible_size > 0)
        index = p_possible_idx[rand() % p_possible_size];
    }
  }
  else
    index = win_idx;

  if(index < 0)
    std::cout << "Impossible move!?!" << std::endl;
  else
  {
    gameSquares[index] = Computer;
    movesMade++;
  }
}

void PrintBoard()
{
  for (int i = 0; i < 3; i++)
  {
    if(i > 0)
      std::cout << std::endl << "---+---+---" << std::endl;
    for (int j = 0; j < 3; j++)
    {
      if(j > 0)
      std::cout << "|";
      switch(gameSquares[(i*3)+j])
      {
      case Computer:
        std::cout << " X ";
        break;
      case Player:
        std::cout << " O ";
        break;
      case None:
        std::cout << "   ";
        break;
      default:
        std::cout << " ?  ";
      }
    }
  }
  std::cout << std::endl << std::endl;
}

void PlayerTurn()
{
  int index = 0;
  std::cout << "Your move, player. You won't defeat me!" << std::endl;
  while(index < 1)
  {
    std::cin >> index;
    if((index < 1) || (index > 9))
      index = 0;
    else if(gameSquares[index - 1] != None)
      index = 0;
    if(index > 0)
      gameSquares[index - 1] = Player;
    else
      std::cout << "That is an invalid move. Try again." << std::endl;
  }
  movesMade++;
}

void HowTo()
{
  std::cout << "Welcome to Tic Tac Toe! I hope you're ready to lose!!\n"
    << "Here's how to play:\n"
    << "You must select a number from 1 to 9, which will represent\n"
    << "a space in the grid\n"
    << "Let me show you what number represents which square!\n\n"
    << " 1 | 2 | 3 \n"
    << "---+---+---\n"
    << " 4 | 5 | 6 \n"
    << "---+---+---\n"
    << " 7 | 8 | 9 " << std::endl << std::endl << std::endl;
}

int main()
{
  srand(time(NULL));
  HowTo();
  const bool compFirst = FirstGo();
  EWho won = None;
  while((None == won) && (movesMade < 9))
  {
    const bool comp_turn = (0 == (movesMade % 2)) ?
      compFirst : !compFirst;
    if(comp_turn)
      ComputerTurn();
    else
      PlayerTurn();
    PrintBoard();
    won = GameWon();
    switch(won)
    {
    case Computer:
      if(compFirst)
        std::cout << "I win! You cannot defeat me, I am superior!" << std::endl;
      else
        std::cout << "I knew you couldn't win. Bow to your machine master" << std::endl;
      break;
    case Player:
      if(compFirst)
        std::cout << "What? This is impossible! I am superior!!" << std::endl;
      else
        std::cout << "This is impossible! You got lucky!" << std::endl;
      break;
    default:
      ;
    }
  }
  if(None == won)
  {
    if(compFirst)
      std::cout << "It is a draw. You cannot win, this game is futile" << std::endl;
    else
      std::cout << "It is a draw. You done better than expected." << std::endl;
  }
  std::cout << "Press any key to quit" << std::endl;

  system("Pause");
}
just tell me if you were able to beat the computer ;)
Managed to beat it ;P
But only starting first, found it impossible otherwise.

How are you getting it to block winning moves though? From the code it looks like the computer is just looking at the possible moves and making a random move from that list. Or do I have that completely wrong?
I can win when the computer goes on an edge on the first move.

I'll have to get mine console ready, I wrote it as an exercise in GLUT.
Pages: 12