Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/user/testbin/tictac/tictac.c
734 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* These are some constants we use in our program.
32
* EMPTY is used to indicate empty spaces in the board.
33
* X_MARKER and O_MARKER are used to indicate where each
34
* players has moved
35
* DIM indicates the size of the board. For now
36
* we assume a conventional 3x3 playing board.
37
*
38
* This should work once the basic system calls are complete.
39
*/
40
41
#include <stdio.h>
42
#include <unistd.h>
43
44
#define NEWLINE 012
45
#define EMPTY 0
46
#define X_PLAYER 1
47
#define O_PLAYER 2
48
#define X_MARKER 1
49
#define O_MARKER 2
50
#define DIM 3
51
#define DIMCHAR "2"
52
#define MAXSTRING 100
53
54
typedef enum { FALSE, TRUE } bool;
55
56
/* Function Declarations */
57
bool ask_yesno(const char *msg);
58
bool do_move(int player);
59
void initialize_board(void);
60
bool is_win(int x, int y);
61
int read_string(char *buf, int length);
62
void print_board(void);
63
void print_instructions(void);
64
bool win_column(int y, int marker);
65
bool win_diag_left(int x, int y, int marker);
66
bool win_diag_right(int x, int y, int marker);
67
bool win_row(int x, int marker);
68
bool Strcmp(const char *a, const char *b);
69
70
71
/*
72
* The board is gloabally defined.
73
*/
74
int board[DIM][DIM];
75
76
/* Console I/O routines */
77
78
int
79
main()
80
{
81
bool win = FALSE;
82
int move, max_moves;
83
int player;
84
85
print_instructions();
86
max_moves = DIM * DIM; /* Maximum number of moves in a game */
87
88
while (TRUE) {
89
initialize_board();
90
for (move = 1; move <= max_moves; move++) {
91
player = move % 2 == 0 ? 2 : 1;
92
win = do_move(player);
93
print_board();
94
if (win) {
95
printf("Player %d, you WON!\n\n", player);
96
break; /* out of for loop */
97
}
98
}
99
/*
100
* If we got here by falling through the loop, then it is a
101
* tie game.
102
*/
103
if (!win)
104
printf("Tie Game!\n\n");
105
if (!ask_yesno("Do you wish to play again?"))
106
break; /* out of while loop */
107
}
108
return 0;
109
}
110
111
/*
112
* print_instructions
113
* Displays the instructions for the game.
114
* Input
115
* None
116
* Output
117
* None
118
* Error
119
* None
120
*/
121
void
122
print_instructions(void)
123
{
124
printf("Welcome to tic-tac-toe!\n");
125
printf("Player 1 always plays X and player 2 always play O\n");
126
printf("Good luck!\n\n\n");
127
}
128
129
void
130
/*
131
* print_board
132
* Display the DIM by DIM board.
133
* Input
134
* None.
135
* Output
136
* None.
137
* Errors
138
* None.
139
*/
140
print_board(void)
141
{
142
int i, j;
143
144
/* Print labels across the top */
145
printf("\n 0 1 2\n");
146
147
for (i = 0; i < DIM; i++) {
148
/* Print row labels */
149
printf(" %d ", i);
150
for (j = 0; j < DIM; j++) {
151
switch (board[i][j]) {
152
case EMPTY: printf(" "); break;
153
case X_MARKER: printf(" X "); break;
154
case O_MARKER: printf(" O "); break;
155
default: printf("???"); break;
156
}
157
}
158
printf("\n");
159
}
160
printf("\n");
161
}
162
163
/*
164
* ask_yesno (taken from histo.c)
165
* This function prints out the message and asks the user to respond
166
* with either a yes or a no. It continues asking the questions until
167
* a valid reply is encountered and returns TRUE/FALSE indicating
168
* the answer (True for yes, false for no).
169
*
170
* Input
171
* Question to be asked.
172
* Output
173
* TRUE if response is yes
174
* FALSE if response is no
175
* Error
176
* None
177
*/
178
bool
179
ask_yesno(const char *msg)
180
{
181
char answer[MAXSTRING];
182
183
while (TRUE) {
184
printf("%s [yes/no] ", msg);
185
if (read_string(answer, MAXSTRING) < 0)
186
return(FALSE);
187
if (Strcmp(answer, "yes"))
188
return(TRUE);
189
else if (Strcmp(answer, "no"))
190
return(FALSE);
191
else
192
printf("Please answer either yes or no\n");
193
}
194
}
195
196
/*
197
* do_move
198
* Processes one player move. The player enters a row and column
199
* and we have to determine if the square is valid (on the board)
200
* and that there is no mark already there. We continue to ask
201
* for row/column pairs until we receive a valid combination.
202
* Then we mark the board, check for a win, and return.
203
*
204
* Input
205
* player Indicates which player (1 or 2) is moving
206
* Output
207
* TRUE if this move won the game.
208
* FALSE if this move did not win the game.
209
* Error
210
* None
211
*/
212
bool
213
do_move(int player)
214
{
215
int x, y;
216
bool first;
217
char answer[MAXSTRING];
218
char cx;
219
220
first = TRUE;
221
printf("Player %d (%c), your move\n", player,
222
player == X_PLAYER ? 'X' : 'O');
223
224
while (TRUE) {
225
printf("Which row [0-%d]: ", DIM-1);
226
if (read_string(answer, MAXSTRING) < 0)
227
return(FALSE);
228
cx = answer[0];
229
x = cx - '0';
230
if (x < 0 || x >= DIM) {
231
printf("Invalid row; must be >= 0 and < %d\n", DIM-1);
232
continue;
233
}
234
printf("Which column [0-%d]: ", DIM-1);
235
if (read_string(answer, MAXSTRING) < 0)
236
return(FALSE);
237
cx = answer[0];
238
y = cx - '0';
239
if (y < 0 || y >= DIM) {
240
printf("Invalid column; must be >= 0 and < %d\n",
241
DIM-1);
242
continue;
243
}
244
245
if (board[x][y] != EMPTY) {
246
printf("That location is occupied; please try again\n");
247
print_board();
248
} else
249
break;
250
}
251
board[x][y] = player == X_PLAYER ? X_MARKER : O_MARKER;
252
253
return(is_win(x, y));
254
255
}
256
257
/*
258
* is_win
259
* Checks if the move into position x, y created a tic-tac-toe.
260
* There are four possible ways to win -- horizontal, vertical,
261
* and the two diagonals; check each one using a separate routine.
262
*
263
* Four routines for checking the wins are:
264
* win_row The horizontal spots are all the same as this current mark.
265
* win_column The vertical spots are all the same as this current mark.
266
* win_diag_left The diagonal spots from left to right are all the
267
* same as the current mark.
268
* win_diag_right The diagonal spots from right to left are all the
269
* same as the current mark.
270
*
271
* Input (for all routines)
272
* x x coordinate
273
* y y coordinate
274
* marker the value just placed on the board.
275
* Output
276
* TRUE if player won
277
* FALSE otherwise
278
*/
279
bool
280
is_win(int x, int y)
281
{
282
int marker;
283
284
marker = board[x][y];
285
286
/*
287
* Note that C "short circuit evaluation". As soon as any one
288
* of these functions returns TRUE, we know that the expression
289
* is true. Therefore, we can return TRUE without executing
290
* any of the other routines.
291
*/
292
return(win_row(x, marker) || win_column(y, marker) ||
293
win_diag_left(x, y, marker) || win_diag_right(x, y, marker));
294
}
295
296
/*
297
* Four helper functions for determining a win.
298
*/
299
bool
300
win_column(int y, int marker)
301
{
302
int i;
303
for (i = 0; i < DIM; i++)
304
if (board[i][y] != marker)
305
return(FALSE);
306
return(TRUE);
307
}
308
309
bool
310
win_row(int x, int marker)
311
{
312
int i;
313
for (i = 0; i < DIM; i++)
314
if (board[x][i] != marker)
315
return(FALSE);
316
return(TRUE);
317
}
318
319
bool
320
win_diag_left(int x, int y, int marker)
321
{
322
int i;
323
324
/* Check that move is on the diagonal */
325
if (x != y)
326
return(FALSE);
327
328
for (i = 0; i < DIM; i++)
329
if (board[i][i] != marker)
330
return(FALSE);
331
return(TRUE);
332
}
333
334
bool
335
win_diag_right(int x, int y, int marker)
336
{
337
int i;
338
339
/* Check that move is on the diagonal */
340
if (x + y != DIM - 1)
341
return(FALSE);
342
for (i = 0; i < DIM; i++)
343
if (board[i][DIM - 1 - i] != marker)
344
return(FALSE);
345
return(TRUE);
346
}
347
348
void
349
initialize_board(void)
350
{
351
int i, j;
352
353
for (i = 0; i < DIM; i++)
354
for (j = 0; j < DIM; j++)
355
board[i][j] = EMPTY;
356
}
357
358
int
359
read_string(char *buf, int length)
360
{
361
int char_read;
362
int i;
363
364
i = 0;
365
while ((char_read = getchar()) != EOF && char_read != NEWLINE &&
366
i < length) {
367
buf[i] = (char) char_read;
368
i++;
369
putchar(char_read);
370
}
371
372
if (char_read == EOF)
373
return(-1);
374
375
/*
376
* If the input overflows the buffer, just cut it short
377
* at length - 1 characters.
378
*/
379
if (i >= length)
380
i--;
381
buf[i] = 0;
382
return(i);
383
}
384
385
bool
386
Strcmp(const char *a, const char *b)
387
{
388
if (a == NULL)
389
return(b == NULL);
390
if (b == NULL)
391
return(FALSE);
392
393
while (*a && *b)
394
if (*a++ != *b++)
395
return(FALSE);
396
397
return(*a == *b);
398
399
}
400
401