Initial checking of tic tac toe minimax tutorial code.
[ttt.git] / ver0 / ttt.c
1 #include <stdlib.h>\r
2 #include <stdio.h>\r
3 #include <memory.h>\r
4 #include <time.h>\r
5 #include "ttt.h"\r
6 \r
7 SQUARE g_sComputerPlays = O_MARK;             // what side comp plays\r
8 \r
9 //+----------------------------------------------------------------------------\r
10 //\r
11 // Function:  SquareContentsToChar\r
12 //\r
13 // Synopsis:  Helper function for DrawBoard\r
14 //\r
15 // Arguments: IN SQUARE s - a square to return a char to represent\r
16 //            \r
17 // Returns:   char - character representing square\r
18 //\r
19 //+----------------------------------------------------------------------------\r
20 char SquareContentsToChar(IN SQUARE s)\r
21 {\r
22     static char c;\r
23     switch(s)\r
24     {\r
25         case X_MARK:\r
26             c = 'X';\r
27             break;\r
28         case O_MARK:\r
29             c = 'O';\r
30             break;\r
31         default:\r
32             c = '_';\r
33             break;\r
34     }\r
35     return(c);\r
36 }\r
37 \r
38 //+----------------------------------------------------------------------------\r
39 //\r
40 // Function:  DrawBoard\r
41 //\r
42 // Synopsis:  Draw the board\r
43 //\r
44 // Arguments: IN POSITION *p - pointer to a position whose board to draw\r
45 //            \r
46 // Returns:   void\r
47 //\r
48 //+----------------------------------------------------------------------------\r
49 void DrawBoard(IN POSITION *p)\r
50 {\r
51     COORD x, y;\r
52 \r
53     for (y = 0; y < BOARD_SIZE; y++)\r
54     {\r
55         for (x = 0; x < BOARD_SIZE; x++)\r
56         {\r
57             printf("%c ", SquareContentsToChar(p->sBoard[y][x]));\r
58         }\r
59         printf("\n");\r
60     }\r
61     printf("\n%c to move.\n", SquareContentsToChar(p->sWhoseTurn));\r
62 }\r
63 \r
64 //+----------------------------------------------------------------------------\r
65 //\r
66 // Function:  ClearBoard\r
67 //\r
68 // Synopsis:  Clear the board\r
69 //\r
70 // Arguments: IN OUT POSITION *p - pointer to position whose board to clear\r
71 //            \r
72 // Returns:   void\r
73 //\r
74 //+----------------------------------------------------------------------------\r
75 void ClearBoard(IN OUT POSITION *p)\r
76 {\r
77     memset(p->sBoard, 0, sizeof(p->sBoard));\r
78     p->sWhoseTurn = X_MARK;\r
79     p->uNumEmpty = (BOARD_SIZE * BOARD_SIZE);\r
80 }\r
81 \r
82 //+----------------------------------------------------------------------------\r
83 //\r
84 // Function:  IsLegalMove\r
85 //\r
86 // Synopsis:  Determine if a given move is legal on a given board\r
87 //\r
88 // Arguments: IN POSITION *p - the board to play the move on\r
89 //            IN MOVE *m - the move in question\r
90 //            \r
91 // Returns:   BOOL - TRUE if it's legal, FALSE otherwise\r
92 //\r
93 //+----------------------------------------------------------------------------\r
94 BOOL IsLegalMove(IN POSITION *p, IN MOVE *m)\r
95 {\r
96     if ((m->cVpos < BOARD_SIZE) && (m->cHpos < BOARD_SIZE))\r
97     {\r
98         if (IS_SQUARE_EMPTY(p->sBoard[m->cVpos][m->cHpos]))\r
99         {\r
100             return(TRUE);\r
101         }\r
102     }\r
103     return(FALSE);\r
104 }\r
105 \r
106 //+----------------------------------------------------------------------------\r
107 //\r
108 // Function:  GetHumanMove\r
109 //\r
110 // Synopsis:  Ask the human for a move\r
111 //\r
112 // Arguments: IN POSITION *p - the current board\r
113 //            OUT MOVE *m - the move the human made; this struct is populated\r
114 //                      as a side-effect of this function.\r
115 //            \r
116 // Returns:   void* (populates the move struct)\r
117 //\r
118 //+----------------------------------------------------------------------------\r
119 void GetHumanMove(IN POSITION *p, OUT MOVE *m)\r
120 {\r
121     unsigned int x;\r
122 \r
123     do\r
124     {\r
125         printf("Enter your move number: ");\r
126         scanf("%u", &x);\r
127         \r
128         m->cHpos = (x % BOARD_SIZE);\r
129         m->cVpos = (x / BOARD_SIZE);\r
130         m->sMark = g_sComputerPlays * -1;\r
131     }\r
132     while(FALSE == IsLegalMove(p, m));\r
133 }\r
134 \r
135 //+----------------------------------------------------------------------------\r
136 //\r
137 // Function:  SearchForComputerMove\r
138 //\r
139 // Synopsis:  Use our sophisticated search algorithm to find a computer\r
140 //            move\r
141 //\r
142 // Arguments: IN POSITION *p - the current board\r
143 //            OUT MOVE *m - the move the computer chooses; this move struct\r
144 //                      is populated as a side-effect of this function.\r
145 //            \r
146 // Returns:   void* (populates move struct)\r
147 //\r
148 //+----------------------------------------------------------------------------\r
149 void SearchForComputerMove(IN POSITION *p, OUT MOVE *m)\r
150 {\r
151     unsigned int x;\r
152 \r
153     do\r
154     {\r
155         x = rand() % (BOARD_SIZE * BOARD_SIZE);\r
156         m->cHpos = (x % BOARD_SIZE);\r
157         m->cVpos = (x / BOARD_SIZE);\r
158         m->sMark = g_sComputerPlays;\r
159     }\r
160     while(FALSE == IsLegalMove(p, m));\r
161 }\r
162 \r
163 //+----------------------------------------------------------------------------\r
164 //\r
165 // Function:  MakeMove\r
166 //\r
167 // Synopsis:  Make a move on a board  \r
168 //\r
169 // Arguments: IN OUT POSITION *p - the board\r
170 //            IN MOVE *m - the move\r
171 //            \r
172 // Returns:   void\r
173 //\r
174 //+----------------------------------------------------------------------------\r
175 void MakeMove(IN OUT POSITION *p, IN MOVE *m)\r
176 {\r
177     if (TRUE == IsLegalMove(p, m))\r
178     {\r
179         p->sBoard[m->cVpos][m->cHpos] = m->sMark;\r
180         p->uNumEmpty--;\r
181         p->sWhoseTurn *= -1;\r
182     }\r
183 }\r
184 \r
185 //+----------------------------------------------------------------------------\r
186 //\r
187 // Function:  GameOver\r
188 //\r
189 // Synopsis:  Is the game over? \r
190 //\r
191 // Arguments: IN POSITION *p - the board\r
192 //            OUT SQUARE *psWhoWon - who won the game (if it's over)\r
193 //            \r
194 // Returns:   TRUE if the game is over.  Also sets psWhoWon telling\r
195 //            which side one if the game is over.\r
196 // \r
197 //            FALSE if the game is not over.\r
198 //\r
199 //+----------------------------------------------------------------------------\r
200 BOOL GameOver(IN POSITION *p, OUT SQUARE *psWhoWon)\r
201 {\r
202     int iSum;\r
203     COORD x, y;\r
204 \r
205     for (x = 0; x < BOARD_SIZE; x++)\r
206     {\r
207         iSum = 0;\r
208 \r
209         for (y = 0; y < BOARD_SIZE; y++)\r
210         {\r
211             iSum += p->sBoard[x][y];\r
212         }\r
213         if (abs(iSum) == BOARD_SIZE) goto winner;\r
214     }\r
215 \r
216     for (y = 0; y < BOARD_SIZE; y++)\r
217     {\r
218         iSum = 0;\r
219 \r
220         for (x = 0; x < BOARD_SIZE; x++)\r
221         {\r
222             iSum += p->sBoard[x][y];\r
223         }\r
224         if (abs(iSum) == BOARD_SIZE) goto winner;\r
225     }\r
226 \r
227     iSum = 0;\r
228     for (x = 0; x < BOARD_SIZE; x++)\r
229     {\r
230         iSum += p->sBoard[x][x];\r
231     }\r
232     if (abs(iSum) == BOARD_SIZE) goto winner;\r
233 \r
234     iSum = 0;\r
235     for (x = 0; x < BOARD_SIZE; x++)\r
236     {\r
237         iSum += p->sBoard[x][(BOARD_SIZE - 1 - x)];\r
238     }\r
239     if (abs(iSum) == BOARD_SIZE) goto winner;\r
240     \r
241     *psWhoWon = EMPTY;\r
242     if (p->uNumEmpty == 0)\r
243     {\r
244         return(TRUE);\r
245     }\r
246     else\r
247     {\r
248         return(FALSE);\r
249     }\r
250 \r
251  winner:\r
252     *psWhoWon = (iSum / BOARD_SIZE);\r
253     return(TRUE);\r
254 }\r
255 \r
256 //+----------------------------------------------------------------------------\r
257 //\r
258 // Function:  main\r
259 //\r
260 // Synopsis:  The program entry point and main game loop.\r
261 //\r
262 // Arguments: void\r
263 //            \r
264 // Returns:   int\r
265 //\r
266 //+----------------------------------------------------------------------------\r
267 int main(void)\r
268 {\r
269     POSITION p;\r
270     MOVE mv;\r
271     SQUARE sResult;\r
272 \r
273     //\r
274     // Randomize: the random numbers returned by rand() will be based on\r
275     // the system clock when the program starts up.\r
276     //\r
277     srand(time(0));\r
278 \r
279     //\r
280     // Setup the board and draw it once.\r
281     //\r
282     ClearBoard(&p);\r
283     DrawBoard(&p);\r
284 \r
285     //\r
286     // Main game loop\r
287     //\r
288     do\r
289     {\r
290         // \r
291         // See whose turn it is -- the human's or the computers -- and\r
292         // get a move from whoever's turn it is.\r
293         //\r
294         if (p.sWhoseTurn == g_sComputerPlays)\r
295         {\r
296             SearchForComputerMove(&p, &mv);\r
297         }\r
298         else\r
299         {\r
300             GetHumanMove(&p, &mv);\r
301         }\r
302 \r
303         //\r
304         // Make the move on the board and draw the board again.\r
305         //\r
306         MakeMove(&p, &mv);\r
307         DrawBoard(&p);\r
308     }\r
309     while(FALSE == GameOver(&p, &sResult));\r
310 \r
311     //\r
312     // If we get here the game is over... see what happened.\r
313     //\r
314     switch(sResult)\r
315     {\r
316         case X_MARK:\r
317             printf("\nX's win.\n");\r
318             break;\r
319         case O_MARK:\r
320             printf("\nO's win.\n");\r
321             break;\r
322         default:\r
323             printf("Tie (what a surprise)\n");\r
324             break;\r
325     }\r
326 \r
327     exit(0);\r
328 }\r
329 \r