在java国际象棋游戏的NegaMax实现中找不到错误

在java国际象棋游戏的NegaMax实现中找不到错误,java,tree,chess,Java,Tree,Chess,我在识别negamax(alpha-beta)实现中的错误时遇到困难 我可以让简单的negamax版本正常工作,但是我无法将其转换为negamax的alpha beta版本 首先是正在运行的简单negaMax版本 public class NegaMax { static Node bestNode = null; public static final Node getMove(Node root, boolean maximizingPlayer) { be

我在识别negamax(alpha-beta)实现中的错误时遇到困难

我可以让简单的negamax版本正常工作,但是我无法将其转换为negamax的alpha beta版本

首先是正在运行的简单negaMax版本

public class NegaMax {

    static Node bestNode = null;
    public static final Node getMove(Node root, boolean maximizingPlayer) {
        bestNode = null;
        int score = maximizingPlayer 
                  ? negaMax(root, 4, maximizingPlayer)
                  : negaMax(root, 4, !maximizingPlayer);

        if(bestNode != null) {
            bestNode.score = score;
        }
        return bestNode;
    }

    private static final int evaluate(Node node, boolean maximizingPlayer) {
        return Integer.parseInt(node.value) * (maximizingPlayer ? 1 : -1);
    }

    private static final int negaMax(Node node, int depthLeft, boolean maximizingPlayer) {
        if(depthLeft == 0) { 
            return evaluate(node, maximizingPlayer);
        }

        int max = Integer.MIN_VALUE;
        Node bestChildSoFar = null;
        List<Node> children = node.getChildren();

        for(Node child : children) {
            int score = -negaMax(child, depthLeft - 1, !maximizingPlayer);
            if(score > max) {
                bestChildSoFar = child;
                max = score;
            }
        }
        bestNode = bestChildSoFar;
        return max;
    }    
公共类NegaMax{
静态节点bestNode=null;
公共静态最终节点getMove(节点根,布尔最大化播放器){
bestNode=null;
整数分数=最大化玩家
?negaMax(根,4,最大化播放器)
:negaMax(根,4,!maximizingPlayer);
if(bestNode!=null){
bestNode.score=分数;
}
返回最佳节点;
}
私有静态最终整数求值(节点,布尔最大化播放器){
返回整数.parseInt(node.value)*(maximizingPlayer?1:-1);
}
私有静态final int negaMax(节点节点、int depthLeft、布尔最大化播放器){
如果(depthLeft==0){
返回评估(节点,最大化玩家);
}
int max=整数的最小值;
节点BestChildsFar=null;
List children=node.getChildren();
用于(节点子节点:子节点){
int分数=-negaMax(儿童,第三名-1,!最大化玩家);
如果(分数>最大值){
BestChildsFar=孩子;
最大值=分数;
}
}
bestNode=bestChildSoFar;
返回最大值;
}    
…这里的版本不是…(返回-无穷大)--(来自chessprogrammingwiki的源代码想法)

公共类AlphaBetaNegaMax{
公共静态最终节点getMove(节点根,布尔最大化播放器){
整数分数=最大化玩家
?alphaBeta(根,Integer.MIN\u值,Integer.MAX\u值,4,最大化播放器)
:alphaBeta(根,Integer.MIN\u值,Integer.MAX\u值,4,!maximizingPlayer);
系统输出打印项次(分数);
return null;//分数错误…请先解决此问题
}
私有静态最终整数求值(节点,布尔isMaximizingPlayer){
返回整数.parseInt(node.value)*(isMaximizingPlayer?1:-1);
}
私有静态最终int-alphaBeta(节点节点、int-alpha、int-beta、int-depthleft、布尔最大化播放器){
如果(depthleft==0){
返回评估(节点,最大化玩家);
}
List children=node.getChildren();
用于(节点子节点:子节点){
int分数=-alphaBeta(儿童,-beta,-alpha,深度-1,!最大化玩家);
如果(分数>=beta){
返回β;
}
如果(分数>α){
α=分数;
}
}
返回α;
}
}
编辑:

问题是你没有捕获移动集,整个4深移动集,即最低移动集对棋盘上的每一个棋子进行4深移动,然后决定使用哪一个移动作为最低成本集的第一个移动,你只能找到非常低的移动,在某些情况下可能是第二、第三或第四个移动。如果该移动返回t这里没有可能的方法来实际完成移动,因为您没有捕获板的前面移动

private static final int INF = Integer.MAX_VALUE;
private static final int DEPTH = 4;
private Move[] best4depthmove = new Move[DEPTH];
private int[] score4deep = new int[DEPTH];

public static final Move getMove(Move previous) {
    for(int x = 0; x < DEPTH; x++)
    {
        best4depthmove[x] = null;
        score4deep[x] = 0;
    }

    negamax(previous, 0);

    return best4depthmove[0];
}

private static final negamax(Move move, int depth) 
{
     int newscore = 0;

    if(depth < DEPTH) 
    {
        List<Move> moves = Engine.getMoves(move);
        for(Move m : moves) 
        {
             newscore = MoveEvaluators.evaluate(m);
             if(newscore > score4deep[depth])
             {
                 score4deep[depth] = newscore;
                 best4depthmove[depth] = m;
             }
             negamax(m, depth+1);

        }
    }
}
private static final int INF=Integer.MAX_值;
专用静态最终整数深度=4;
私人移动[]best4depthmove=新移动[深度];
私有整数[]score4deep=新整数[深度];
公共静态最终移动getMove(上一个移动){
对于(int x=0;xscore4deep[深度])
{
score4deep[深度]=新闻核心;
最佳4深度移动[深度]=m;
}
内伽马峰(米,深度+1);
}
}
}

这就是我所能想到的,它应该递归地遍历每一个可能的移动。这可能适用于任何深度,只要你有足够的内存来处理递归调用。

我发现了这个bug,这个bug非常微妙……问题是我假设了Math.MIN\u值和Ma的绝对值MAX_值是相同的,忘记了java是如何用2表示整数的

我刚刚将无穷大定义为9999999,并将这个对称值用于正无穷大和负无穷大,它起了作用(alpha和beta的交换是这些值必须对称的地方,否则我们会看到这个bug)


我认为web上的这个小程序也有类似的问题:(我通知了作者,他回答了。他确实有完全相同的错误!)

我认为他确实引用了以前的移动,就像在getMove()方法中引用Engine.getMoves(先前)一样…因此,我们只能假设实现只是代码的一部分。他/她使用它的方式是从他们创建或使用的引擎中获取可能的移动,而不是跟踪以前的移动,而且您也不希望使用引擎通过引擎调用找到成本最高/最低的移动,这将花费很长时间和很慢的时间我知道我的基本情况并不完全正确,因为它不仅要看深度,还要看对局和僵局。我有如上所述的方法来简化错误检测过程。如果没有达到游戏结束状态,终端节点的评估结果不会传递回调用方,而是传递给上一个negamax call(我认为是正确的)。错的是我在某个地方错误地否定了。我将在假期后再次尝试调试:)还要注意,引擎返回一整套fr
private static final int INF = Integer.MAX_VALUE;
private static final int DEPTH = 4;
private Move[] best4depthmove = new Move[DEPTH];
private int[] score4deep = new int[DEPTH];

public static final Move getMove(Move previous) {
    for(int x = 0; x < DEPTH; x++)
    {
        best4depthmove[x] = null;
        score4deep[x] = 0;
    }

    negamax(previous, 0);

    return best4depthmove[0];
}

private static final negamax(Move move, int depth) 
{
     int newscore = 0;

    if(depth < DEPTH) 
    {
        List<Move> moves = Engine.getMoves(move);
        for(Move m : moves) 
        {
             newscore = MoveEvaluators.evaluate(m);
             if(newscore > score4deep[depth])
             {
                 score4deep[depth] = newscore;
                 best4depthmove[depth] = m;
             }
             negamax(m, depth+1);

        }
    }
}