【问题标题】:Chess AI implementation in Java projectJava项目中的国际象棋AI实现
【发布时间】:2025-12-12 08:00:01
【问题描述】:

我目前正在将国际象棋 AI 应用到我的国际象棋游戏中。现在我正在努力如何处理 AI 的游戏状态。

因为我觉得自己像 AI,需要来自棋盘或游戏类的最新属性(在我的情况下,我发送了一个游戏类)。但我想知道,这是错误的方式。为什么?

每当我使用 minmax 计算 AI 的移动时,我都会尝试将移动放在棋盘上,但问题是这不应该在棋盘上。因为第二个玩家基本上是在使用棋盘。我觉得它会崩溃,因为每当 AI 尝试一个动作时,它都会尝试在棋盘上进行更新,从而导致崩溃。

所以我认为我必须创建游戏/棋盘的假/模拟副本(包含所需的属性、可用动作列表、棋子颜色、玩家等)并将其发送给 AI。但是最好的方法是什么?

我当前的 minimax 算法的代码设置 相关使用的其他代码:https://hastebin.com/niqaderule.java:

public class MiniMax implements MoveStrategy {

    private final BoardEvaluator boardEvaluator;
    private int searchDepth;


    public MiniMax(BoardEvaluator boardEvaluator, int searchDepth) {
        this.boardEvaluator = boardEvaluator;
        this.searchDepth = searchDepth;
    }

    @Override
    public String toString() {
        return "MiniMax{" +
                "boardEvaluator=" + boardEvaluator +
                '}';
    }

    @Override
    public Move execute(ChessGame game) {

        long startTime = System.currentTimeMillis();

        Move calculatedBestMove = null;

        int highestSeenValue = Integer.MIN_VALUE;
        int lowestSeenValue = Integer.MAX_VALUE;
        int currentValue;

        System.out.println("computer thinks" + " depth= " + this.searchDepth);

        var numberOfAllMoves = game.getBoard().getAllAvailableMoves(PieceColor.BLACK);

        for(Move move : game.getBoard().getAllAvailableMoves(PieceColor.BLACK)){
             game.getBoard().movePiece(move.getSelectedPiece(), move);
             currentValue = calculateValue(game);
             if(game.getCurrentTurn() == game.getPlayers().get(0) && currentValue >= highestSeenValue)
             {
                 highestSeenValue = currentValue;
                 calculatedBestMove = move;
             }
             else if(game.getCurrentTurn() == game.getPlayers().get(1) && currentValue <= lowestSeenValue){
                 lowestSeenValue = currentValue;
                 calculatedBestMove = move;
             }

        }
        long CalculationTime = System.currentTimeMillis() - startTime;
        return  calculatedBestMove;
    }

    public int calculateValue(ChessGame game){
        if(game.getCurrentTurn() == game.getPlayers().get(0)){
           return  min(game, -1);
        }
            return max(game,  -1);
    }


    public int min(ChessGame game, int depth){

        if(depth == 0 || game.getGameStatus() == GameStatus.BLACK_CHECK_MATE || game.getGameStatus() == GameStatus.WHITE_CHECK_MATE){
            return this.boardEvaluator.evaluate(game, depth);
        }

        int lowestValue = Integer.MAX_VALUE;

        for(Move move: game.getBoard().getAllAvailableMoves(PieceColor.BLACK)){
            game.getBoard().movePiece(move.getSelectedPiece(), move);
            int currentValue = max(game, depth -1);
            if(currentValue <= lowestValue)
            {
                lowestValue = currentValue;
            }
        }
        return lowestValue;
    }

    public int max(ChessGame game, int depth){
        if(depth == 0 || game.getGameStatus() == GameStatus.BLACK_CHECK_MATE || game.getGameStatus() == GameStatus.WHITE_CHECK_MATE){
            return this.boardEvaluator.evaluate(game, depth);
        }

        int highestSeenValue = Integer.MIN_VALUE;

        for(Move move: game.getBoard().getAllAvailableMoves(PieceColor.BLACK)){
            game.getBoard().movePiece(move.getSelectedPiece(), move);

            int currentValue = min(game, depth -1);
            if(currentValue <= highestSeenValue)
            {
                highestSeenValue = currentValue;
            }
        }
        return highestSeenValue;
    }
}

【问题讨论】:

  • 看看Board representation。你需要评估函数来告诉你当前位置的得分和一组可用的动作。
  • 为了清楚起见,每次你得到一组动作时,你都会传递一个具有新状态的棋盘副本。它应该是一个递归函数调用,一旦达到所需的深度就会退出。评分功能由您决定。
  • 作为复制棋盘的替代方法,您可以设计一个 takeBack 方法来撤消移动,将状态完全恢复到移动之前的状态(包括关于易位、过路俘虏、晋升等的状态)。这可能比复制状态更便宜。

标签: java algorithm artificial-intelligence chess minimax


【解决方案1】:

有两种常见的方法:

  1. 在移动之前(递归调用之前)创建棋盘表示的深层副本,然后将棋盘副本发送到 minimax 函数。

  2. 在棋盘上进行移动,将其发送到极小极大函数,然后收回移动以恢复原始棋盘状态。

【讨论】:

    【解决方案2】:

    最近我开始用各种人工智能机器人做类似的项目,我采取的方法是使用来自 Apache commons-lang3 的 SerializationUtils。确保你的板状态类实现了 Serializable 接口,然后你可以这样做:

    final Board state = SerializationUtils.clone(currentState)

    您可以在此处找到更多信息:https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/SerializationUtils.html

    【讨论】: