【问题标题】:Chess AI MiniMax algorithm not working国际象棋 AI MiniMax 算法不起作用
【发布时间】:2018-03-14 22:50:40
【问题描述】:

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

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

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

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

PieceMovements.move() 将棋子(p) 移动到位置(m -> 表示移动)

PieceMovements.undo() 撤消上一个动作

searchDepth 是一个变量,在第一次调用 miniMax 时作为深度值传入,换句话说,就是你想向下搜索多远。原因...

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

... 是记录这首曲子并进行移动。我在搜索树的顶层记录了这个值。 piece 和 move 代表实际的棋子,并且 move 算法认为是最有效的。

当调用 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;
}

和RelativePieceValues 类:

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;
}

如果您有任何问题,请提出。感谢您的任何回复,我已经坚持了一段时间。我想知道我的 mini max 算法或评估函数是否真的有问题,或者我的程序中可能还有其他你看不到的问题。 谢谢。

【问题讨论】:

  • 在任何时候你都不会使用你的极小极大的结果来决定采取哪一步。您似乎只是将您在递归堆栈顶部看到的每一个可能的移动分配给一个实例变量,这意味着您使用的移动始终是最后一个考虑的移动。
  • 那么我将在算法中的哪个位置决定最佳的移动是什么?
  • 板子评估也很简单。如果搜索找不到要捕获的部分,它如何确定一个位置是否优于另一个位置?来回移动可能是对当前位置感到满意的结果(对相持规则一无所知)。
  • 那我该如何改进评估功能呢?有什么推荐的吗?
  • 我也知道有negamax。如果使用 negamax,评估函数只考虑一侧(白色或黑色)的部分。当使用带有 minimax 算法的评估函数时,我是否必须使用棋盘上的所有棋子(包括白色和黑色)来计算棋盘值?

标签: java chess minimax


【解决方案1】:

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

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

使用 minimax 函数的初始调用:

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

Minimax 函数本身。 board.is_human_turn 在 board 类中用于确定玩家是谁。然后我们得到该玩家(该位置的孩子)的所有可能动作。

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

对于每个玩家(分别最大化和最小化),它会通过所有孩子。它制作了一个棋盘副本(不与原始棋盘更改)并在棋盘上移动(其中一个孩子)。然后它计算所有节点的评估,并与评估一起返回最佳移动。

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

您还可以实施开局书,这样您就可以在每场比赛中获得良好的开端,而无需花时间计算位置。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多