7 SQUARE g_sComputerPlays = O_MARK; // what side comp plays
\r
8 unsigned int g_uPly = 0;
\r
9 MOVE g_mvBest = { 0 };
\r
11 //+----------------------------------------------------------------------------
\r
13 // Function: SquareContentsToChar
\r
15 // Synopsis: Helper function for DrawBoard
\r
17 // Arguments: IN SQUARE s - a square to return a char to represent
\r
19 // Returns: char - character representing square
\r
21 //+----------------------------------------------------------------------------
\r
22 char SquareContentsToChar(IN SQUARE s)
\r
44 //+----------------------------------------------------------------------------
\r
46 // Function: DrawBoard
\r
48 // Synopsis: Draw the board
\r
50 // Arguments: IN POSITION *p - pointer to a position whose board to draw
\r
54 //+----------------------------------------------------------------------------
\r
55 void DrawBoard(IN POSITION *p)
\r
59 for (y = 0; y < BOARD_SIZE; y++)
\r
61 for (x = 0; x < BOARD_SIZE; x++)
\r
63 printf("%c ", SquareContentsToChar(p->sBoard[y][x]));
\r
67 ASSERT(X_OR_O(p->sWhoseTurn));
\r
68 printf("\n%c to move.\n", SquareContentsToChar(p->sWhoseTurn));
\r
71 //+----------------------------------------------------------------------------
\r
73 // Function: ClearBoard
\r
75 // Synopsis: Clear the board
\r
77 // Arguments: IN OUT POSITION *p - pointer to position whose board to clear
\r
81 //+----------------------------------------------------------------------------
\r
82 void ClearBoard(IN OUT POSITION *p)
\r
84 memset(p->sBoard, 0, sizeof(p->sBoard));
\r
85 p->sWhoseTurn = X_MARK; // x's go first
\r
86 p->uNumEmpty = (BOARD_SIZE * BOARD_SIZE);
\r
89 //+----------------------------------------------------------------------------
\r
91 // Function: IsLegalMove
\r
93 // Synopsis: Determine if a given move is legal on a given board
\r
95 // Arguments: IN POSITION *p - the board to play the move on
\r
96 // IN MOVE *m - the move in question
\r
98 // Returns: BOOL - TRUE if it's legal, FALSE otherwise
\r
100 //+----------------------------------------------------------------------------
\r
101 BOOL IsLegalMove(IN POSITION *p, IN MOVE *m)
\r
103 if ((m->cVpos < BOARD_SIZE) && (m->cHpos < BOARD_SIZE))
\r
105 if (IS_SQUARE_EMPTY(p->sBoard[m->cVpos][m->cHpos]))
\r
113 //+----------------------------------------------------------------------------
\r
115 // Function: GetHumanMove
\r
117 // Synopsis: Ask the human for a move
\r
119 // Arguments: IN POSITION *p - the current board
\r
120 // OUT MOVE *m - the move the human made; this struct is populated
\r
121 // as a side-effect of this function.
\r
123 // Returns: void* (populates the move struct)
\r
125 //+----------------------------------------------------------------------------
\r
126 void GetHumanMove(IN POSITION *p, OUT MOVE *m)
\r
132 printf("Enter your move number: ");
\r
135 m->cHpos = NUM_TO_HPOS(x);
\r
136 m->cVpos = NUM_TO_VPOS(x);
\r
137 m->sMark = OPPOSITE_MARK(g_sComputerPlays);
\r
139 while(FALSE == IsLegalMove(p, m));
\r
142 //+----------------------------------------------------------------------------
\r
144 // Function: GameOver
\r
146 // Synopsis: Is the game over?
\r
148 // Arguments: IN POSITION *p - the board
\r
149 // OUT SQUARE *psWhoWon - who won the game (if it's over)
\r
151 // Returns: TRUE if the game is over. Also sets psWhoWon telling
\r
152 // which side one if the game is over. This also serves
\r
153 // as a very simple evaluation routine for the search.
\r
155 // FALSE if the game is not over.
\r
157 //+----------------------------------------------------------------------------
\r
158 BOOL GameOver(IN POSITION *p, OUT SQUARE *psWhoWon)
\r
163 for (x = 0; x < BOARD_SIZE; x++)
\r
167 for (y = 0; y < BOARD_SIZE; y++)
\r
169 iSum += p->sBoard[x][y];
\r
171 if (abs(iSum) == BOARD_SIZE) goto winner;
\r
174 for (y = 0; y < BOARD_SIZE; y++)
\r
178 for (x = 0; x < BOARD_SIZE; x++)
\r
180 iSum += p->sBoard[x][y];
\r
182 if (abs(iSum) == BOARD_SIZE) goto winner;
\r
186 for (x = 0; x < BOARD_SIZE; x++)
\r
188 iSum += p->sBoard[x][x];
\r
190 if (abs(iSum) == BOARD_SIZE) goto winner;
\r
193 for (x = 0; x < BOARD_SIZE; x++)
\r
195 iSum += p->sBoard[x][(BOARD_SIZE - 1 - x)];
\r
197 if (abs(iSum) == BOARD_SIZE) goto winner;
\r
200 if (p->uNumEmpty == 0)
\r
210 *psWhoWon = (iSum / BOARD_SIZE);
\r
211 ASSERT(X_OR_O(*psWhoWon));
\r
216 //+----------------------------------------------------------------------------
\r
218 // Function: MakeMove
\r
220 // Synopsis: Make a move on a board
\r
222 // Arguments: IN OUT POSITION *p - the board
\r
223 // IN MOVE *m - the move
\r
227 //+----------------------------------------------------------------------------
\r
228 void MakeMove(IN OUT POSITION *p, IN MOVE *m)
\r
230 if (TRUE == IsLegalMove(p, m))
\r
232 ASSERT(p->sBoard[m->cVpos][m->cHpos] == EMPTY);
\r
233 p->sBoard[m->cVpos][m->cHpos] = m->sMark;
\r
235 ASSERT(p->uNumEmpty < (BOARD_SIZE * BOARD_SIZE));
\r
236 p->sWhoseTurn = OPPOSITE_MARK(p->sWhoseTurn);
\r
238 ASSERT(g_uPly > 0);
\r
242 //+----------------------------------------------------------------------------
\r
244 // Function: UnmakeMove
\r
246 // Synopsis: The opposite of MakeMove
\r
248 // Arguments: IN OUT POSITION *p - the board
\r
249 // IN MOVE *m - the move to undo
\r
253 //+----------------------------------------------------------------------------
\r
254 void UnmakeMove(IN OUT POSITION *p, IN MOVE *m)
\r
256 if (p->sBoard[m->cVpos][m->cHpos] == m->sMark)
\r
258 p->sBoard[m->cVpos][m->cHpos] = EMPTY;
\r
260 ASSERT(p->uNumEmpty > 0);
\r
261 ASSERT(p->uNumEmpty <= (BOARD_SIZE * BOARD_SIZE));
\r
262 p->sWhoseTurn = OPPOSITE_MARK(p->sWhoseTurn);
\r
263 ASSERT(g_uPly > 0);
\r
270 SimpleSearch(IN POSITION *p)
\r
276 int iBestScore = -INFINITY;
\r
279 // Evaluate this position
\r
281 if (TRUE == GameOver(p, &sWhoWon))
\r
283 if (sWhoWon == p->sWhoseTurn)
\r
287 else if (sWhoWon == (p->sWhoseTurn * -1))
\r
295 // No one won, game is still going. Evaluate every
\r
296 // possible move from here.
\r
298 ASSERT(p->uNumEmpty > 0);
\r
299 for (s = 0; s < (BOARD_SIZE * BOARD_SIZE); s++)
\r
301 mv.cHpos = NUM_TO_HPOS(s);
\r
302 mv.cVpos = NUM_TO_VPOS(s);
\r
303 mv.sMark = p->sWhoseTurn;
\r
305 if (IsLegalMove(p, &mv))
\r
309 iScore = -1 * SimpleSearch(p);
\r
310 if (iScore > iBestScore)
\r
312 iBestScore = iScore;
\r
319 UnmakeMove(p, &mv);
\r
322 return(iBestScore);
\r
325 //+----------------------------------------------------------------------------
\r
327 // Function: SearchForComputerMove
\r
329 // Synopsis: Use our sophisticated search algorithm to find a computer
\r
332 // Arguments: IN POSITION *p - the current board
\r
333 // OUT MOVE *m - the move the computer chooses; this move struct
\r
334 // is populated as a side-effect of this function.
\r
336 // Returns: void* (populates move struct)
\r
338 //+----------------------------------------------------------------------------
\r
339 void SearchForComputerMove(IN POSITION *p, OUT MOVE *m)
\r
343 #if defined(PLAY_RANDOMLY)
\r
346 x = rand() % (BOARD_SIZE * BOARD_SIZE);
\r
347 m->cHpos = NUM_TO_HPOS(x);
\r
348 m->cVpos = NUM_TO_VPOS(x);
\r
349 m->sMark = g_sComputerPlays;
\r
351 while(FALSE == IsLegalMove(p, m));
\r
352 #elif defined(SIMPLE_SEARCH)
\r
357 #error "No Search Strategy Defined"
\r
361 //+----------------------------------------------------------------------------
\r
365 // Synopsis: The program entry point and main game loop.
\r
371 //+----------------------------------------------------------------------------
\r
379 // Randomize: the random numbers returned by rand() will be based on
\r
380 // the system clock when the program starts up.
\r
385 // Setup the board and draw it once.
\r
396 // See whose turn it is -- the human's or the computers -- and
\r
397 // get a move from whoever's turn it is.
\r
399 if (p.sWhoseTurn == g_sComputerPlays)
\r
401 SearchForComputerMove(&p, &mv);
\r
405 GetHumanMove(&p, &mv);
\r
409 // Make the move on the board and draw the board again.
\r
414 while(FALSE == GameOver(&p, &sResult));
\r
417 // If we get here the game is over... see what happened.
\r
422 printf("\nX's win.\n");
\r
425 printf("\nO's win.\n");
\r
428 printf("Tie (what a surprise)\n");
\r