【问题标题】:Negamax chess algorithm: How to use final return?Negamax 国际象棋算法:如何使用最终回报?
【发布时间】:2014-10-26 05:48:19
【问题描述】:

我为类似国际象棋的游戏制作了一个负最大算法,我想知道如何使用最终的棋盘值结果。我知道 negamax 算法的最终回报代表了玩家采取最佳行动后棋盘的价值,但这并不是完全有用的信息。我需要知道这个动作是什么,而不是它的价值。

代码如下:

public int negamax(Match match, int depth, int alpha, int beta, int color) {
    if(depth == 0) {
        return color*stateScore(match);
    }

    ArrayList<Match> matches = getChildren(match, color);

    if(matches.size() == 0) {
        return color*stateScore(match);
    }

    int bestValue = Integer.MIN_VALUE;

    for(int i = 0; i != matches.size(); i++) {
        int value = -negamax(matches.get(i), depth-1, -beta, -alpha, -color);

        if(value > bestValue) {
            bestValue = value;
        }

        if(value > alpha) {
            alpha = value;
        }

        if(alpha >= beta) {
            break;
        }
    }

    return bestValue;
}

public void getBestMove(Match match, int color) {

    int bestValue = negamax(match, 4, Integer.MIN_VALUE, Integer.MAX_VALUE, color);

    // What to do with bestValue???

}

我想在确定 bestValue 后重新评估当前匹配状态的子项。然后我遍历它们并找出其中哪些孩子的 stateScore 等于 bestValue。但这行不通,因为他们中的很多人无论如何都会有相同的 stateScore,这是他们可以导致的结果......

【问题讨论】:

标签: java algorithm alpha-beta-pruning negamax


【解决方案1】:

我可以看到您正在执行 qsearch 和 alpha-beta。您的算法众所周知,但您缺少关键部分。

让我概述一下国际象棋搜索的基本算法,它甚至适用于 Stockfish(世界上最强大的引擎)。

search(Position p) {

    if (leaf node)
        qsearch(p)

    if (need to do move reduction)
        do_move_reduction_and_cut_off(p)

    moves = generate_moves(p)

    for_each(move in moves) {            
        p.move(move)
        v = -search(p, -beta, -alpha)
        p.undo(move)

        store the score and move into a hash table

        if (v > beta)
           cutoff break;           
    }

这只是一个非常简短的草图,但所有国际象棋算法都遵循它。对比一下你的版本,你有没有发现没有p.move(move)和p.undo(move)?

基本上,传统方法会生成给定位置的移动列表。循环移动,播放并撤消它并搜索它。如果你这样做了,你就会确切地知道哪个动作会产生哪个分数。

还要注意将移动和得分存储到哈希表中的行。如果这样做,您可以轻松地从根节点重建整个主变体。

我不知道您的 Java 类 Match 中到底有什么,但无论如何您的尝试很接近,但不是完全经典的搜索方式。请记住,您需要在搜索算法中提供一个位置对象,但您却给了它一个 Match 对象,这是错误的。

【讨论】:

  • 哦,对了...看看我想如果我使用 getChildren() 方法来获取所有可能的动作,然后将这些动作中的每一个依次应用到游戏状态的副本中,然后然后返回所有可能产生的游戏状态,然后我不需要在循环中间进行和撤消移动。我认为我可以循环所有比赛状态并对其进行评分,这是否只是一个重大误解?如果在递归 negamax 调用之后有一个 getParent() 方法调用,它会起作用吗?
  • 顺便说一下,每场比赛都包含棋盘上的棋子列表,以及描述棋盘本身的二维数组,它可以在比赛过程中发生变化 - 所以它本质上只是一个用一些花里胡哨的方式定位对象。
猜你喜欢
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-24
相关资源
最近更新 更多