是什么导致程序运行一段时间后开始错误计算?

我正在尝试为跳棋游戏实现 NegaMax 算法。我目前只是用深度为 0 进行测试,这意味着当前玩家只评估他的所有移动,而不考虑对手接下来可能做什么。它在大约一半的游戏时间里运行完美(正确计算得分),然后在中途开始输出无意义的答案。

例如,白方可能只剩 1 个棋子,而黑方有 5 个,但它会将白方的移动评估为 7 分,而实际上它们都应该是负数,因为白方正在输。黑方可能在他的下一步行动中获胜,但它会将制胜一招评估为 -4,即使它应该是 1000。

我可以理解它一直输出垃圾数据,但为什么它在前几回合可以正常工作,然后才开始出错?

private static Move GetBestMove(Color color, Board board, int depth){    var bestMoves = new List<Move>();    IEnumerable<Move> validMoves = board.GetValidMoves(color);    int highestScore = int.MinValue;    Board boardAfterMove;    int tmpScore;    var rand = new Random();    Debug.WriteLine("{0}'s Moves:", color);    foreach (Move move in validMoves)    {        boardAfterMove = board.Clone().ApplyMove(move);        if (move.IsJump && !move.IsCrowned && boardAfterMove.GetJumps(color).Any())            tmpScore = NegaMax(color, boardAfterMove, depth);        else            tmpScore = -NegaMax(Board.Opposite(color), boardAfterMove, depth);        Debug.WriteLine("{0}: {1}", move, tmpScore);        if (tmpScore > highestScore)        {            bestMoves.Clear();            bestMoves.Add(move);            highestScore = tmpScore;        }        else if (tmpScore == highestScore)        {            bestMoves.Add(move);        }    }    return bestMoves[rand.Next(bestMoves.Count)];}private static int NegaMax(Color color, Board board, int depth){    return BoardScore(color, board);}private static int BoardScore(Color color, Board board){    if (!board.GetValidMoves(color).Any()) return -1000;    return board.OfType<Checker>().Sum(c => (c.Color == color ? 1 : -1) * (c.Class == Class.Man ? 2 : 3));}

我已经分离出一个它不喜欢的棋盘状态,在一个 6×6 的棋盘上:

 . . .. w B  W . .. . .  . w .. . W w = white, b = black, capital letter = king

看来这不是一个时间或已进行步数的问题,只是它不喜欢特定的棋盘状态。但我没有看到这个状态有什么特别之处。

在这种状态下,它将黑方的所有 4 步都评估为 -13。如果你看看我是如何评分的,它说每个士兵 2 分,每个国王 3 分,如果属于对方玩家则为负分。看起来它好像把所有的棋子都当成了白棋……这是得到 13 的唯一方法。


我找到了另一个线索。在棋盘评分方法中,我让它打印出它所看到的内容……这是它告诉我的:

2: White 4: White 6: White 13: White 17: White 

其中棋盘的格子编号如下:

  00  01  0203  04  05  06  07  0809  10  11  12  13  1415  16  17

我认为它确实说黑棋是白棋……现在要弄清楚是什么导致了这种情况。


所以……现在我知道颜色是错的,但只在 BoardScore 函数中。我的正常显示程序从未发现这一点,否则我几个小时前就该找出问题了。我正在考虑颜色可能在 ApplyMove 函数中被切换了……

public Board ApplyMove(Move m){    if (m.IsJump)    {        bool indented = m.Start % Width < _rowWidth;        int offset = indented ? 1 : 0;        int enemy = (m.Start + m.End) / 2 + offset;        this[m.Color, enemy] = Tile.Empty;    }    this[m.Color, m.End] = this[m.Color, m.Start];    this[m.Color, m.Start] = Tile.Empty;    var checker = this[m.Color, m.End] as Checker;    if (m.IsCrowned) checker.Class = Class.King;    return this;}

但这也没有多大意义……棋子只是从起始位置复制到结束位置。需要调查 m.Color 是什么……也许它会提供更多线索!我感觉自己像个侦探。


回答:

根据您的描述,我怀疑是棋子的颜色数据出了问题。如果它以某种方式被设置为错误的值,它会将所有内容评估为负值。

我对您的 BoardScore 函数不太满意——像这样复杂的公式很擅长隐藏错误,而且很难调试。

我建议添加一个 Checker.Value(Color) 函数来简化 BoardScore,并允许您更轻松地查看正在发生的事情。

您没有展示 Color 的数据类型,如果它允许超过黑白两种颜色,那么那里的损坏值会导致您观察到的行为。

根据您最新的更新,我建议查看 boardAfterMove 并确保它被正确生成。

再次编辑:那里有两个调用——克隆是否正确?

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注