我正在为一个简单的国际象棋引擎制作一个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;
}
事实证明这个错误不是逻辑上的问题,而是我的方法的问题,即使在我的声明“我确信其他方法完美地工作”之后。事实证明,问题是由于验证件移动。
在国际象棋中有一个模糊的“en passant”规则,其中刚刚向前移动两个棋子的棋子与刚刚向前移动两个棋盘的棋子不同。出于这个原因,我有一个类用于这些碎片并在常规移动结束时用常规棋子替换它们的实例,但是由于这些测试移动不是常规移动,它没有移除movingTwoPawn,并且认为它无法移动,就像在常规游戏中一样,moveTwoPawn永远不会被移动。
为了解决这个问题,我添加了用常规Pawns替换movingTwoPawns,它完美无缺。