os161-1.99
 All Data Structures
tictac.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * These are some constants we use in our program.
00032  * EMPTY is used to indicate empty spaces in the board.
00033  * X_MARKER and O_MARKER are used to indicate where each
00034  *      players has moved
00035  * DIM indicates the size of the board.  For now
00036  * we assume a conventional 3x3 playing board.
00037  *
00038  * This should work once the basic system calls are complete.
00039  */
00040 
00041 #include <stdio.h>
00042 #include <unistd.h>
00043 
00044 #define NEWLINE 012
00045 #define EMPTY           0
00046 #define X_PLAYER        1
00047 #define O_PLAYER        2
00048 #define X_MARKER        1
00049 #define O_MARKER        2
00050 #define DIM             3
00051 #define DIMCHAR         "2"
00052 #define MAXSTRING       100
00053 
00054 typedef enum { FALSE, TRUE } bool;
00055 
00056 /* Function Declarations */
00057 bool ask_yesno(const char *msg);
00058 bool do_move(int player);
00059 void initialize_board(void);
00060 bool is_win(int x, int y);
00061 int  read_string(char *buf, int length);
00062 void print_board(void);
00063 void print_instructions(void);
00064 bool win_column(int y, int marker);
00065 bool win_diag_left(int x, int y, int marker);
00066 bool win_diag_right(int x, int y, int marker);
00067 bool win_row(int x, int marker);
00068 bool Strcmp(const char *a, const char *b);
00069 
00070 
00071 /*
00072  * The board is gloabally defined.
00073  */
00074 int board[DIM][DIM];
00075 
00076 /* Console I/O routines */
00077 
00078 int
00079 main()
00080 {
00081         bool win = FALSE;
00082         int move, max_moves;
00083         int player;
00084 
00085         print_instructions();
00086         max_moves = DIM * DIM;  /* Maximum number of moves in a game */
00087 
00088         while (TRUE) {
00089                 initialize_board();
00090                 for (move = 1; move <= max_moves; move++) {
00091                         player = move % 2 == 0 ? 2 : 1;
00092                         win = do_move(player);
00093                         print_board();
00094                         if (win) {
00095                                 printf("Player %d, you WON!\n\n", player);
00096                                 break;          /* out of for loop */
00097                         }
00098                 }
00099                 /*
00100                  * If we got here by falling through the loop, then it is a
00101                  * tie game.
00102                  */
00103                 if (!win)
00104                         printf("Tie Game!\n\n");
00105                 if (!ask_yesno("Do you wish to play again?"))
00106                         break;                  /* out of while loop */
00107         }
00108         return 0;
00109 }
00110 
00111 /*
00112  * print_instructions
00113  * Displays the instructions for the game.
00114  * Input
00115  *      None
00116  * Output
00117  *      None
00118  * Error
00119  *      None
00120  */
00121 void
00122 print_instructions(void)
00123 {
00124         printf("Welcome to tic-tac-toe!\n");
00125         printf("Player 1 always plays X and player 2 always play O\n");
00126         printf("Good luck!\n\n\n");
00127 }
00128 
00129 void
00130 /*
00131  * print_board
00132  * Display the DIM by DIM board.
00133  * Input
00134  *      None.
00135  * Output
00136  *      None.
00137  * Errors
00138  *      None.
00139  */
00140 print_board(void)
00141 {
00142         int i, j;
00143 
00144         /* Print labels across the top */
00145         printf("\n    0  1  2\n");
00146 
00147         for (i = 0; i < DIM; i++) {
00148                 /* Print row labels */
00149                 printf(" %d ", i);
00150                 for (j = 0; j < DIM; j++) {
00151                         switch (board[i][j]) {
00152                                 case EMPTY: printf("   "); break;
00153                                 case X_MARKER: printf(" X "); break;
00154                                 case O_MARKER: printf(" O "); break;
00155                                 default: printf("???"); break;
00156                         }
00157                 }
00158                 printf("\n");
00159         }
00160         printf("\n");
00161 }
00162 
00163 /*
00164  * ask_yesno (taken from histo.c)
00165  * This function prints out the message and asks the user to respond
00166  * with either a yes or a no.  It continues asking the questions until
00167  * a valid reply is encountered and returns TRUE/FALSE indicating
00168  * the answer (True for yes, false for no).
00169  *
00170  * Input
00171  *      Question to be asked.
00172  * Output
00173  *      TRUE if response is yes
00174  *      FALSE if response is no
00175  * Error
00176  *      None
00177  */
00178 bool
00179 ask_yesno(const char *msg)
00180 {
00181         char answer[MAXSTRING];
00182 
00183         while (TRUE) {
00184                 printf("%s [yes/no] ", msg);
00185                 if (read_string(answer, MAXSTRING) < 0)
00186                         return(FALSE);
00187                 if (Strcmp(answer, "yes"))
00188                         return(TRUE);
00189                 else if (Strcmp(answer, "no"))
00190                         return(FALSE);
00191                 else
00192                         printf("Please answer either yes or no\n");
00193         }
00194 }
00195 
00196 /*
00197  * do_move
00198  * Processes one player move.  The player enters a row and column
00199  * and we have to determine if the square is valid (on the board)
00200  * and that there is no mark already there.  We continue to ask
00201  * for row/column pairs until we receive a valid combination.
00202  * Then we mark the board, check for a win, and return.
00203  *
00204  * Input
00205  *      player          Indicates which player (1 or 2) is moving
00206  * Output
00207  *      TRUE if this move won the game.
00208  *      FALSE if this move did not win the game.
00209  * Error
00210  *      None
00211  */
00212 bool
00213 do_move(int player)
00214 {
00215         int x, y;
00216         bool first;
00217         char answer[MAXSTRING];
00218         char cx;
00219 
00220         first = TRUE;
00221         printf("Player %d (%c), your move\n", player, 
00222                player == X_PLAYER ? 'X' : 'O');
00223         
00224         while (TRUE) {
00225                 printf("Which row [0-%d]: ", DIM-1);
00226                 if (read_string(answer, MAXSTRING) < 0)
00227                         return(FALSE);
00228                 cx = answer[0];
00229                 x = cx - '0';
00230                 if (x < 0 || x >= DIM) {
00231                         printf("Invalid row; must be >= 0 and < %d\n", DIM-1);
00232                         continue;
00233                 }
00234                 printf("Which column [0-%d]: ", DIM-1);
00235                 if (read_string(answer, MAXSTRING) < 0)
00236                         return(FALSE);
00237                 cx = answer[0];
00238                 y = cx - '0';
00239                 if (y < 0 || y >= DIM) {
00240                         printf("Invalid column; must be >= 0 and < %d\n",
00241                                 DIM-1);
00242                         continue;
00243                 }
00244 
00245                 if (board[x][y] != EMPTY) {
00246                         printf("That location is occupied; please try again\n");
00247                         print_board();
00248                 } else
00249                         break;
00250         }
00251         board[x][y] = player == X_PLAYER ? X_MARKER : O_MARKER;
00252 
00253         return(is_win(x, y));
00254 
00255 }
00256 
00257 /*
00258  * is_win
00259  * Checks if the move into position x, y created a tic-tac-toe.
00260  * There are four possible ways to win -- horizontal, vertical,
00261  * and the two diagonals; check each one using a separate routine.
00262  * 
00263  * Four routines for checking the wins are:
00264  * win_row      The horizontal spots are all the same as this current mark.
00265  * win_column   The vertical spots are all the same as this current mark.
00266  * win_diag_left        The diagonal spots from left to right are all the
00267  *                      same as the current mark.
00268  * win_diag_right       The diagonal spots from right to left are all the
00269  *                      same as the current mark.
00270  *
00271  * Input (for all routines)
00272  *      x x coordinate
00273  *      y y coordinate
00274  *      marker the value just placed on the board.
00275  * Output
00276  *      TRUE if player won
00277  *      FALSE otherwise
00278  */
00279 bool
00280 is_win(int x, int y)
00281 {
00282         int marker;
00283 
00284         marker = board[x][y];
00285 
00286         /*
00287          * Note that C "short circuit evaluation".  As soon as any one
00288          * of these functions returns TRUE, we know that the expression
00289          * is true.  Therefore, we can return TRUE without executing
00290          * any of the other routines.
00291          */
00292         return(win_row(x, marker) || win_column(y, marker) ||
00293             win_diag_left(x, y, marker) || win_diag_right(x, y, marker));
00294 }
00295 
00296 /*
00297  * Four helper functions for determining a win.
00298  */
00299 bool
00300 win_column(int y, int marker)
00301 {
00302         int i;
00303         for (i = 0; i < DIM; i++)
00304                 if (board[i][y] != marker)
00305                         return(FALSE);
00306         return(TRUE);
00307 }
00308 
00309 bool
00310 win_row(int x, int marker)
00311 {
00312         int i;
00313         for (i = 0; i < DIM; i++)
00314                 if (board[x][i] != marker)
00315                         return(FALSE);
00316         return(TRUE);
00317 }       
00318 
00319 bool
00320 win_diag_left(int x, int y, int marker)
00321 {
00322         int i;
00323 
00324         /* Check that move is on the diagonal */
00325         if (x != y)
00326                 return(FALSE);
00327 
00328         for (i = 0; i < DIM; i++)
00329                 if (board[i][i] != marker)
00330                         return(FALSE);
00331         return(TRUE);
00332 }
00333 
00334 bool
00335 win_diag_right(int x, int y, int marker)
00336 {
00337         int i;
00338 
00339         /* Check that move is on the diagonal */
00340         if (x + y != DIM - 1)
00341                 return(FALSE);
00342         for (i = 0; i < DIM; i++)
00343                 if (board[i][DIM - 1 - i] != marker)
00344                         return(FALSE);
00345         return(TRUE);
00346 }
00347 
00348 void
00349 initialize_board(void)
00350 {
00351         int i, j;
00352 
00353         for (i = 0; i < DIM; i++)
00354                 for (j = 0; j < DIM; j++)
00355                         board[i][j] = EMPTY;
00356 }
00357 
00358 int
00359 read_string(char *buf, int length)
00360 {
00361         int     char_read;
00362         int     i;
00363 
00364         i = 0;
00365         while ((char_read = getchar()) != EOF && char_read != NEWLINE && 
00366             i < length) {
00367                 buf[i] = (char) char_read;
00368                 i++;
00369                 putchar(char_read);
00370         }
00371 
00372         if (char_read == EOF)
00373                 return(-1);
00374 
00375         /*
00376          * If the input overflows the buffer, just cut it short
00377          * at length - 1 characters.
00378          */
00379         if (i >= length)
00380                 i--;
00381         buf[i] = 0;
00382         return(i);
00383 }
00384 
00385 bool
00386 Strcmp(const char *a, const char *b)
00387 {
00388         if (a == NULL)
00389                 return(b == NULL);
00390         if (b == NULL)
00391                 return(FALSE);
00392 
00393         while (*a && *b)
00394                 if (*a++ != *b++)
00395                         return(FALSE);
00396 
00397         return(*a == *b);
00398 
00399 }
 All Data Structures