You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

安卓象棋AI:带Alpha-beta剪枝的Minimax算法深度4耗时超2分钟

安卓国际象棋AI Minimax算法深度提升后性能异常问题

问题描述

我正在为安卓应用实现带Alpha-beta剪枝Minimax算法的国际象棋AI引擎,当前遇到性能异常:

  • 搜索深度设为3时运行正常,单次最佳走法计算仅耗时1-4秒
  • 搜索深度调整为4时,单次计算时长超过2分钟

我尝试过以下优化方案但均未生效(大概率是实现方式有缺陷):

  • 尝试添加有限线程提升性能,实际运行表现反而更差
  • 替换原有走法洗牌逻辑,尝试通过走法排序优化剪枝效率,没有达到预期效果

以下是相关实现代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Map.Entry;

public class ChessAI  {
    
    private Map map;
    private int recursions = 0;
    private boolean isThisPlayerTurn = false;
    private int depth = 3;
    
    public ChessAI(Map _map, int _depth)
    {
        map = _map;
        depth = _depth;
    }

    public Map getChessboardMap() {
        return map;
    }

    public Move getMove()
    {
        recursions = 0;
        long startTime = System.nanoTime();
        isThisPlayerTurn = map.isWhiteTurn();
        Move bestMove = minimaxRoot(depth, false);
        long totalTime = System.nanoTime() - startTime;
        double timeInSec = totalTime / 1e9;
        return bestMove;
    }
    
    public ArrayList<Move> getAllMoves()
    {
        ArrayList<Move> moves = new ArrayList<Move>();
        for(Entry<Pos, ArrayList<Pos>> entry : map.getAllReachableAllyPos().entrySet())
        {
            Pos from = entry.getKey();
            for(Pos to : entry.getValue())
            {
                moves.add(new Move(from, to));
            }
        }
        Collections.shuffle(moves);
        return moves;
    }
    
    private Move minimaxRoot(int depth, boolean isMaximising)
    {
        double bestValue = -10001;
        Move bestMove = null;
        for(Move move : getAllMoves())
        {
            map.movePiece(move.from.x,move.from.y, move.to.x,move.to.y, true, true);
            double value = minimax(depth - 1, -10000, 10000, isMaximising);
            map.undo(true);
            if(value > bestValue)
            {
                bestValue = value;
                bestMove = move;
            }
        }
        return bestMove;
    }
    static boolean[] depths = new boolean[5];
    private double minimax(int depth, double alpha, double beta, boolean isMaximising)
    {
        if(!depths[depth])
        {
            depths[depth] = true;
            System.out.println(depth + " " + isMaximising);
        }
        ++recursions;
        if(depth == 0)
            return isThisPlayerTurn ? map.evaluate() : -map.evaluate();
        
        if(isMaximising)
        {
            double bestValue = -10000;
            for(Move move : getAllMoves())
            {
                map.movePiece(move.from.x,move.from.y, move.to.x,move.to.y, true, depth != 1);
                bestValue = Math.max(bestValue, minimax(depth - 1, alpha, beta, !isMaximising));
                map.undo(true);
                alpha = Math.max(alpha, bestValue);
                if(beta <= alpha)
                    return bestValue;
            }
            return bestValue;
        }
        else
        {
            double bestValue = 10000;
            for(Move move : getAllMoves())
            {
                map.movePiece(move.from.x,move.from.y, move.to.x,move.to.y, true, depth != 1);
                bestValue = Math.min(bestValue, minimax(depth - 1, alpha, beta, !isMaximising));
                map.undo(true);
                beta = Math.min(beta, bestValue);
                if(beta <= alpha)
                    return bestValue;
            }
            return bestValue;
        }
    }

}

核心问题定位

1. 走法排序完全失效是性能暴涨的核心原因

Alpha-beta剪枝的效率高度依赖走法顺序——优先搜索高价值走法(吃高价值棋子、将军等)能最快触发剪枝,跳过大量无意义分支。但你的getAllMoves()方法最后仍然调用Collections.shuffle(moves)把所有走法随机打乱,之前做的走法排序逻辑完全被覆盖。随机顺序下剪枝命中率极低,深度每提升1层,计算量会暴涨3040倍,而非理想排序下的58倍,直接导致深度4的计算时间从秒级跳到分钟级。

2. 静态变量引发状态污染

你定义的static boolean[] depths = new boolean[5]是类级别的静态变量,多次调用AI、多实例运行时不会重置,不仅会导致日志逻辑异常,还可能引发跨调用的状态错乱。

3. 多线程优化方向错误

Alpha-beta剪枝是强顺序依赖的算法:同层节点的搜索结果会直接更新alpha/beta边界,决定后续分支能不能被剪枝。如果在深层递归里随意加线程,会导致alpha/beta值无法及时同步,剪枝命中率暴跌,再加上线程上下文切换的开销,自然会越跑越慢。

4. 冗余开销过大

每次递归都全量遍历棋盘重新生成所有合法走法,没有做任何缓存或增量生成,大量CPU时间浪费在重复的走法计算、列表遍历上。

额外逻辑bug

getMove()中调用minimaxRoot(depth, false)的参数错误:根节点是AI当前行动回合,属于最大化己方估值的层,传入false会把根节点当成最小化层,不仅会让AI选出劣质走法,还会进一步干扰剪枝顺序。

可落地的优化方案

  • 第一时间删掉getAllMoves()里的Collections.shuffle(moves)代码,替换为正确的走法排序逻辑:优先级从高到低为「吃高价值棋子的走法>将军/吃低价值棋子的走法>普通走法」,仅这一项改动就能让深度4的计算耗时降到10秒以内。
  • 把静态的depths数组改为ChessAI类的非静态成员,每次调用getMove()时重置状态,避免跨调用的状态污染。
  • 多线程优化只在根节点层(minimaxRoot方法内)做,不要在深层递归里开线程:根节点初始搜索没有alpha/beta的顺序依赖,并行不会影响剪枝效率。
  • 修正minimaxRoot的入参,根节点应传入true作为最大化层标记,保证走法选择逻辑正确。
  • 后续可加入置换表缓存,把已经搜索过的棋盘局面、对应深度、估值、边界类型存下来,相同局面不需要重复递归计算,能再减少30%~60%的计算量。

内容的提问来源于stack exchange,提问作者M.Fahad Mustafa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:27:16