Logical errors, winner check in Tic Tac Toe

Good, so I'm incredibly close to completing this program. I understand why my program did not move, and I was able to fix it, but now I'm trying to check the winner. I understand that my winGame() function must be at some point or do a while loop to finish the game. But, when I tried to do a little debugging to figure out some things, I understand something alarming. He always says that this is a draw, even if it should not be. These are such secondary things that I am ashamed not to understand, and I would very much like to help in how I can fix this. In addition, I know that there must be some time or a cycle to complete the game if there is a victory. I just don’t know where to express it, so if you have any suggestions, please let me know.

* Please note that there is a small array in my actual move function, I plan to make it a static const array. My get functions return a value in the name (for example, getIval () returns the initial value of a cell object), while my set functions simply assign values ​​accordingly.

 bool TicTacToe::validMove(char move){ char options[9] = { '1','2', '3', '4','5','6','7', '8','9' }; bool validate = false; for ( int i = 0; i < 9; i++ ){ if ( move == options[i]){ validate = true; } } return ( validate ); } void TicTacToe::setMove( char move ){ for ( int i = 0; i < ROW; i++ ){ for ( int j = 0; j < COL; j++ ){ if ( board[i][j].getiVal() == move ){ board[i][j].setiVal( players[currentPlayer].getMarker() ); switchPlayer(); break; } } } } void TicTacToe::makeAMove(){ char move; int turns = 1; bool validate = true; do{ cout << "Player " << (getCurrentPlayer() + 1) << " make a move." << endl; cin >> move; if ( validMove( move ) ){ if ( turns > 4 ){ cout << "Nested if-else statement." << endl; winGame(); setMove( move ); } else setMove(move); } else{ cout << "Invalid Move. Please reenter." << endl; cin >> move; } DrawBoard(); turns++; } while ( turns <= 9 ); } bool TicTacToe::winGame(){ cout << "Calling winGame() " << endl; bool validate = false; int k = 0; for ( int i = 0; i < COL; i++ ){ //check column wins if ( board[0][i].getMarker() == board[1][i].getMarker() && board[1][i].getMarker() == board[2][i].getMarker() && board[2][i].getMarker() != (' ')){ cout << "Column win " << endl; validate = true; break; } //check row wins else if ( board[i][0].getMarker() == board[i][1].getMarker() && board[i][1].getMarker() == board[i][2].getMarker() && board[i][2].getMarker() != (' ')){ cout << "Row win." << endl; validate = true; break; } } if( board[0][0].getMarker() == board[1][1].getMarker() && board[1][1].getMarker() == board[2][2].getMarker() && board[2][2].getMarker() != (' ')){ cout << "Diagonal 1" << endl; validate = true; } else if ( board[0][2].getMarker() == board[1][1].getMarker() && board[1][1].getMarker() == board[2][0].getMarker() && board[2][0].getMarker() != (' ') ){ cout << "Diagonal 2 " << endl; validate = true; } else{ cout << "It a draw!" << endl; validate = true; } return (validate); } 

Here is an example of starting a program for your reference.

  //sample run +--+--+--+ |1 |2 |3 | +--+--+--+ |4 |5 |6 | +--+--+--+ |7 |8 |9 | +--+--+--+ Player 1 make a move. 1 +--+--+--+ |X |2 |3 | +--+--+--+ |4 |5 |6 | +--+--+--+ |7 |8 |9 | +--+--+--+ Player 2 make a move. 2 +--+--+--+ |X |O |3 | +--+--+--+ |4 |5 |6 | +--+--+--+ |7 |8 |9 | +--+--+--+ Player 1 make a move. 3 +--+--+--+ |X |O |X | +--+--+--+ |4 |5 |6 | +--+--+--+ |7 |8 |9 | +--+--+--+ Player 2 make a move. 5 +--+--+--+ |X |O |X | +--+--+--+ |4 |O |6 | +--+--+--+ |7 |8 |9 | +--+--+--+ Player 1 make a move. +--+--+--+ |X |O |X | +--+--+--+ |4 |O |6 | +--+--+--+ |7 |8 |9 | +--+--+--+ Player 1 make a move. 7 Nested if-else statement. Calling winGame() It a draw! +--+--+--+ |X |O |X | +--+--+--+ |4 |O |6 | +--+--+--+ |X |8 |9 | +--+--+--+ Player 2 make a move. 8 Nested if-else statement. Calling winGame() It a draw! +--+--+--+ |X |O |X | +--+--+--+ |4 |O |6 | +--+--+--+ |X |O |9 | +--+--+--+ 
+5
source share
2 answers

There are 3 problems with this code.

  • The game cycle does not end in victory.
  • The win function is not returned as soon as the victory is confirmed.
  • Wrong logic for the drawing condition.

they are easily fixed, though.

  • set a break in your do-while loop if WinGame == true
  • change gaps in victories of rows and columns with confirmation of return
  • Pass goes into the WinGameme function and makes an additional if statement that checks if the turns == 9

    void TicTacToe :: makeAMove () {char move; int turn = 1; bool validate = true;

      do{ cout << "Player " << (getCurrentPlayer() + 1) << " make a move." << endl; cin >> move; if ( validMove( move ) ){ if ( turns > 4 ){ cout << "Nested if-else statement." << endl; setMove( move ); if (winGame(turns)==true) { break; } } else setMove(move); } else{ cout << "Invalid Move. Please reenter." << endl; cin >> move; } DrawBoard(); turns++; } while ( turns <= 9 ); cout << "Game Over" <<endl; 

    }

and then

 bool TicTacToe::winGame(int turns) { cout << "Calling winGame() " << endl; bool validate = false; int k = 0; for ( int i = 0; i < COL; i++ ) { //check column wins if ( board[0][i].getMarker() == board[1][i].getMarker() && board[1][i].getMarker() == board[2][i].getMarker() && board[2][i].getMarker() != (' ')){ cout << "Column win " << endl; validate = true; break; } //check row wins else if ( board[i][0].getMarker() == board[i][1].getMarker() && board[i][1].getMarker() == board[i][2].getMarker() && board[i][2].getMarker() != (' ')){ cout << "Row win." << endl; validate = true; break; } } if( board[0][0].getMarker() == board[1][1].getMarker() && board[1][1].getMarker() == board[2][2].getMarker() && board[2][2].getMarker() != (' ')){ cout << "Diagonal 1" << endl; validate = true; } else if ( board[0][2].getMarker() == board[1][1].getMarker() && board[1][1].getMarker() == board[2][0].getMarker() && board[2][0].getMarker() != (' ') ){ cout << "Diagonal 2 " << endl; validate = true; } else { if (turns==9) { cout << "It a draw!" << endl; validate = true; } } return (validate); } 
+2
source

He always says that this is a draw, even if it should not be.

The reason is because your winGame function winGame not immediately return to detecting the winner of a row or column. Instead, if a row or column wins, additional checks are performed to check the winner of the diagonals for no reason.

The code should immediately return to detecting a column or row winner instead of running diagonal checks. There would also be no need for a validate variable if the code was executed this way.

It would be better if you took a more systematic approach and just write the code for three different ways to win: row, column and diagonal. If any of them is the winner, return immediately.

It’s also faster to check if there is a marker before checking a row, column or diagonals. Your code checks the marker for empty, so without the need to call getMarker when there is no need to call it.

The code illustrates the points made:

 bool TicTacToe::winGame() { char marker; // row check for ( int i = 0; i < COL; i++ ) { marker = board[i][0].getMarker(); // get the initial marker // test if something is there if ( marker != ' ') { // now test the other two markers to see if they match if ( board[i][1].getMarker() == marker && board[i][2].getMarker() == marker ) return true; } } // column check for ( int i = 0; i < COL; i++ ) { marker = board[0][i].getMarker(); if ( marker != ' ') { if ( board[1][i].getMarker() == marker && board[2][i].getMarker() == marker ) return true; } } // check diagonals next //... (code not shown) return false; // if the diagonals fail } 

I did not write code to check the diagonals, but you should get this idea. Rows and columns are checked in separate loops (nothing unusual). If there is a winner in any iteration of these loops, the return value is true , indicating the winner.

+2
source

Source: https://habr.com/ru/post/1238688/


All Articles