提问者:小点点

Minimax算法仍然可以在井字游戏中发挥最佳动作


我为一个井字游戏实现了带有alpha-beta修剪的minimax。这是代码:

如果还有更多移动,则此函数返回。

bool isMovesLeft()
{
    for (int x = 0; x < ROWS; x++)
        for (int y = 0; y < COLS; y++)
            if (game.Board[x][y] == EMPTY)
                return true;

    return false;
}

评估板并返回分数。可能的结果:-10,0,10。

int evaluateBoard()
{
    for (int x = 0; x < ROWS; x++)
    {
        if (game.Board[x][0] == game.Board[x][1] &&
            game.Board[x][1] == game.Board[x][2])
        {
            if (game.Board[x][0] == PLAYER_X)
                return 10;
            else if (game.Board[x][0] == PLAYER_O)
                return -10;
        }
    }

    for (int y = 0; y < COLS; y++)
    {
        if (game.Board[0][y] == game.Board[1][y] &&
            game.Board[1][y] == game.Board[2][y])
        {
            if (game.Board[0][y] == PLAYER_X)
                return 10;
            else if (game.Board[0][y] == PLAYER_O)
                return -10;
        }
    }

    if (game.Board[0][0] == game.Board[1][1] &&
        game.Board[1][1] == game.Board[2][2])
    {
        if (game.Board[0][0] == PLAYER_X)
            return 10;
        else if (game.Board[0][0] == PLAYER_O)
            return -10;
    }

    if (game.Board[0][2] == game.Board[1][1] &&
        game.Board[1][1] == game.Board[2][0])
    {
        if (game.Board[0][2] == PLAYER_X)
            return 10;
        else if (game.Board[0][2] == PLAYER_O)
            return -10;
    }

    return 0;
}

具有alpha-beta剪枝的实际最小极大算法:

int minimax(int depth, int alpha, int beta, bool isMax)
{
    int score = evaluateBoard();

    if (score == 10)
        return 10 - depth;

    if (score == -10)
        return -10 + depth;

    if (!isMovesLeft())
        return 0;

    if (isMax)
    {
        int best = -1000;

        for (int x = 0; x < ROWS; x++)
        {
            for (int y = 0; y < COLS; y++)
            {
                if (game.Board[x][y] == EMPTY)
                {
                    game.Board[x][y] = PLAYER_X;

                    int max = minimax(depth + 1, alpha, beta, !isMax);
                    if (max > best)
                        best = max;

                    if (best > alpha)
                        alpha = best;

                    game.Board[x][y] = EMPTY;

                    if (beta <= alpha)
                        break;
                }
            }
        }

        return best;
    }
    else if (!isMax)
    {
        int best = 1000;

        for (int x = 0; x < ROWS; x++)
        {
            for (int y = 0; y < COLS; y++)
            {
                if (game.Board[x][y] == EMPTY)
                {
                    game.Board[x][y] = PLAYER_O;

                    int min = minimax(depth + 1,alpha, beta, isMax);
                    if (min < best)
                        best = min;

                    if (best < beta)
                        beta = best;

                    game.Board[x][y] = EMPTY;

                    if (beta <= alpha)
                        break;
                }
            }
        }

        return best;
    }
}

返回最佳移动。轮到对手时调用。

BestMove findBestMove()
{
    int bestScore = -1000;

    BestMove bestMove;
    bestMove.Row = -1;
    bestMove.Col = -1;

    if (game.Board[1][1] == EMPTY)
    {
        bestMove.Row = 1;
        bestMove.Col = 1;
        return bestMove;
    }

    for (int x = 0; x < ROWS; x++)
    {
        for (int y = 0; y < COLS; y++)
        {
            if (game.Board[x][y] == EMPTY)
            {
                game.Board[x][y] = PLAYER_X;

                int score = minimax(0, -10000000000, 10000000000, false);

                game.Board[x][y] = EMPTY;

                if (score > bestScore)
                {
                    bestScore = score;
                    bestMove.Row = x;
                    bestMove.Col = y;
                }
            }
        }
    }

    return bestMove;
}

我还在计算分数时增加了深度(在< code>minimax函数中),使人工智能稍微更加智能。

然而,人工智能仍然会做出愚蠢的动作,而且很容易被击败。有些胜利一次又一次地重复。

上面的代码是否正确还是我错过了什么?


共1个答案

匿名用户

问题是由isMax的错误值引起的。在最小化函数的主else块中,递归调用是通过传递isMax进行的,但这意味着递归调用将获得与当前调用相同的isMax值。这是错误的。它应该切换该值。要么传递! isMax,要么只传递一个硬编码的true,因为这里isMaxfalse