root/user/testbin/tictac/tictac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. main
  2. print_instructions
  3. print_board
  4. ask_yesno
  5. do_move
  6. is_win
  7. win_column
  8. win_row
  9. win_diag_left
  10. win_diag_right
  11. initialize_board
  12. read_string
  13. Strcmp

   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 }

/* [<][>][^][v][top][bottom][index][help] */