tic-tac-toe中的Minimax未正确评分分支

tic-tac-toe中的Minimax未正确评分分支,c,algorithm,tic-tac-toe,minimax,C,Algorithm,Tic Tac Toe,Minimax,我正在尝试用C语言创建一个完美的井字游戏。我使用2D数组来跟踪棋盘 我已经将问题缩小到了我的minimax函数对每个潜在动作的评分方式,但是我在调试它时遇到了困难,因为错误通常发生在第二个动作附近,并且我无法从那一点跟踪所有潜在的游戏状态 计算机在第一位,并且总是“X”minimax是从computerMove函数中调用的,该函数尝试每个可用的移动,然后将其最小化。它将从minimax中为潜在游戏状态返回的值作为临时分数,并将其与当前最高分数进行比较。我相信该计划的一部分正在发挥作用。问题在于m

我正在尝试用C语言创建一个完美的井字游戏。我使用2D数组来跟踪棋盘

我已经将问题缩小到了我的
minimax
函数对每个潜在动作的评分方式,但是我在调试它时遇到了困难,因为错误通常发生在第二个动作附近,并且我无法从那一点跟踪所有潜在的游戏状态

计算机在第一位,并且总是“X”
minimax
是从
computerMove
函数中调用的,该函数尝试每个可用的移动,然后将其最小化。它将从
minimax
中为潜在游戏状态返回的值作为临时分数,并将其与当前最高分数进行比较。我相信该计划的一部分正在发挥作用。问题在于
minimax
函数本身

以下是我的代码的重要部分:

int minimax(char board[][3], char maxPlayer) // +10 -> X wins 
{                                            // -10 -> O wins
    char minPlayer;                          //   0 -> draw
    int scores[3][3];
    if (maxPlayer == 'X') minPlayer = 'O';
    else minPlayer = 'X';
    int topScore = 0;

    // initializing scores to ensure a move is selected
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            scores[i][j] = -11;
        }
    }

    // check for terminal state
    if (isWinning(board,'X') || isWinning(board,'O') || 
    !moveAvailable(board)) {
        if (isWinning(board,'X')) return 10;
        else if (isWinning(board,'O')) return -10;
        else return 0;
    }

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (board[i][j] == 'U') { 
                board[i][j] = maxPlayer;                // try the move
                scores[i][j] = minimax(board,minPlayer);// minimax it
                board[i][j] = 'U';                      // undo the move
            }
        }
    }  

    // if calling minimax for computer, maximize the score
    if (maxPlayer == 'X') {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (scores[i][j] > topScore && scores[i][j] != -11) 
                    topScore = scores[i][j];
            }
        }
    }

    // if calling minimax for human, minimize the score
    else if (maxPlayer == 'O') {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (scores[i][j] < topScore && scores[i][j] != -11) 
                    topScore = scores[i][j];
            }
        }
    }
    return topScore;
}
int minimax(char board[][3],char maxPlayer)//+10->X赢
{//-10->O获胜
char minPlayer;//0->draw
智力分数[3][3];
如果(maxPlayer='X')minPlayer='O';
else minPlayer='X';
int-topScore=0;
//初始化分数以确保选择移动
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
[i][j]=-11分;
}
}
//检查终端状态
如果(是赢的(板,'X')|是赢的(板,'O')|
!可用(板)){
如果(iswing(board,'X'))返回10;
否则如果(正在获胜(板,'O'))返回-10;
否则返回0;
}
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
如果(板[i][j]=='U'){
board[i][j]=maxPlayer;//尝试移动
分数[i][j]=minimax(棋盘,minPlayer);//minimax it
板[i][j]=“U”;//撤消移动
}
}
}  
//如果为计算机调用minimax,则将分数最大化
如果(maxPlayer='X'){
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
如果(得分[i][j]>上核和得分[i][j]!=-11)
topScore=得分[i][j];
}
}
}
//如果为人调用minimax,则最小化分数
else if(maxPlayer='O'){
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
如果(得分[i][j]<上核和得分[i][j]!=-11)
topScore=得分[i][j];
}
}
}
返回上堆芯;
}

问题在于
topScore
初始化:

  • 你应该在11点或-11点初始化
    topScore
    ,这取决于谁打球,而不是0,否则两名球员都会认为他们至少可以从深度2开始打到平局(事实并非如此)

  • 就良好实践(imho)而言,我认为应该将最后两个循环归为一个循环,在更新
    topScore
    之前,将
    if(maxPlayer='X')
    条件放在其中。此外,您应该跳过
    板[i][j]!='U'
    ,比在分数中查找
    -11
    更容易理解(尽管这很好)


我的最佳选择是这一行:
if(board[i][j]='U'){
这个条件从来都不是真的,我猜这一行:
得分[row][column]=-11;//将all设置为“O”wins
不正确。根据函数签名语句上的其他注释,“O”wins为-10,而不是-11每个递归都以新的未初始化版本的
分数[]开始
这可能是不正确的。分数值从来都不是0、-11和+10。我认为分数应该是累加的。也就是说,将每个新的
分数初始化为全部0,然后每次递归调用
minimax()
都会导致上层
分数增加(可能增加-10)根据对
minimax()
@VidorVistrom的递归调用的结果,我猜董事会最初包含了我们所有人,所以他确实需要这个检查。