当前位置: 首页 > 知识库问答 >
问题:

国际象棋AI MiniMax算法不工作

通宾白
2023-03-14

我已经在我的国际象棋AI中实现了极大极小算法,我知道它不能正常工作,因为它只是一次又一次地来回移动一个棋子。

getPieces(true)返回当前棋盘状态下的所有白色棋子

getPieces(false)返回当前板状态下的所有黑色块

ChessPiece.getAllPoentialMoves()非常不言自明,获取特定块的所有可能移动

PieceMovements.move()移动一块(p)到位置(m-

PieceMovements.undo()撤消之前的移动

Search chDepth是一个变量,当第一次调用MiniMax时,它首先作为深度值传递,换句话说,它是您想要向下搜索多远。的原因...

if(depth == searchDepth) {
    piece = p;
    move = m;
}

...是记录这首曲子,然后移动。我把这个值记录在搜索树的顶层,块和移动代表算法认为最高效的实际块和移动。

当调用miniMax时,它看起来是这样的:miniMax(searchDepth,false)。错误,因为AI,黑色,是最小值。

这是我的方法

public int miniMax(int depth, boolean maxi) {

    if(maxi) {
        if(depth == 0) return evaluateBoard();
        int max = -9999; //negative infinity
        for(ChessPiece p : getPieces(maxi)) for(Vector2 m : p.getAllPotentialMoves()) {
                PieceMovements.move(board, p, (int)m.x, (int)m.y);
                max = Math.max(max, miniMax(depth-1, !maxi));
                PieceMovements.undo();
                if(depth == searchDepth) {
                    piece = p;
                    move = m;
                }
            }
        return max;
    } else {
        if(depth == 0) return -evaluateBoard();
        int min = 9999; //positive infinity
        for(ChessPiece p : getPieces(maxi)) for(Vector2 m : p.getAllPotentialMoves()) {
                PieceMovements.move(board, p, (int)m.x, (int)m.y);
                min = Math.min(min, miniMax(depth-1, !maxi));
                PieceMovements.undo();
                if(depth == searchDepth) {
                    piece = p;
                    move = m;
                }
            }
        return min;
    }
}

还有我的评估函数,它目前只取每件作品的相对作品值,并将它们相加:

public int evaluateBoard() {
    int total = 0;
    for(ChessPiece[] row : board)
        for(ChessPiece piece : row)
            if(piece != null)
                switch(piece.getPiece()) {
                    case WPAWN:
                    case BPAWN:
                        total += RelativePieceValues.PAWN;
                        //a pawn about to be promoted takes on more value
                        if(piece.getPosition().y == 1 || piece.getPosition().y == 6)
                            total += 50; //50 + 10 = 60
                        break;
                    case WKNIGHT:
                    case BKNIGHT:
                        total += RelativePieceValues.KNIGHT;
                        break;
                    case WBISHOP:
                    case BBISHOP:
                        total += RelativePieceValues.BISHOP;
                        break;
                    case WROOK:
                    case BROOK:
                        total += RelativePieceValues.ROOK;
                        break;
                    case WQUEEN:
                    case BQUEEN:
                        total += RelativePieceValues.QUEEN;
                        break;
                    case WKING:
                    case BKING:
                        total += RelativePieceValues.KING;
                        break;
                }

    return total;
}

和相对值类:

public class RelativePieceValues{

//piece value constants
public static final int PAWN = 10;
public static final int KNIGHT = 30;
public static final int BISHOP = 30;
public static final int ROOK = 50;
public static final int QUEEN = 90;
public static final int KING = 900;
}

如果您有任何问题,请提问。谢谢你的任何回复,我已经被困在这一段时间了。我想知道我的迷你最大算法或我的评估函数是否真的有问题,或者我的程序中可能还有你看不到的其他问题。谢谢。

共有1个答案

欧金鹏
2023-03-14

正如答案中指出的,您没有使用minimax函数的结果。下面是我用Python开发的工作版本,希望您能将其翻译成java:)

这一个是使用alpha-beta修剪来提高性能。

具有极小值函数的初始调用:

best_move, evaluation = minimax(board, 5, -math.inf, math.inf, True)

最小值函数本身。board.is_human_turn在棋盘类中用于确定玩家是谁。然后我们得到那个球员(位置的孩子)所有可能的移动。

然后它检查我们是否达到了最大深度,或者它是否在这个位置上结束了游戏(平局或检查伴侣)。

对于每个玩家(分别最大化和最小化),它会遍历所有的子玩家。它制作了一个板副本(不与原始板更改)并在板上移动(一个孩子)。然后,它计算所有节点中的计算值,并随计算值返回最佳移动。

def minimax(board, depth, alpha, beta, maximizing_player):

    board.is_human_turn = not maximizing_player
    children = board.get_all_possible_moves()

    if depth == 0 or board.is_draw or board.is_check_mate:
        return None, evaluate(board)

    best_move = random.choice(children)

    if maximizing_player:
        max_eval = -math.inf
        for child in children:
            board_copy = copy.deepcopy(board)
            board_copy.move(child)
            current_eval = minimax(board_copy, depth - 1, alpha, beta, False)[1]
            if current_eval > max_eval:
                max_eval = current_eval
                best_move = child
            alpha = max(alpha, current_eval)
            if beta <= alpha:
                break
        return best_move, max_eval

    else:
        min_eval = math.inf
        for child in children:
            board_copy = copy.deepcopy(board)
            board_copy.move(child)
            current_eval = minimax(board_copy, depth - 1, alpha, beta, True)[1]
            if current_eval < min_eval:
                min_eval = current_eval
                best_move = child
            beta = min(beta, current_eval)
            if beta <= alpha:
                break
        return best_move, min_eval

我的评估函数目前非常简单,只考虑棋子值以及它们在棋盘上的位置。例如,一个骑士本来值320,然后你根据它的位置进行加减。有关更多信息,请参阅此链接:https://www.chessprogramming.org/Simplified_Evaluation_Function.

你也可以实现一个开场白,这样你就可以在每场比赛中有一个好的开始,而不必花时间计算位置。

希望这有帮助!

 类似资料:
  • 我对我的象棋游戏的最小极大算法的实现有问题。它的大部分似乎都起作用了,但它要么从来没有做出好的动作,要么对它们的评估(基于两个玩家的活动棋子的分数)出了问题。例如,如果我设置了check(例如,傻瓜的伴侣),ai会做一些随机的事情,而不是杀死国王。我真的找不出我做错了什么。 评估电路板的类StandardBoardEvaluator在经过一些测试后似乎可以工作,因此问题很可能出现在MiniMax实

  • 我正在下国际象棋,除了一件事,我几乎得到了所有的东西:我需要使棋手不可能将棋子移动到棋盘上。我很难解决这个问题。 我现在用伪代码生成的有效移动是:类getMoveLocations(我定义了一个位置为国际象棋中的一个方块):如果这个位置在边界内,这个位置的棋子是敌人的棋子,并且模拟的移动不会导致棋盘被检查,然后将该位置添加到工件可以移动到的可能位置。 问题是我如何检查棋盘是否“在检查中”。在我的代

  • DreamChess 是一款开放源码、跨平台(可在 Windows、Mac OS X 及 Linux 上运行)的 3D 国际象棋游戏。该游戏包含自身的引擎 Dreamer,提供各种国际象棋棋盘,并具有背景音乐及声效等其他附属功能。

  • 我已经为我的国际象棋游戏实现了alpha-beta算法,但是要最终做出一个相当愚蠢的动作需要很多时间(4-ply需要几分钟)。 我已经试图找到错误(我假设我犯了一个)2天了,我非常感谢对我的代码的一些外部输入。 getMobile函数:为根节点调用,它为所有子节点调用alphaBeta函数(可能的移动),然后选择得分最高的移动。 AlphaBeta函数: 编辑:我应该注意到,评估板只评估棋子的机动

  • 我已经有一个Board对象,包含一个碎片列表。Piece是一个抽象类,有一个位置(x,y)和一个颜色(黑色或白色)。然后是King、Queen、Knight这三个类,实现了Piece类。 谢谢

  • 上面的代码显示了一个可以上下移动的部分的示例。这不是一个有效的棋步。所以,如果我要移动一个皇后,我该怎么做呢?我们只是假设我们已经有了一个矩阵(x,y)8×8的板。

  • 我是编程的新手,我正在尝试实现一个小的象棋游戏。 我目前正在为每件作品的验证移动而挣扎。 字典是: 我在每个子类中都创建了一个函数(Pawn,Rook,Queen...)这应该能证明这次行动是正确的。语法类似于: 目前,我可以移动任何白色树懒或树懒上有一个黑色的部分(但我不能吃我自己),反之亦然。 我想我使用的是而不是列表列表这一事实使事情变得更加困难。我真的迷路了。这将是惊人的,如果你可以帮助我

  • 我为象棋游戏做了一个负极算法,我想知道如何使用最终的棋盘值结果。我知道负极算法的最终回报代表了玩家采取最佳策略后的棋盘值,但这并不完全是有用的信息。我需要知道那一步是什么,而不是它的价值。 代码如下: 在确定bestValue后,我考虑重新评估当前匹配状态的子项。然后我遍历它们,找出其中哪个孩子的statecore等于bestValue。但这是行不通的,因为不管怎样,他们中的很多人都会有相同的状态