代码之家  ›  专栏  ›  技术社区  ›  mpen

是什么导致这一点在一段时间后开始计算错误?

  •  1
  • mpen  · 技术社区  · 15 年前

    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));
    }
    

    我在6x6板上隔离了一个它不喜欢的板状态:

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

    看来这不是一个时间或动作数发挥的问题,它只是不喜欢特定的董事会状态。不过,我看不出这个州有什么特别之处。

    在这种状态下,它将Black的所有4个动作计算为-13。如果你看看我是怎么得分的,上面写着每个人2分,每个国王3分,如果被其他球员拥有的话是负数。它看起来好像把所有的碎片都当成了白色…这是得到13个碎片的唯一方法。


    我发现了另一条线索。在棋盘得分法中,我让它打印出它看到的东西。。这就是它告诉我的:

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

      00  01  02
    03  04  05
      06  07  08
    09  10  11
      12  13  14
    15  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

    2 回复  |  直到 15 年前
        1
  •  2
  •   Loren Pechtel    15 年前

    根据你的描述,我怀疑这件衣服的颜色数据。如果它以某种方式被设置为错误的东西,它会把所有的东西都评价为负面的。

    我发现自己对你的BoardScore函数不太满意——像这样的复杂公式善于隐藏错误,而且很难调试。

    您还没有显示Color的数据类型,如果它允许的颜色多于黑白,则损坏的值将导致您观察到的行为。

        2
  •  0
  •   mpen    15 年前

    发现了问题。

            foreach (char ch in checkers)
            {
                switch (ch)
                {
                    case 'w':
                        Add(new Checker(Color.White, Class.Man));
                        break;
                    case 'W':
                        Add(new Checker(Color.White, Class.King));
                        break;
                    case 'b':
                        Add(new Checker(Color.Black, Class.Man));
                        break;
                    case 'B':
                        Add(new Checker(Color.White, Class.King));
                        break;
                    default:
                        Add(Tile.Empty);
                        break;
                }
            }
    

    推荐文章