5

我正在制作一个可以在游戏中测试一些纸牌战术的机器人,该机器人可以工作,但我有一个问题。我的抽卡方法不是很好。我这样摇牌:

        public void ShuffelDeck()
        {
            for (int i = 0; i < 5; i++)
                Cards = ShuffelCards(Cards);
        }

        private ArrayList ShuffelCards(ArrayList Cards)
        {
            ArrayList ShuffedCards = new ArrayList();

            Random SeedCreator = new Random();
            Random RandomNumberCreator = new Random(SeedCreator.Next());

            while (Cards.Count != 0)
            {
                int RandomNumber = RandomNumberCreator.Next(0, Cards.Count);
                ShuffedCards.Insert(ShuffedCards.Count, Cards[RandomNumber]);
                Cards.RemoveAt(RandomNumber);
            }

            return ShuffedCards; 
        }

问题是当我计算在摇牌过程之间没有停顿时,少数玩家会赢得很多游戏。例如

Player 1: 8 games
Player 2: 2 games
Player 3: 0 games
Player 4: 0 games

但是当我在摇牌过程之前添加一个对话框时,胜利将分散在玩家身上:

Player 1: 3 games
Player 2: 2 games
Player 3: 1 game
Player 4: 4 games

我猜 Random 类对于这样的蛮力来说还不够好。我怎样才能洗牌没有这样的问题?

更新:我已经尝试过使用 1 个随机类,并且我也尝试过只摇一次牌。

4

2 回答 2

10

当您创建Random类的新实例时,它会使用当前时间播种,但当前播种时间的精度仅为 16 毫秒,这意味着如果您Random在相同的 16 毫秒间隔内创建新类(这是很的时间对于计算机)作为另一个实例,您将获得相同的随机数序列。

一个好的解决方案是确保您不会创建这么多新的Randoms. 创建一个,一次,并将其传递给 shuffle cards 方法,或者创建一个在很多地方都可以访问的静态随机数(请记住它不是线程安全的)。

附带说明一下,对于您的实际洗牌算法来说,它非常好。不过,您可以进行一项改进。无需将所选元素添加到末尾并从中间删除,您只需将末尾的元素与中间的元素交换即可。这更有效,因为从 List 中间删除不是一个有效的操作。此外,不要在 0 和大小之间选择一个随机数,而是选择一个介于 0 和(大小减去当前迭代次数)之间的数字。有关该算法的更多详细信息,请参阅有关该主题的维基百科文章。

于 2012-07-25T18:45:47.973 回答
4

拥有 2 个随机类并为其中一个生成种子并不能提高随机性。

然后,不要在 ShuffelCards 中创建 Random 类。在 ShuffelDeck 中创建它并将其传递给 ShuffelCards,或使其成为该类的成员。这应该会有所帮助。

于 2012-07-25T18:46:08.533 回答