Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include<iostream>
- #include<string>
- #include<sstream>
- #include<tuple>
- //DrawBoard Function to draw the game board. Reference to 2d array of char is passed. char &board [x][y]
- //is not allowed it is parsed as an array of references which is illegal.
- //std::ostringstream is used to format strings using the insertion << operator
- void DrawBoard(const char (&board) [3][3], const int &player, std::ostringstream &stream) {
- system("cls"); //clear the screen before drawing the board
- std::cout << "\t\t\t TIC TAC TOE" << std::endl;
- std::cout << "\n\t\t\t Player 1 is X and Player 2 is O" << std::endl;
- std::cout << "\t\t\t Current Player: " << player << std::endl;
- for (int row = 0; row < 3; ++row) {
- stream << "\t\t\t\t\t";
- for (int col = 0; col < 3; ++col) {
- stream << board[row][col];
- if (col < 2) {
- stream << " | ";
- }
- }
- std::cout << stream.str() << std::endl; //stream.str() returns std::string which can be used with std::cout
- if (row < 2) {
- std::cout << "\t\t\t\t\t----------"<<std::endl;
- }
- stream.str("");//empty the stream for the next row
- }
- }
- //Get row and col from move. Used tuple to be able to return multiple values from function
- std::tuple<int, int> GetRowCol(const int& move) {
- int row, col;
- if (1 <= move && move <= 3) { //m-1 allows to computer the column number correctly
- row = 0;
- col = (move - 1) % 3;
- }
- else if (4 <= move && move <= 6) {
- row = 1;
- col = (move - 1) % 3;
- }
- else {
- row = 2;
- col = (move - 1) % 3;
- }
- return std::make_tuple(row, col);
- }
- //Update the array board after valid move
- void UpdateBoard(char (&board) [3][3], const int &move, const int &player) {
- char insert_move;
- std::tuple<int, int> board_index = GetRowCol(move);
- int row = std::get<0>(board_index); //get row from the tuple... std::get<i>(tuple) will get the ith element from tuple
- int col = std::get<1>(board_index); //get col from the tuple
- board_index = GetRowCol(move);
- if (player == 1) {
- insert_move = 'X';
- }
- else {
- insert_move = 'O';
- }
- board[row][col] = insert_move;
- }
- //Get the move from player
- int GetMove() {
- int move;
- std::cout << "Enter your move >";
- std::cin >> move;
- return move;
- }
- //Check if the played move is valid
- bool ValidateMove(char(&board)[3][3], const int &move) {
- int row, col;
- std::tuple<int, int> board_index = GetRowCol(move);
- row = std::get<0>(board_index);
- col = std::get<1>(board_index);
- if (board[row][col] != 'X' && board[row][col] != 'O') {
- return true;
- }
- else {
- return false;
- }
- }
- //Check if the played move wins the game
- bool CheckWin(const char (&board)[3][3]) {
- //check if any row is same
- for (int row = 0; row < 3; ++row) {
- if (board[row][0] == board[row][1] && board[row][0] == board[row][2]) {
- return true;
- }
- }
- //check if any col is same
- for (int col = 0; col < 3; ++col) {
- if (board[0][col] == board[1][col] && board[0][col] == board[2][col]) {
- return true;
- }
- }
- //check if any of the two diagnols are the same
- if (board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
- return true;
- }
- else if(board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
- return true;
- }
- return false; //no condition for win has matched the game continues
- }
- //The main GameLoop
- void GameLoop() {
- char Board[3][3] = { {'1', '2', '3'},
- {'4', '5', '6'},
- {'7', '8', '9'} };
- std::ostringstream Stream; //std::ostringstream is used to format strings using the insertion << operator
- int move, current_player;
- current_player = 1;
- while (!CheckWin(Board)) {
- DrawBoard(Board, current_player, Stream);
- try{
- move = GetMove();
- if (1 <= move && move <= 9 && ValidateMove(Board, move)) { //check if the move is in the valid range and is valid
- UpdateBoard(Board, move, current_player);
- if (current_player == 1) {
- current_player = 2;
- }
- else {
- current_player = 1;
- }
- }
- else {
- throw -1; // invalid move error for both an invalid input or an invalid move(enter an already occupied index on board
- }
- }
- catch(int e){
- system("cls");
- std::cerr << "\n\n\tERROR:" << e << " REPLAY LAST MOVE! \n PRESS ENTER TO CONTINUE";
- //clear the input buffer if this is not done the program does not pause on std::cin.get()
- // goto this link for more info
- // https://stackoverflow.com/questions/5131647/why-would-we-call-cin-clear-and-cin-ignore-after-reading-input
- //std::cin.clear() clears the error flag on std::cin
- std::cin.clear();
- //std::cin.ignore(limit, '\n') will ignore all the characters upto limit and will stop if it gets '\n'
- std::cin.ignore(INT_MAX, '\n');//INT_MAX is a the max value of int
- std::cin.get();
- }
- }
- std::cout << "\n\n\n\t\tGAME OVER! Player " << current_player << " Wins!";
- }
- int main() {
- GameLoop();
- return 0;
- }
Add Comment
Please, Sign In to add comment