home *** CD-ROM | disk | FTP | other *** search
/ Beginning C++ Through Gam…rogramming (2nd Edition) / BCGP2E.ISO / source / chapter07 / tic-tac-toe2.cpp < prev   
Encoding:
C/C++ Source or Header  |  2004-04-11  |  7.3 KB  |  266 lines

  1. // Tic-Tac-Toe 2.0
  2. // Plays the game of tic-tac-toe against a human opponent
  3. // Uses pointers instead of refernces for function parameters
  4.  
  5. #include <iostream>
  6. #include <string>
  7. #include <vector>
  8. #include <algorithm>
  9.  
  10. using namespace std;
  11.  
  12. // global constants
  13. const char X = 'X';
  14. const char O = 'O';
  15. const char EMPTY = ' ';
  16. const char TIE = 'T';
  17. const char NO_ONE = 'N';
  18.  
  19. // function prototypes
  20. void instructions();
  21. char askYesNo(string question);
  22. int askNumber(string question, int high, int low = 0);
  23. char humanPiece();
  24. char opponent(char piece);
  25. void displayBoard(const vector<char>* const pBoard);
  26. char winner(const vector<char>* const pBoard);
  27. bool isLegal(const vector<char>* const pBoard, int move);
  28. int humanMove(const vector<char>* const pBoard, char human);
  29. int computerMove(vector<char> board, char computer);
  30. void announceWinner(char winner, char computer, char human);
  31.  
  32. // main function
  33. int main()
  34. {
  35.     int move;
  36.     const int NUM_SQUARES = 9;
  37.     vector<char> board(NUM_SQUARES, EMPTY);
  38.  
  39.     instructions();
  40.     char human = humanPiece();
  41.     char computer = opponent(human);
  42.     char turn = X;
  43.     displayBoard(&board);
  44.  
  45.     while (winner(&board) == NO_ONE)
  46.     {
  47.         if (turn == human)
  48.         {
  49.             move = humanMove(&board, human);
  50.             board[move] = human;
  51.         }
  52.         else
  53.         {
  54.             move = computerMove(board, computer);
  55.             board[move] = computer;
  56.         }
  57.         displayBoard(&board);
  58.         turn = opponent(turn);
  59.     }
  60.  
  61.     announceWinner(winner(&board), computer, human);
  62.  
  63.     return 0;
  64. }
  65.  
  66. // functions
  67. void instructions()
  68. {
  69.     cout << "Welcome to the ultimate man-machine showdown: Tic-Tac-Toe.\n";
  70.     cout << "--where human brain is pit against silicon processor\n\n";
  71.  
  72.     cout << "Make your move known by entering a number, 0 - 8.  The number\n";
  73.     cout << "corresponds to the desired board position, as illustrated:\n\n";
  74.     
  75.     cout << "       0 | 1 | 2\n";
  76.     cout << "       ---------\n";
  77.     cout << "       3 | 4 | 5\n";
  78.     cout << "       ---------\n";
  79.     cout << "       6 | 7 | 8\n\n";
  80.  
  81.     cout << "Prepare yourself, human.  The battle is about to begin.\n\n";
  82. }
  83.  
  84. char askYesNo(string question)
  85. {
  86.     char response;
  87.     do
  88.     {
  89.         cout << question << " (y/n): ";
  90.         cin >> response;
  91.     } while (response != 'y' && response != 'n');
  92.  
  93.     return response;
  94. }
  95.  
  96. int askNumber(string question, int high, int low)
  97. {
  98.     int number;
  99.     do
  100.     {
  101.         cout << question << " (" << low << " - " << high << "): ";
  102.         cin >> number;
  103.     } while (number > high || number < low);
  104.  
  105.     return number;
  106. }
  107.  
  108. char humanPiece()
  109. {
  110.     char go_first = askYesNo("Do you require the first move?");
  111.     if (go_first == 'y')
  112.     {
  113.         cout << "\nThen take the first move.  You will need it.\n";
  114.         return X;
  115.     }
  116.     else
  117.     {
  118.         cout << "\nYour bravery will be your undoing... I will go first.\n";
  119.         return O;
  120.     }
  121. }
  122.  
  123. char opponent(char piece)
  124. {
  125.     if (piece == X)
  126.         return O;
  127.     else
  128.         return X;
  129. }
  130.  
  131. void displayBoard(const vector<char>* const pBoard)
  132. {
  133.     cout << "\n\t" << (*pBoard)[0] << " | " << (*pBoard)[1] << " | " << (*pBoard)[2];
  134.     cout << "\n\t" << "---------";
  135.     cout << "\n\t" << (*pBoard)[3] << " | " << (*pBoard)[4] << " | " << (*pBoard)[5];
  136.     cout << "\n\t" << "---------";
  137.     cout << "\n\t" << (*pBoard)[6] << " | " << (*pBoard)[7] << " | " << (*pBoard)[8];
  138.     cout << "\n\n";
  139. }
  140.  
  141. char winner(const vector<char>* const pBoard)
  142. {
  143.     // all possible winning rows
  144.     const int WINNING_ROWS[8][3] = { {0, 1, 2},
  145.                                      {3, 4, 5},
  146.                                      {6, 7, 8},
  147.                                      {0, 3, 6},
  148.                                      {1, 4, 7},
  149.                                      {2, 5, 8},
  150.                                      {0, 4, 8},
  151.                                      {2, 4, 6} };
  152.     const int TOTAL_ROWS = 8;
  153.  
  154.     // if any winning row has three values that are the same (and not EMPTY),
  155.     // then we have a winner
  156.     for(int row = 0; row < TOTAL_ROWS; ++row)
  157.     {
  158.         if ( ((*pBoard)[WINNING_ROWS[row][0]] != EMPTY) &&
  159.              ((*pBoard)[WINNING_ROWS[row][0]] == (*pBoard)[WINNING_ROWS[row][1]]) &&
  160.              ((*pBoard)[WINNING_ROWS[row][1]] == (*pBoard)[WINNING_ROWS[row][2]]) )
  161.         {
  162.             return (*pBoard)[WINNING_ROWS[row][0]];
  163.         }
  164.     }
  165.  
  166.     // since nobody has won, check for a tie (no empty squares left)
  167.     if (count(pBoard->begin(), pBoard->end(), EMPTY) == 0)
  168.         return TIE;
  169.  
  170.     // since nobody has won and it isn't a tie, the game ain't over
  171.     return NO_ONE;
  172. }
  173.  
  174. inline bool isLegal(int move, const vector<char>* pBoard)
  175. {
  176.     return ((*pBoard)[move] == EMPTY);
  177. }
  178.  
  179. int humanMove(const vector<char>* const pBoard, char human)
  180. {
  181.     int move = askNumber("Where will you move?", (pBoard->size() - 1));
  182.     while (!isLegal(move, pBoard))
  183.     {
  184.         cout << "\nThat square is already occupied, foolish human.\n";
  185.         move = askNumber("Where will you move?", (pBoard->size() - 1));
  186.     }
  187.     cout << "Fine...\n";
  188.     return move;
  189. }
  190.  
  191. int computerMove(vector<char> board, char computer)
  192. {
  193.     cout << "I shall take square number ";
  194.     
  195.     // if computer can win on next move, make that move
  196.     for(int move = 0; move < board.size(); ++move)
  197.     {
  198.         if (isLegal(move, &board))
  199.         {
  200.             board[move] = computer;
  201.             if (winner(&board) == computer)
  202.             {
  203.                 cout << move << endl;
  204.                 return move;
  205.             }
  206.             // done checking this move, undo it
  207.             board[move] = EMPTY;
  208.         }
  209.     }
  210.         
  211.     // if human can win on next move, block that move
  212.     char human = opponent(computer);
  213.     for(int move = 0; move < board.size(); ++move)
  214.     {
  215.         if (isLegal(move, &board))
  216.         {
  217.             board[move] = human;
  218.             if (winner(&board) == human)
  219.             {
  220.                 cout << move << endl;
  221.                 return move;
  222.             }
  223.             // done checking this move, undo it
  224.             board[move] = EMPTY;
  225.         }
  226.     }
  227.  
  228.     // the best moves to make, in order
  229.     const int BEST_MOVES[] = {4, 0, 2, 6, 8, 1, 3, 5, 7};
  230.     // since no one can win on next move, pick best open square
  231.     for(int i = 0; i < board.size(); ++i)
  232.     {
  233.         int move = BEST_MOVES[i];
  234.         if (isLegal(move, &board))
  235.         {
  236.             cout << move << endl;
  237.             return move;
  238.         }
  239.     }
  240. }
  241.  
  242. void announceWinner(char winner, char computer, char human)
  243. {
  244.     if (winner == computer)
  245.     {
  246.         cout << winner << "'s won!\n";
  247.         cout << "As I predicted, human, I am triumphant once more -- proof\n";
  248.         cout << "that computers are superior to humans in all regards.\n";
  249.     }
  250.  
  251.     else if (winner == human)
  252.     {
  253.         cout << winner << "'s won!\n";
  254.         cout << "No, no!  It cannot be!  Somehow you tricked me, human.\n";
  255.         cout << "But never again!  I, the computer, so swear it!\n";
  256.     }
  257.  
  258.     else
  259.     {
  260.         cout << "It's a tie.\n";
  261.         cout << "You were most lucky, human, and somehow managed to tie me.\n";
  262.         cout << "Celebrate... for this is the best you will ever achieve.\n";
  263.     }
  264. }
  265.  
  266.