简体   繁体   English

确定井字游戏的最佳动作

[英]Determine best move in tic tac toe

i want to code a recursive function to determine the best move in a given tic - tac - toe game 我想编写一个递归函数来确定给定井字游戏中的最佳动作

int nextMove(struct Game g, enum Symbol player) {
if (game_over(g) != 0) {
return -1;
}
int i, j;
int score, end;
for(i = 0; i < 3; i += 1) {
    for (j = 0; j < 3; j += 1) {
        if(g.board.fields[i][j] == 0) {
            g.board.fields[i][j] = player;
            score = nextMove(g, -player);
        }
    }
}
end = game_over(g)
}

My game_over function : 我的game_over函数:

enum Symbol game_over(struct Game g)
{
int x, y = x = 0;
int full = 0;

for (y = 0; y < SIZE_Y_AXIS; y += 1)
{
    for (x = 0; x < SIZE_X_AXIS; x += 1)
    {
        if (g.board.fields[x][y] == NONE)
            full++;
        else if (x < SIZE_X_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x+1][y] &&
                 g.board.fields[x][y] == g.board.fields[x+2][y])
            return g.board.fields[x][y];
        else if (y < SIZE_Y_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x][y+1] &&
                 g.board.fields[x][y] == g.board.fields[x][y+2])
            return g.board.fields[x][y];
        else if (x < SIZE_X_AXIS - 2 && y < SIZE_Y_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x+1][y+1] &&
                 g.board.fields[x][y] == g.board.fields[x+2][y+2])
            return g.board.fields[x][y];
        else if (x >= 2 && y < SIZE_Y_AXIS - 2 &&
                 g.board.fields[x][y] == g.board.fields[x-1][y+1] &&
                 g.board.fields[x][y] == g.board.fields[x-2][y+2])
            return g.board.fields[x][y];
    }
}
if (full == 0)
    return FULL;
return NONE;
}

I think the leaf production works fine, but i don't know how to determine which leaf (or which move) is the best one? 我认为烟叶的生产效果很好,但是我不知道如何确定哪一叶(或哪一招)是最好的? Any suggestions by now? 现在有什么建议吗?

Thanks 谢谢

In a game like tic-tac-toe, the search tree is so small that all leaf nodes can be evaluated (unlike in a game like chess or Go where the search is cut short). 在井字游戏中,搜索树是如此之小,可以评估所有叶子节点(与象棋或围棋这样的搜索被缩短的游戏不同)。 Since all nodes are examined, the leaf nodes can be evaluated by checking if they are a win, lose, or draw. 由于检查了所有节点,因此可以通过检查叶子节点是赢,输还是平局来评估叶子节点。 You can use 1,-1, and 0 respectively to represent these values. 您可以分别使用1,-1和0来表示这些值。 Once you do that, return the value of the node to its parent. 完成后,将节点的值返回给它的父节点。 For non-leaf nodes, it must choose either the highest value of its children, or the lowest, depending on if it is a max node (the computer) or min node (its opponent).This will back up the tree all the way to the root, giving it a value for all its possible moves. 对于非叶节点,它必须选择其子节点的最大值或最小值,这取决于它是最大节点(计算机)还是最小节点(其对手),这将一直备份树根,为其所有可能的移动赋予价值。 The move at the root of the tree with the highest value is the best move for that position This is the minimax algorithm. 在树的根部具有最高值的移动是该位置的最佳移动。这是minimax算法。 Additionally, in the code sample you provided, you failed to check if the game was over before all fields are full. 此外,在您提供的代码示例中,您未能在所有字段都填满之前检查游戏是否结束。 Instead, check if a player has already gotten three in a row, as then the game is already over. 相反,请检查玩家是否已经连续获得三局,因为游戏已经结束。 Note:Your nextMove function claims to return an int but doesn't in most cases. 注意:您的nextMove函数声称返回一个int,但在大多数情况下不返回。 That has to be fixed. 那必须解决。 Here is what I would add to your code (the added parts in psuedo-code). 这是我要添加到您的代码中的内容(伪代码中添加的部分)。 I am not sure exactly what the game_over function does, so I can't be sure of what the exact code should be. 我不确定确切的game_over函数做什么,所以我不确定确切的代码应该是什么。 Therefore, I am going to take it out and add psuedocode to take its place. 因此,我要删除它并添加psuedocode来代替它。

int nextMove(struct Game g, enum Symbol player) {
    if (computerWon) {
    return 1;
    }
    if (OpponnentWon) {
    return -1;
    }
    if (allSquaresAreFull) {
    return 0;
    }
    int i, j;
    int bestScore;//use this to calculate which move to return
    int score, end;
    //now check whose turn it is
    if(player == 1){//I'm assuming this is the computer player
        bestScore = -100;//start with an arbitrary low value 
        for(i = 0; i < 3; i += 1) {
            for (j = 0; j < 3; j += 1) {
                if(g.board.fields[i][j] == 0) {
                    g.board.fields[i][j] = player;
                    score = nextMove(g, -player);
                    g.board.fields[i][j] = 0;//make sure to undo every move made in the search
                    if(score > bestScore){//a better move for this player
                         bestScore = score;//update bestScore
                    }
               }
           }
        }
        return bestScore;//return best move to parent;

    }
    if(player == -1){//I'm assuming this is the opponent
        bestScore = 100;//start with an arbitrary high value 
        for(i = 0; i < 3; i += 1) {
            for (j = 0; j < 3; j += 1) {
                if(g.board.fields[i][j] == 0) {
                    g.board.fields[i][j] = player;
                    score = nextMove(g, -player);
                    g.board.fields[i][j] = 0;//make sure to undo every move made in the search
                    if(score < bestScore){//a better move for the opponent is a lower move
                         bestScore = score;//update bestScore
                    }
               }
           }
        }
        return bestScore;//return best move to parent;

    }
end = game_over(g)//this variable is never used. Not sure what it does. I would remove it, it seems useless
}

This should return the value of the position(if it is won, lost, or drawn). 这应该返回头寸的值(如果赢得,丢失或平仓)。 To determine which move to take, this would have to be slightly modified. 为了确定采取哪一步,必须对此做些微修改。 Add a test to see if we are in the first time nextMove is called (ie the root) if we are, instead of keeping track of ony bestMove, which is the value of the move, also keep track of what the actual best move is (perhaps in a move struct). 添加一个测试以查看是否在第一次调用nextMove(即根),而不是仅跟踪移动的值ony bestMove,同时跟踪实际的最佳移动是什么(也许在移动结构中)。 Return that instead if best move. 如果最好的话,将其返回。 Now nextMove will return which move to take. 现在nextMove将返回要采取的动作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM