【问题标题】:Perft test results - Can't find Bug?Perft 测试结果 - 找不到错误?
【发布时间】:2012-07-06 15:29:48
【问题描述】:

我现在为我糟糕的英语道歉,我是意大利人。

我正在用 C# 编写一个国际象棋游戏的完整实现,Player vs Player 和 Player vs Computer,现在我在实现 NegaMax 算法时遇到了一些困难。 有兴趣的可以看看我的github仓库:https://github.com/crybot/ChessEngine_NOGUI/tree/master/Chess%20Engine%20-%20NOGUI

我已经尝试将这个项目尽可能的面向对象,所以,如果你认为我的设计不正确,请告诉我:)

这是我的问题:

我实现了一个非常简单的评估函数,它对所有玩家对称地工作:

public static float Evaluate(PieceColor playerColor, Game game)
{
    float score = 0;

    score += 1 * (game.board.GetNumberOfPieces(PieceType.Pawn, playerColor)
    - game.board.GetNumberOfPieces(PieceType.Pawn, playerColor.GetOpposite()));

    score += 3 * (game.board.GetNumberOfPieces(PieceType.Bishop, playerColor)
    - game.board.GetNumberOfPieces(PieceType.Bishop, playerColor.GetOpposite()));

    score += 3 * (game.board.GetNumberOfPieces(PieceType.Knight, playerColor)
    - game.board.GetNumberOfPieces(PieceType.Knight, playerColor.GetOpposite()));

    score += 5 * (game.board.GetNumberOfPieces(PieceType.Rook, playerColor)
    - game.board.GetNumberOfPieces(PieceType.Rook, playerColor.GetOpposite()));

    score += 9 * (game.board.GetNumberOfPieces(PieceType.Queen, playerColor)
    - game.board.GetNumberOfPieces(PieceType.Queen, playerColor.GetOpposite()));

    score += 0.1f * (game.GetPlayer(playerColor).GetMoves(game).Count);

    return score;
}

这是我的 NegaMax 函数,它接受一个游戏参数(包括棋盘、玩家、ecc.ecc。)、由枚举提供的 playerColor 和深度搜索;

我首先扫描了 EnginePlayer 的所有可能动作,然后我从 NegaMax 函数中得到了他们的分数,但有些东西不起作用......

private float NegaMax(Game game, PieceColor playerColor, int depth)
{
    if (depth == 0) 
    return EvaluateMove(playerColor, game);

    float max = float.MinValue;
    float score;

    foreach (Move move in game.GetPlayer(playerColor.GetOpposite()).GetMoves(game))
    {
        game.board.SimulateMove(move);
        score = Math.Max(max, -NegaMax(game, playerColor.GetOpposite(), depth - 1));

        game.board.CancelMove(move);

        if (score > max)
          max = score;
    }

    return max;
}


public Move ThinkMove(Game game, PieceColor playerColor, int depth)
{

    Move bestMove = new NullMove();
    float bestScore = float.MinValue;
    float temp = 0;

    foreach (Move move in GetMoves(game))
    {
        game.board.SimulateMove(move);
        temp = NegaMax(game, playerColor, depth);
        game.board.CancelMove(move);

        if (temp > bestScore)
        {
            if (Judge.IsLegal(move, game))
            {
                 bestMove = move;
                 bestScore = temp;
            }
        }
    }

    if (bestMove is NullMove)
    throw new NotImplementedException();
    return bestMove;
}

我想这就是全部......我希望你会发现我做错了什么:) 谢谢。

编辑: 我实现了一个 Perft,它显示了移动生成器的不正确性。它帮助找到了一些相对容易找到的错误,但最后一些结果仍然是错误的。 结果如下:

Perft Depth: 1
Nodes: 20  Captures: 0  Checks: 0  Castles: 0  Mates: 0  EnPassant: 0

Perft Depth: 2
Nodes: 400  Captures: 0  Checks: 0  Castles: 0  Mates: 0  EnPassant: 0

Perft Depth: 3
Nodes: 8902  Captures: 34  Checks: 12  Castles: 0  Mates: 0  EnPassant: 0

Perft Depth: 4
Nodes: 197281  Captures: 1610  Checks: 473  Castles: 0  Mates: 8  EnPassant: 0

这是正确的结果:https://chessprogramming.wikispaces.com/Perft+Results

如您所见,在深度 4,我得到了正确的节点分析,但不正确的捕获和检查值(而配合是正确的)。

多亏了这些结果,我试图通过在深度 4 处划分每次移动分析的节点来隔离错误,得到了这些结果:

Move    Nodes
a2a3    8457
a2a4    9329
b2b3    9345
b2b4    9332
c2c3    9272
c2c4    9744
d2d3    11959
d2d4    12435
e2e3    13134
e2e4    13160
f2f3    8457
f2f4    8929
g2g3    9345
g2g4    9328
h2h3    8457
h2h4    9329
b1a3    8885
b1c3    9755
g1f3    9748
g1h3    8881
Total Nodes: 197281

并与这些结果进行比较,从 Sharper 获得:

 Sharper v0.17 by Albert Bertilsson
 divide 4
 b1c3 9755
 b1a3 8885
 g1h3 8881
 g1f3 9748
 a2a3 8457
 a2a4 9329
 b2b3 9345
 b2b4 9332
 c2c3 9272
 c2c4 9744
 d2d3 11959
 d2d4 12435
 e2e3 13134
 e2e4 13160
 f2f3 8457
 f2f4 8929
 g2g3 9345
 g2g4 9328
 h2h3 8457
 h2h4 9329
 Nodes: 197281
 Moves: 20

但即使在这里值也是正确的... 所以我尝试了深度 5 perft 来获得这些结果:

Move    Nodes
a2a3    181046
a2a4    217813
b2b3    215255
b2b4    216110
c2c3    222861
c2c4    240044
d2d3    328511
d2d4    361753
e2e3    402988
e2e4    405348
f2f3    178891
f2f4    198437
g2g3    217210
g2g4    214017
h2h3    181044
h2h4    218810
b1a3    198572
b1c3    234656
g1f3    233491
g1h3    198502
Total Nodes: 4865359

然后与Sharper的结果进行比较:

 Sharper v0.17 by Albert Bertilsson
 divide 5
 b1c3 234656
 b1a3 198572
 g1h3 198502
 g1f3 233491
 a2a3 181046
 a2a4 217832
 b2b3 215255
 b2b4 216145
 c2c3 222861
 c2c4 240082
 d2d3 328511
 d2d4 361790
 e2e3 402988
 e2e4 405385
 f2f3 178889
 f2f4 198473
 g2g3 217210
 g2g4 214048
 h2h3 181044
 h2h4 218829
 Nodes: 4865609
 Moves: 20

所以我意识到问题是由棋子的双推产生的动作引起的......但我无法真正找到错误...... 有人遇到过同样的问题吗? 或类似的东西,或者只是提示找到那个错误......

谢谢大家:)

【问题讨论】:

  • 究竟是什么不工作?引擎不“智能”或根本不搜索?
  • 起初它似乎工作,但随后它试图通过将他的主教从 g8 移动到 a3 来杀死它。深度 2 有时也会给出非法动作。
  • 你测试你的移动生成器了吗?
  • 我做到了,我努力在移动生成器和 Judge 类(它说明移动是否合法)上找到错误
  • 如果您的逻辑产生非法动作,那么这与您的 negamax 方法本身无关,因为它只关心对动作进行评分。首先确保你的逻辑在有效移动中随机选择时下有效的国际象棋。

标签: c# algorithm chess minimax


【解决方案1】:

您应该首先确保移动生成是一致的,have a look here on how to。这被称为 perft 测试。另一个奇怪的事情是我在你的算法中看不到'队友'威胁:当根本没有动作并且国王被俘虏时,你应该返回一个非常糟糕的值(否则就是一个立场)。然后你应该采取一些策略来对移动进行排序,以便从 negamax 算法中受益,然后是一些“水平”策略(也就是说,如果在 depth== 0 时仍有捕获会发生什么?)。 如果您在移动生成方面遇到问题,请尝试用一些更有趣的位置挑战您的引擎,have a look here for example,或者如果您想要更难的东西this is the file that I use for testing my engine。它由许多行组成,其中包含 FEN 格式的位置,然后是以下格式的深度移动计数:

D1 50; D2 279

这意味着(例如)在深度 1 移动 50 次,在深度 2 移动 279 次

我提出的职位来自我对护目镜的旧研究,关于具有挑战性的职位。你需要能够support FEN notation,如果你还没有我强烈建议你实施,因为它是国际象棋引擎(而不仅仅是)世界中交流位置的“事实上的”标准。

【讨论】:

  • 谢谢,我会尝试,但出于好奇,您是否发现我的 NegaMax 算法有问题,除了那个伙伴?
  • 我没有,但你知道,仅仅通过眼睛进行调试并不是那么容易 :) 无论如何,伴侣的事情正在极大地影响你的引擎运行方式;)
  • 你能看看我问题的顶部吗?我添加了 perft 结果:)
  • @Crybot 正如你所看到的那样是错误的,所以你应该努力解决这个问题:我过去也有过同样的情况,我知道这是一项具有挑战性但很享受的工作 :) 我添加到我的回复一些特殊板的链接。
【解决方案2】:

你想清楚了吗?我遇到了同样的问题。说同样的话,我的意思是我在 perft(4) 的初始位置上获得了 1610 次捕获。

而且,this 家伙似乎也有同样的问题。

我非常仔细地检查了代码(并用幼稚的替代方案替换了一些复杂的代码),但没有发现任何错误。毕竟,总的移动计数是正确的,不是吗?

然后我意识到:1610 = 1576 + 34。这只是一个例子,我检查了其余的 perft 结果,并确定是问题所在。

那些“标准”perft 结果表中的捕获计数仅捕获深度等于 0 的叶节点,包括途中捕获。

【讨论】:

    猜你喜欢
    • 2018-12-30
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    • 1970-01-01
    • 2017-04-20
    • 2020-07-11
    相关资源
    最近更新 更多