Guest User

TICTACTOE

a guest
Aug 4th, 2020
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.81 KB | None | 0 0
  1. #include<iostream>
  2. #include<string>
  3. #include<sstream>
  4. #include<tuple>
  5.  
  6.  
  7. //DrawBoard Function to draw the game board. Reference to 2d array of char is passed. char &board [x][y]
  8. //is not allowed it is parsed as an array of references which is illegal.
  9. //std::ostringstream is used to format strings using the insertion << operator
  10. void DrawBoard(const char (&board) [3][3], const int &player, std::ostringstream &stream) {
  11.     system("cls"); //clear the screen before drawing the board
  12.     std::cout << "\t\t\t TIC TAC TOE" << std::endl;
  13.     std::cout << "\n\t\t\t Player 1 is X and Player 2 is O" << std::endl;
  14.     std::cout << "\t\t\t Current Player: " << player << std::endl;
  15.     for (int row = 0; row < 3; ++row) {
  16.         stream << "\t\t\t\t\t";
  17.         for (int col = 0; col < 3; ++col) {
  18.             stream << board[row][col];
  19.             if (col < 2) {
  20.                 stream << " | ";
  21.             }
  22.         }
  23.         std::cout << stream.str() << std::endl; //stream.str() returns std::string which can be used with std::cout
  24.         if (row < 2) {
  25.             std::cout << "\t\t\t\t\t----------"<<std::endl;
  26.         }
  27.         stream.str("");//empty the stream for the next row
  28.     }
  29.  
  30. }
  31.  
  32. //Get row and col from move. Used tuple to be able to return multiple values from function
  33. std::tuple<int, int> GetRowCol(const int& move) {
  34.     int row, col;
  35.     if (1 <= move && move <= 3) { //m-1 allows to computer the column number correctly
  36.         row = 0;
  37.         col = (move - 1) % 3;
  38.     }
  39.     else if (4 <= move && move <= 6) {
  40.         row = 1;
  41.         col = (move - 1) % 3;
  42.     }
  43.     else {
  44.         row = 2;
  45.         col = (move - 1) % 3;
  46.     }
  47.     return std::make_tuple(row, col);
  48. }
  49.  
  50.  
  51. //Update the array board after valid move
  52. void UpdateBoard(char (&board) [3][3], const int &move, const int &player) {
  53.     char insert_move;
  54.     std::tuple<int, int> board_index = GetRowCol(move);
  55.     int row = std::get<0>(board_index); //get row from the tuple... std::get<i>(tuple) will get the ith element from tuple
  56.     int col = std::get<1>(board_index); //get col from the tuple
  57.     board_index = GetRowCol(move);
  58.     if (player == 1) {
  59.         insert_move = 'X';
  60.  
  61.     }
  62.     else {
  63.         insert_move = 'O';
  64.     }
  65.     board[row][col] = insert_move;
  66. }
  67.  
  68. //Get the move from player
  69. int GetMove() {
  70.     int move;
  71.     std::cout << "Enter your move >";
  72.     std::cin >> move;
  73.     return move;
  74.    
  75. }
  76.  
  77. //Check if the played move is valid
  78. bool ValidateMove(char(&board)[3][3], const int &move) {
  79.     int row, col;
  80.     std::tuple<int, int> board_index = GetRowCol(move);
  81.     row = std::get<0>(board_index);
  82.     col = std::get<1>(board_index);
  83.     if (board[row][col] != 'X' && board[row][col] != 'O') {
  84.         return true;
  85.     }
  86.     else {
  87.         return false;
  88.     }
  89. }
  90.  
  91.  
  92. //Check if the played move wins the game
  93. bool CheckWin(const char (&board)[3][3]) {
  94.     //check if any row is same
  95.     for (int row = 0; row < 3; ++row) {
  96.         if (board[row][0] == board[row][1] && board[row][0] == board[row][2]) {
  97.             return true;
  98.         }
  99.     }
  100.     //check if any col is same
  101.     for (int col = 0; col < 3; ++col) {
  102.         if (board[0][col] == board[1][col] && board[0][col] == board[2][col]) {
  103.             return true;
  104.         }
  105.     }
  106.     //check if any of the two diagnols are the same
  107.     if (board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
  108.         return true;
  109.     }
  110.     else if(board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
  111.         return true;
  112.     }
  113.     return false; //no condition for win has matched the game continues
  114. }
  115.  
  116. //The main GameLoop
  117. void GameLoop() {
  118.     char Board[3][3] = { {'1', '2', '3'},
  119.                          {'4', '5', '6'},
  120.                          {'7', '8', '9'} };
  121.     std::ostringstream Stream; //std::ostringstream is used to format strings using the insertion << operator
  122.     int move, current_player;
  123.     current_player = 1;
  124.     while (!CheckWin(Board)) {
  125.         DrawBoard(Board, current_player, Stream);
  126.         try{
  127.             move = GetMove();
  128.             if (1 <= move && move <= 9 && ValidateMove(Board, move)) { //check if the move is in the valid range and is valid
  129.                     UpdateBoard(Board, move, current_player);
  130.                     if (current_player == 1) {
  131.                         current_player = 2;
  132.                     }
  133.                     else {
  134.                         current_player = 1;
  135.                     }
  136.             }
  137.             else {
  138.                 throw -1; // invalid move error for both an invalid input or an invalid move(enter an already occupied index on board
  139.             }
  140.         }
  141.         catch(int e){
  142.             system("cls");
  143.             std::cerr << "\n\n\tERROR:" << e << " REPLAY LAST MOVE! \n PRESS ENTER TO CONTINUE";
  144.             //clear the input buffer if this is not done the program does not pause on std::cin.get()
  145.             // goto this link for more info
  146.             // https://stackoverflow.com/questions/5131647/why-would-we-call-cin-clear-and-cin-ignore-after-reading-input
  147.             //std::cin.clear() clears the error flag on std::cin
  148.             std::cin.clear();
  149.             //std::cin.ignore(limit, '\n') will ignore all the characters upto limit and will stop if it gets '\n'
  150.             std::cin.ignore(INT_MAX, '\n');//INT_MAX is a the max value of int
  151.             std::cin.get();
  152.            
  153.         }
  154.     }
  155.     std::cout << "\n\n\n\t\tGAME OVER! Player " << current_player << " Wins!";
  156. }
  157.  
  158. int main() {
  159.     GameLoop();
  160.     return 0;
  161.  
  162. }
Add Comment
Please, Sign In to add comment