Advertisement
kartikkukreja

Tic-Tac-Toe bots

Oct 12th, 2013
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.99 KB | None | 0 0
  1. #include <cstdio>
  2. #include <cstring>
  3. using namespace std;
  4.  
  5. // Strategy-based tic-tac-toe player
  6. class Tic_Tac_Toe_Player_1 {
  7.  
  8.     // The Tic-Tac-Toe board is represented by a 9-element vector
  9.     // 2 represents a blank square
  10.     // 3 represents an X
  11.     // 5 represents an O
  12.     int board[9];
  13.  
  14.     // Squares representing winning combinations
  15.     int win_comb[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 3, 6},
  16.                         {1, 4, 7}, {2, 5, 8}, {0, 4, 8}, {2, 4, 6}};
  17.  
  18.     // Attempts to capture the center square {4} if it is blank
  19.     // otherwise any blank non-corner square {1, 3, 5, 7}
  20.     int make2() {
  21.         if (board[4] == 2)
  22.             return 4;
  23.         for (int i = 1; i <= 7; i += 2)
  24.             if (board[i] == 2)
  25.                 return i;
  26.     }
  27.  
  28.     // Return -1 if the player p cannot win on his next move
  29.     // otherwise it returns the number of square that constitutes
  30.     // a winning move
  31.     int posswin(char p) {
  32.         int i, j, prod;
  33.  
  34.         switch (p)  {
  35.             case 'X':
  36.                 for (i = 0; i < 8; i++) {
  37.                     for (j = 0, prod = 1; j < 3; j++)
  38.                         prod *= board[win_comb[i][j]];
  39.                     if (prod == 18) {   // 3 x 3 x 2 represents X can win on his next move
  40.                         for (j = 0; j < 3; j++)
  41.                             if (board[win_comb[i][j]] == 2)
  42.                                 return win_comb[i][j];   // return the blank square
  43.                     }
  44.                 }
  45.                 break;
  46.             case 'O':
  47.                 for (i = 0; i < 8; i++) {
  48.                     for (j = 0, prod = 1; j < 3; j++)
  49.                         prod *= board[win_comb[i][j]];
  50.                     if (prod == 50) {   // 5 x 5 x 2 represents O can win on his next move
  51.                         for (j = 0; j < 3; j++)
  52.                             if (board[win_comb[i][j]] == 2)
  53.                                 return win_comb[i][j];   // return the blank square
  54.                     }
  55.                 }
  56.                 break;
  57.         }
  58.         return -1;
  59.     }
  60.  
  61.     // Returns any blank square
  62.     int go_blank()  {
  63.         for (int i = 0; i <= 8; i++)
  64.             if (board[i] == 2)
  65.                 return i;
  66.     }
  67.  
  68. public:
  69.  
  70.     // Given a board configuration and the turn number, it returns
  71.     // the square number it wants to make a move on
  72.     int play(int grid[9], int turn)    {
  73.         memcpy(board, grid, 9 * sizeof (int));
  74.         int move;
  75.  
  76.         // Playing strategy
  77.         switch (turn)   {
  78.             case 1:     // Capture upper-left corner
  79.                 return 0;
  80.             case 2:     // if center is blank, capture it, otherwise capture the upper-left corner
  81.                 return (board[4] == 2) ? 4 : 0;
  82.             case 3:     // if lower-right corner is blank, capture it, otherwise capture the upper-right corner
  83.                 return (board[8] == 2) ? 8 : 2;
  84.             case 4:
  85.                 move = posswin('X');
  86.                 return (move != -1) ? move : make2();
  87.             case 5:
  88.                 move = posswin('X');
  89.                 if (move != -1) return move;
  90.                 move = posswin('O');
  91.                 if (move != -1) return move;
  92.                 return (board[6] == 2) ? 6 : 2;
  93.             case 6:
  94.                 move = posswin('O');
  95.                 if (move != -1) return move;
  96.                 move = posswin('X');
  97.                 return (move != -1) ? move : make2();
  98.             case 7:
  99.                 move = posswin('X');
  100.                 if (move != -1) return move;
  101.                 move = posswin('O');
  102.                 return (move != -1) ? move : go_blank();
  103.             case 8:
  104.                 move = posswin('O');
  105.                 if (move != -1) return move;
  106.                 move = posswin('X');
  107.                 return (move != -1) ? move : go_blank();
  108.             case 9:
  109.                 move = posswin('X');
  110.                 if (move != -1) return move;
  111.                 move = posswin('O');
  112.                 return (move != -1) ? move : go_blank();
  113.         }
  114.  
  115.         // invalid turn
  116.         return -1;
  117.     }
  118.  
  119. };
  120.  
  121. // Heuristic-based tic-tac-toe player
  122. class Tic_Tac_Toe_Player_2 {
  123.     // Squares representing winning combinations
  124.     int win_comb[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 3, 6},
  125.                         {1, 4, 7}, {2, 5, 8}, {0, 4, 8}, {2, 4, 6}};
  126.  
  127.     // Heuristic_Array[i][j] gives the utility value for player 'X' if some
  128.     // row, column or diagonal has i 'X' markers and j 'O' markers
  129.     // Similarly, it gives the utility value for player 'O' if some
  130.     // row, column or diagonal has i 'O' markers and j 'X' markers
  131.     int Heuristic_Array[4][4] = {
  132.             {     0,   -10,  -100, -1000 },
  133.             {    10,     0,     0,     0 },
  134.             {   100,     0,     0,     0 },
  135.             {  1000,     0,     0,     0 }};
  136.  
  137.     // Returns the utility value of the given position for the given player
  138.     int evaluatePosition(int board[9], char p)    {
  139.         int player, opponent, sum = 0, i, j, piece;
  140.  
  141.         for (i = 0; i < 8; i++)  {
  142.             player = opponent = 0;
  143.             for (j = 0; j < 3; j++)  {
  144.                 piece = board[win_comb[i][j]];
  145.                 if ((piece == 3 && p == 'X') || (piece == 5 && p == 'O'))
  146.                     player++;
  147.                 else if (piece != 2)
  148.                     opponent++;
  149.             }
  150.             sum += Heuristic_Array[player][opponent];
  151.         }
  152.         return sum;
  153.     }
  154.  
  155. public:
  156.     // Given a board configuration and the turn number, it returns
  157.     // the square number it wants to make a move on
  158.     int play(int board[9], int turn)   {
  159.         int i, k, heuristic = -10000, utility, best = 0, worst, tmp;
  160.         char player = (turn & 1) ? 'X' : 'O';
  161.         char opponent = (turn & 1) ? 'O' : 'X';
  162.  
  163.         for(k = 0; k < 9; k++)  {
  164.             if(board[k] == 2) { // found a blank square
  165.                 board[k] = (turn & 1) ? 3 : 5;  // try playing this move
  166.                 utility = evaluatePosition(board, player);
  167.  
  168.                 worst = -10000;     // find the worst your opponent could do
  169.                 for (i = 0; i < 9; i++)  {
  170.                     if(board[i] == 2) { // simulate a move by opponent
  171.                         board[i] = (turn & 1) ? 5 : 3;
  172.                         tmp = evaluatePosition(board, opponent);
  173.                         if(tmp > worst)
  174.                             worst = tmp;
  175.                         board[i] = 2;
  176.                     }
  177.                 }
  178.  
  179.                 // opponent had no legal move
  180.                 if(worst == -10000)
  181.                     worst = 0;
  182.  
  183.                 utility -= worst;
  184.                 if(utility > heuristic) {
  185.                     heuristic = utility;
  186.                     best = k;
  187.                 }
  188.                 board[k] = 2;
  189.             }
  190.         }
  191.  
  192.         return best;
  193.     }
  194. };
  195.  
  196. // Plays a game between the two Tic_Tac_Toe_Players
  197. class Judge {
  198.     int board[9];
  199.  
  200.     // Squares representing winning combinations
  201.     int win_comb[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 3, 6},
  202.                         {1, 4, 7}, {2, 5, 8}, {0, 4, 8}, {2, 4, 6}};
  203.  
  204.     // Returns true if player 'p' has won, false otherwise
  205.     bool check_win(char p)    {
  206.         int i, j, prod;
  207.         for (i = 0; i < 8; i++) {
  208.             for (j = 0, prod = 1; j < 3; j++)
  209.                 prod *= board[win_comb[i][j]];
  210.             if ((prod == 27 && p == 'X') || (prod == 125 && p == 'O'))
  211.                 return true;
  212.         }
  213.         return false;
  214.     }
  215.  
  216.     // Display board on the console
  217.     void print_board()  {
  218.         for (int i = 0; i < 3; i++) {
  219.             for (int j = 0; j < 3; j++) {
  220.                 switch (board[i * 3 + j])   {
  221.                     case 2: printf("-"); break;
  222.                     case 3: printf("X"); break;
  223.                     case 5: printf("O"); break;
  224.                 }
  225.             }
  226.             printf("\n");
  227.         }
  228.         printf("\n");
  229.     }
  230.  
  231. public:
  232.     void play_game()    {
  233.         Tic_Tac_Toe_Player_1 X;
  234.         Tic_Tac_Toe_Player_2 O;
  235.         int move, i, turn;
  236.         char player;
  237.  
  238.         // make all squares blank
  239.         for (i = 0; i < 9; i++)
  240.             board[i] = 2;
  241.  
  242.         for (turn = 1; turn <= 9; turn++)   {
  243.             player = (turn & 1) ? 'X' : 'O';
  244.             move = (turn & 1) ? X.play(board, turn) : O.play(board, turn);
  245.  
  246.             // check if the move is valid
  247.             if (board[move] != 2)   {
  248.                 printf("Invalid move %d by player %c.\n", move, player);
  249.                 return;
  250.             }
  251.  
  252.             // make the move
  253.             board[move] = (turn & 1) ? 3 : 5;
  254.             print_board();
  255.  
  256.             // check if the move wins the game
  257.             if (check_win(player))  {
  258.                 printf("Game Over. Player %c won.\n", player);
  259.                 return;
  260.             }
  261.         }
  262.         printf("Game Tied.\n");
  263.     }
  264. };
  265.  
  266. int main()  {
  267.     Judge judge;
  268.     judge.play_game();
  269.  
  270.     return 0;
  271. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement