我正在制作一个机器人,可以在游戏中测试一些卡片策略,机器人可以工作,但我有一个问题。我的卡摇法不是很好。 我这样摇动卡片:
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
我猜这个随机类对于像这样的蛮力来说还不够好。如何在没有这样的问题的情况下洗牌?
更新: 我已经尝试过使用1个随机课程,而且我也试过只摇一次卡片。
答案 0 :(得分:10)
当您创建Random
类的新实例时,它将以当前时间播种,但其播种的当前时间仅为16毫秒,这意味着如果您创建新的{{1}在相同的16毫秒间隔内(类似于计算机的长时间)的类,作为另一个实例,您将获得相同的随机数序列。
一个好的解决方案是确保您没有创建这么多新的Random
。创建一个,一次,并将其传递到shuffle卡方法,或创建一个只能在很多地方访问的静态随机(只记得它不是线程安全的)。
另一方面,对于你的实际改组算法,它非常好。你可以做一个改进。您可以将末尾的元素与中间的元素交换,而不是将所选元素添加到末尾并从中间删除它。这样更有效,因为从List中间删除不是一种有效的操作。此外,不是选择介于0和大小之间的随机数,而是选择介于0和(大小减去当前迭代次数)之间的数字。有关算法的详细信息,请参阅wikipedia article on the subject。
答案 1 :(得分:4)
拥有2个随机类并为另一个生成种子并不会改善随机性。
然后,不要在ShuffelCards中创建Random类。在ShuffelDeck中创建它并将其传递给ShuffelCards,或使其成为该类的成员。这应该有所帮助。