/****************************************************************** * Purpose: * This file implements a tic-tac-toe playing program. * It is written as an example of how to write code from a design * document. * * Assumptions: * 1. The program will be played by a single user, playing against the * computer. * 2. The input will be via the keyboard, and the output will be on the * console. * * Rules of tic-tac-toe: * Tic-tac-toe is played on a 3x3 grid consisting of 9 cells. The cells * are initially empty. Players take turns placing Xs (one player) and * Os (the other player) until either the board is full, in which case * the game is a draw, or until one player has placed three Xs or Os in a * row, either horizontally, vertically, or diagonally. * ******************************************************************/ #include #include /* Board cell values */ #define USER 1 #define COMPUTER -1 #define EMPTY 0 #define DRAW 0 /* * move - A tic-tac-toe move * - x and y represent the location of the move in the array, and w is * either 1 for the user or -1 for the computer, depending on whose * move this is. */ typedef struct move { int x; int y; int w; } move; typedef int boolean; #define true 1 #define false 0 /* * function prototypes - the body of the functions are below main */ void print_rules(void); void clear_board(int board[3][3]); void display_board(int board[3][3]); int get_first(void); move *get_user_move(void); move *get_computer_move(int board[3][3]); void do_move(int board[3][3], move * newmove); int check_winner(int board[3][3]); boolean check_full(int board[3][3]); /****************************************************************** * Main - plays the game ******************************************************************/ int main(int argc, char *argv[]) { /* * board - The tic-tac-toe board * Represents an empty cell, 1 represents the users move, and -1 * represents the computer's move. */ int board[3][3]; /* move - A tic-tac-toe move */ move *onemove; /* * turn - Whose turn it is to play * Either 1 or -1 depending upon whether it is the user's turn or * the computer's turn */ int turn = 0; /* Clear the board */ clear_board(board); /* * Tic-Tac-Toe Game * Print out the rules of the game and instructions for * playing the game. */ print_rules(); /* * Ask the user who should go first, the user or the computer * Input the response and set turn to the appropriate value */ turn = get_first(); /* * As long as the board isn't full and someone has not * won the game, loop, getting moves and displaying the board */ while (!check_full(board) && !check_winner(board)) { /* Display the board */ display_board(board); /* See whose turn it is, and get their move */ if (turn == USER) { onemove = get_user_move(); printf("USER: (%d,%d)\n\n", onemove->x, onemove->y); } else { onemove = get_computer_move(board); printf("COMPUTER: (%d,%d)\n\n", onemove->x, onemove->y); } /* Do the move */ do_move(board, onemove); /* Swap turn */ if (turn == USER) turn = COMPUTER; else turn = USER; } /* Display the board */ display_board(board); /* * Print out the value of check_winner, either user, computer, or * draw, depending on whether check_winner(board) returns 1, -1, or * 0. */ switch (check_winner(board)) { case USER: printf("You won!\n"); break; case COMPUTER: printf("The computer won!\n"); break; case DRAW: printf("Draw!\n"); break; } exit(0); } /****************************************************************** * * clear_board(board) * Description: a function that sets the board to the initial * state, all 0s. * Input: a board * Output: nothing * result: the board is cleared to 0s * ******************************************************************/ void clear_board(int board[3][3]) { int i; int j; /* Set all cells to EMPTY */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) board[i][j] = EMPTY; } /****************************************************************** * * display_board(board) * Description: A function that displays the board on the console * Input: the board * Output: nothing * result: the board is displayed on the console * ******************************************************************/ void display_board(int board[3][3]) { int i; int j; printf("The board: \n\n"); printf(" 0 1 2\n"); /* print out all cells */ for (i = 0; i < 3; i++) { printf("%d ", i); for (j = 0; j < 3; j++) { /* Print out X, O, or . depending on the cell value */ switch (board[i][j]) { case USER: printf("0"); break; case COMPUTER: printf("X"); break; case EMPTY: printf("."); break; } if (j < 2) printf("|"); } if (i < 2) { printf("\n "); for (j = 0; j < 3; j++) printf("--"); } /* Print a newline to end the row */ printf("\n"); } /* Print 2 newlines to end the board printing */ printf("\n\n"); } /****************************************************************** * * move get_user_move() * Description: a function that gets a move from the user * Input: nothing * Output: a move * result: one move has been gotten from the user * ******************************************************************/ move *get_user_move(void) { move *newmove = (move *) malloc(sizeof(move)); /* Get the values from the user */ printf("Please enter the x and y values, separated by a comma: "); scanf("%d,%d", &newmove->x, &newmove->y); newmove->w = USER; return newmove; } /****************************************************************** * * move get_computer_move(board) * Description: a function that computes the computer's move * Input: the board * Output: a move * result: the computer has made one move * * * Algorithm for get_computer_move(): * * 1. If there is a move that would give the computer three in a row, * return that move. * * 2. Otherwise, if the user has two in a row, return the move that the * user would play to get three in a row. * * 3. Otherwise, if there is a move that would give the user two sets of * two in a row, return that move. * * 4. Otherwise, if the center cell is open, return that move. * * 5. Otherwise, if there is a move that would give the computer two in a * row, return that move. * * 6. Otherwise, if a corner cell is open, return that move. * * 7. Otherwise, play in any other cell. * ******************************************************************/ /******************************************************** ******************************************************** ******************************************************** * Dumb algorithm - doesn't do what it is supposed to do* * This algorithm just chooses the first open cell * * Later, I will make this work correctly, after I have * * gotten everything else working. * ******************************************************** ******************************************************** ********************************************************/ /* * I'm not really going to work on this any more. * I'm just showing you how you might document an * intermediate solution, while you are in the process * of developing your program. * It is important to document everything as you go, * not wait until the program is completely correct. * */ move *get_computer_move(int board[3][3]) { int i; int j; move *newmove = (move *) malloc(sizeof(move)); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) if (board[i][j] == EMPTY) { newmove->x = j; newmove->y = i; newmove->w = COMPUTER; return newmove; } } /****************************************************************** * * void do_move(board, move) * Description: a function that updates the board to reflect * the move that it is passed * Input: the board, a move * Output: nothing * Result: The board has been changed to reflect the move * ******************************************************************/ void do_move(int board[3][3], move * newmove) { board[newmove->y][newmove->x] = newmove->w; } /****************************************************************** * * integer check_winner(board) * Description: Checks to see if anyone won the game * Input: the board * Output: 1, 0, or -1 depending on whether the user, nobody, or the * computer won the game * Result: a winner (if present) is determined * ******************************************************************/ int check_winner(int board[3][3]) { int sum[8]; int i; /* Add up all sets of three */ /* Across */ sum[0] = board[0][0] + board[0][1] + board[0][2]; sum[1] = board[1][0] + board[1][1] + board[1][2]; sum[2] = board[2][0] + board[2][1] + board[2][2]; /* Down */ sum[3] = board[0][0] + board[1][0] + board[2][0]; sum[4] = board[0][1] + board[1][1] + board[2][1]; sum[5] = board[0][2] + board[1][2] + board[2][2]; /* Diagonals */ sum[6] = board[0][0] + board[1][1] + board[2][2]; sum[7] = board[0][2] + board[1][1] + board[2][0]; /* * See if anyone won by seeing if any sum represents three * in a row */ for (i = 0; i < 8; i++) { if (sum[i] == 3 * USER) return USER; if (sum[i] == 3 * COMPUTER) return COMPUTER; } /* If not, return DRAW */ return DRAW; } /****************************************************************** * * boolean check_full(board) * Description: Checks to see if the board is full * Input: The board * Output: true or false depending on whether or not the board is full * Result: the fullness of the board has been checked * ******************************************************************/ boolean check_full(int board[3][3]) { int i; int j; /* See if there are any empty cells */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) if (board[i][j] == EMPTY) return false; /* If not, the board is full */ return true; } /****************************************************************** * * void print_rules(void) * Description: Print out the rules to tic-tac-toe * Input: nothing * Output: nothing * Result: The rules have been printed * ******************************************************************/ void print_rules(void) { printf("Rules of tic-tac-toe:\n"); printf("Tic-tac-toe is played on a 3x3 grid consisting of 9 cells.\n"); printf("The cells are initially empty. Players take turns placing Xs\n"); printf("(the user) and Os (the computer) until either the board\n"); printf("is full, in which case the game is a draw, or until one player\n"); printf("has placed three Xs or Os in a row, either horizontally,\n"); printf("vertically, or diagonally."); printf("\n\n"); } /****************************************************************** * * int get_first(void) * Description: ask the user who should go first * Input: nothing * Output: who should go first * Result: We now know who should go first * ******************************************************************/ int get_first(void) { int response; /* Ask who should go first */ printf("Enter 0 for the user to go first or\n"); printf(" 1 for the computer to go first\n"); /* Read in the response */ scanf("%d", &response); /* return the right value */ if (response == 0) return USER; else return COMPUTER; }