【问题标题】:Logical Mistakes, Checking for a Winner in Tic Tac Toe逻辑错误,在井字游戏中寻找赢家
【发布时间】:2025-12-29 08:50:07
【问题描述】:

好的,所以我非常接近完成这个程序。我理解为什么我的程序没有采取行动并且我能够修复它,但现在我正在尝试检查是否有赢家。我意识到我的winGame() 函数应该在某种while 中或执行while 循环以结束游戏。但是,当我尝试进行一些调试以解决一些问题时,我意识到一些令人不安的事情。它总是说这是平局,即使它不应该是。这些都是很小的事情,我很惭愧不理解,我真的很想得到一些关于如何解决它的帮助。另外,我知道如果赢了,应该有一段时间或做while循环来结束游戏。我只是不确定把它放在哪里,所以如果你有任何建议,请告诉我。

*请注意,在我的有效移动函数中有一个小数组,我计划将其设为静态 const 数组。我的 get 函数返回名称中的值(例如 getIval() 返回单元格对象的初始值),而我的 set 函数只是适当地分配值。

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's a draw!" << endl;
        validate = true;
    }

    return (validate);
}

这是一个程序运行示例供您参考。

    //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's a draw!

+--+--+--+
|X |O |X |
+--+--+--+
|4 |O |6 |
+--+--+--+
|X |8 |9 |
+--+--+--+
Player 2 make a move.
8
Nested if-else statement.
Calling winGame()
It's a draw!

+--+--+--+
|X |O |X |
+--+--+--+
|4 |O |6 |
+--+--+--+
|X |O |9 |
+--+--+--+

【问题讨论】:

  • 你为什么不在发现获胜者后立即返回true?相反,您正在检测获胜者,而不是立即返回,您的代码会无缘无故地进行更多检查。
  • 我的导师告诉我,在一个函数中有多个返回值是糟糕的编程习惯。但鉴于多人告诉我同样的事情,我开始假设我的导师给了我错误的信息。现在我知道了,我会考虑到这一点。感谢您的回复!

标签: c++ if-statement


【解决方案1】:

它总是说这是平局,即使它不应该这样。

原因是您的winGame 函数不会在检测到行或列获胜者时立即返回。相反,如果一行或一列获胜,则会无缘无故地进行额外检查以检查对角线获胜者。

代码应在检测到列或行获胜时立即返回,而不是运行对角线检查。如果代码以这种方式完成,也不需要validate 变量。

如果您采用更系统的方法并只为 3 种不同的获胜方式编写代码会更好:按行、按列和按对角线。如果其中任何一个是赢家,请立即返回。

此外,在检查行、列或对角线之前先检查是否有标记会更快。您的代码最后对空白进行标记检查,因此在不需要调用它时不必要地调用getMarker

代码说明了要点:

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
}

我没有编写代码来测试对角线,但你应该明白了。行和列检查在单独的循环中完成(没什么花哨的)。如果在这些循环的任何迭代中都有获胜者,则返回值为true,表示获胜者。

【讨论】:

  • 您好,感谢您的周到回复,非常感谢。我的导师告诉我,在一个函数中有多个返回值是不好的编程习惯。但是,这不是第一次有人通知我添加其他退货声明。这是常见的事情吗?
【解决方案2】:

这段代码有 3 个问题。

  1. 游戏循环不会因胜利而结束。
  2. 确认胜利后,win 函数不会立即返回。
  3. 抽奖条件的逻辑不正确。

这些很容易解决。

  • 如果 WinGame==true,则在您的 do-while 循环中放置一个中断
  • 使用 return validate 更改行和列胜利中的中断
  • Pass变成WinGameme函数并做一个额外的if语句 检查是否turns==9

    无效井字游戏::makeAMove(){ 字符移动; 整数转数 = 1; 布尔验证=真;

        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;
    

    }

然后

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's a draw!" << endl;
                    validate = true;
                }
        }

        return (validate);
} 

【讨论】: