首页 > 解决方案 > Minimax 算法逻辑输出意外结果

问题描述

我正在为一个简单的国际象棋引擎制作一个极小极大算法,但是遇到了一些困难。我已经运行了几个小时的代码,但无济于事,它似乎仍然输出错误的结果;当我威胁它的一个棋子并且它有一个可以挽救棋子的有效动作时,它会忽略该动作。

下面,我尽可能简化了 minimax 算法方法的代码,以尝试展示我想要实现的目标,并希望让错误可见。它最初是用 minimax(2,true) 调用的;

public static int[] minimax(int depth, boolean max) {
    int piece = 0;
    int square = 0;
    int boardScore = 0;
    int bestScore = -9999;
    if (!max) {
        bestScore = 9999;
    }
    for (int a = 0; a < 64; a++) {
        for (int b = 0; b < 64; b++) {
            boardScore = 0;
            boolean valid = false;
            if (max) {
                valid = Board[a].validate(b, aiColor);
            } else {
                valid = Board[a].validate(b, playerColor);
            }

            if (valid) {
                storePosition(depth-1);
                if (max) {
                    Board[a].move(b,aiColor);
                } else {
                    Board[a].move(b,playerColor);
                }

                boardScore = calculateScore();
                if (depth != 1) {
                    if (max) {
                        int[] minimaxArray = minimax(depth-1, false);
                        boardScore = minimaxArray[2];
                    } else {
                        int[] minimaxArray = minimax(depth-1, true);
                        boardScore = minimaxArray[2];
                    }

                }
                if (boardScore > bestScore && max) {
                    piece = a;
                    square = b;
                    bestScore = boardScore;
                }
                if (boardScore < bestScore && !max) {
                    piece = a;
                    square = b;
                    bestScore = boardScore;
                }
                resetPosition(depth-1);
            }

        }
    }
    int[] returnVars = new int[3];
    returnVars[0] = piece;
    returnVars[1] = square;
    returnVars[2] = bestScore;
    return returnVars;
}

我确信其他方法可以完美运行,因为 move() 只是改变了棋子, validate() 是正确的,因为它显示了玩家可以进行的所有移动,calculateScore() 是正确的,因为它只是计算实例的碎片和总分数取决于它们的颜色。(如果 ai 是前面的马,则得分为 3;如果玩家是前面的卒,则得分为 -1)。

但是,该程序似乎仍然没有遵循我希望它遵循的逻辑,并且在受到威胁时也不会将其碎片移开。例如,我移动了一个棋子以便它可以带走机器人的马,但它未能将马移开。

这是它错误的一个例子,让我相信我的逻辑在计算最佳移动/它的递归执行不正确时存在问题,但它可能是 calculateScore(),所以我也会添加它。

public static int calculateScore() {
    int boardScore = 0;
    for (int c = 0; c < 64; c++) {
        if (Board[c].color.equals(aiColor)) {
            boardScore += Board[c].points;
        } else {
            boardScore -= Board[c].points;
        }
    }
    return boardScore;
}

标签: javachessminimax

解决方案


事实证明,这个错误不是逻辑问题,而是我的方法有问题,即使在我声明“我确信其他方法可以完美运行”之后也是如此。事实证明,问题是由于验证了移动的部分。

在国际象棋中有一条模糊的“过路人”规则,即刚刚向前移动两个棋子的棋子的行为与一个尚未向前移动两个格子的棋子的行为不同。出于这个原因,我为这些棋子设置了一个类,并在常规动作结束时将它们的实例替换为常规棋子,但是由于这些测试动作不是常规动作,因此它没有删除movedTwoPawn,并认为它无法移动,就像在常规游戏中一样,movedTwoPawn 永远无法移动。

为了解决这个问题,我添加了用常规 Pawns 替换movedTwoPawns 并且它工作得很好。


推荐阅读