为什么这段代码给出了两种不同的输出(似乎是)相同的输入? [英] Why does this code give two different outputs for (what appears to be) the same inputs?

查看:181
本文介绍了为什么这段代码给出了两种不同的输出(似乎是)相同的输入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想一些AI的跳棋游戏程序。我的程序是说有0移动的白人球员,尽管我知道有。在 GetValidMoves()功能进行了测试,并在代码的其他地区工作。

I'm trying to program some AI for a game of checkers. My program is saying there are 0 moves for the white player, even though I know there are. The GetValidMoves() function is tested, and works in other areas of the code.

要尽量隔离我救出来有问题的电路板状态,那么该程序加载它备份,看看我会得到同样的问题:

To try and isolate the program I saved out the problematic board-state then loaded it back up to see if I would get the same problem:

using(Stream s = File.Open("board.dat", FileMode.Create))
{
    var bf = new BinaryFormatter();
    bf.Serialize(s, board);
}
Debug.WriteLine(board.GetValidMoves(Color.White).Count());

using (Stream s = File.Open("board.dat", FileMode.Open))
{
    var bf = new BinaryFormatter();
    board = (Board)bf.Deserialize(s);
}
Debug.WriteLine(board.GetValidMoves(Color.White).Count());

这将显示:

0
7

当我期望的输出是相同(7是正确的)。

When I would expect the output to be the same (7 is correct).

这是什么原因,开始反序列化后的工作?董事会的两个实例似乎是完全一样的......我打印出所有属性,它们都同样正确。我不知道从哪里何去何从?

What could cause this to start working after deserialization? Both instances of the board appear to be exactly the same... I printed out all the properties and they all same correct. I'm not sure where to go from here?

董事会(反序列化之前)的第一个实例是克隆的结果。我可以克隆它错了吗?是否存在悬空引用

The first instance of the board (before deserialization) is the result of a clone. Could I be cloning it wrong? Are there "dangling references"?

GetValidMoves:

    public IEnumerable<Move> GetValidMoves(Color c)
    {
        var jumps = GetJumps(c);
        if (jumps.Any())
            foreach (var j in jumps)
                yield return j;
        else
            foreach (var s in GetSlides(c))
                yield return s;
    }

    public IEnumerable<Move> GetSlides(Color c)
    {
        foreach (int i in Enumerate(c))
            foreach (var s in GetSlides(c, i))
                yield return s;
    }

    public IEnumerable<Move> GetJumps(Color c)
    {
        foreach (int i in Enumerate(c))
            foreach (var j in GetJumps(c, i))
                yield return j;
    }

    public IEnumerable<Move> GetJumps(Color c, int i)
    {
        Checker checker = this[c, i] as Checker;
        bool indentedRow = i % Width < rowWidth;
        int column = i % rowWidth;
        int offset = indentedRow ? 0 : -1;
        bool againstLeft = column == 0;
        bool againstRight = column == rowWidth - 1;
        int moveSW = i + rowWidth + offset;
        int moveSE = moveSW + 1;
        int jumpSW = i + rowWidth * 2 - 1;
        int jumpSE = jumpSW + 2;

        if (!againstLeft && jumpSW < Count && IsEnemy(c, moveSW) && IsEmpty(c, jumpSW))
            yield return new Move(c, i, jumpSW, jump: true, crown: IsCrowned(checker, jumpSW));
        if (!againstRight && jumpSE < Count && IsEnemy(c, moveSE) && IsEmpty(c, jumpSE))
            yield return new Move(c, i, jumpSE, jump: true, crown: IsCrowned(checker, jumpSE));

        if (checker.Class == Class.King)
        {
            int moveNW = i - rowWidth + offset;
            int moveNE = moveNW + 1;
            int jumpNW = i - rowWidth * 2 - 1;
            int jumpNE = jumpNW + 2;

            if (!againstLeft && jumpNW >= 0 && IsEnemy(c, moveNW) && IsEmpty(c, jumpNW))
                yield return new Move(c, i, jumpNW, jump: true);
            if (!againstRight && jumpNE >= 0 && IsEnemy(c, moveNE) && IsEmpty(c, jumpNE))
                yield return new Move(c, i, jumpNE, jump: true);
        }
    }

    public IEnumerable<Move> GetSlides(Color c, int i)
    {
        Checker checker = this[c, i] as Checker;
        bool indentedRow = i % Width < rowWidth;
        int column = i % rowWidth;
        int offset = indentedRow ? 0 : -1;
        bool againstLeft = !indentedRow && column == 0;
        bool againstRight = indentedRow && column == rowWidth - 1;
        int moveSW = i + rowWidth + offset;
        int moveSE = moveSW + 1;

        if (!againstLeft && moveSW < Count && IsEmpty(c, moveSW))
            yield return new Move(c, i, moveSW, crown: IsCrowned(checker, moveSW));
        if (!againstRight && moveSE < Count && IsEmpty(c, moveSE))
            yield return new Move(c, i, moveSE, crown: IsCrowned(checker, moveSE));

        if (checker.Class == Class.King)
        {
            int moveNW = i - rowWidth + offset;
            int moveNE = moveNW + 1;

            if (!againstLeft && moveNW >= 0 && IsEmpty(c, moveNW))
                yield return new Move(c, i, moveNW, crown: IsCrowned(checker, moveNW));
            if (!againstRight && moveNE >= 0 && IsEmpty(c, moveNE))
                yield return new Move(c, i, moveNE, crown: IsCrowned(checker, moveNE));
        }
    }



它的不应该的。有副作用

要回答有关是否有效的举措是在不经意间改变电路板状态查询:

To answer your queries about whether valid moves is inadvertently changing the board state:

            var board = new Board(8, 8);
            board.SetUp();
            foreach(var m in board.GetValidMoves(Color.White))
                Console.WriteLine(m);
            Console.WriteLine("---");
            foreach(var m in board.GetValidMoves(Color.White))
                Console.WriteLine(m);



打印:

Prints:

8-12
8-13
9-13
9-14
10-14
10-15
11-15
---
8-12
8-13
9-13
9-14
10-14
10-15
11-15

(同样输出两次)正如你所期望。

(The same output twice) As you'd expect.

推荐答案

很肯定的bug是实际上是 Board.Clone 方法。我想序列化/反序列化的品牌创建新的对象,而我clone方法不正确克隆的一切,而是返回引用

Pretty sure the bug was in the Board.Clone method actually. I think serializing/deserializing created brand new objects whereas my clone method wasn't cloning everything correctly, but rather returning references.

请参阅http://stackoverflow.com/questions/3647983/how-to-clone-an-inherited-object 详情

这篇关于为什么这段代码给出了两种不同的输出(似乎是)相同的输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆