【问题标题】:Using random numbers to select a item in one list and move it to another list使用随机数选择一个列表中的项目并将其移动到另一个列表
【发布时间】:2013-01-23 19:43:37
【问题描述】:

我正在设计一款名为 Snap 的纸牌游戏(这里有一个显示规则的链接 http://boardgames.about.com/od/cardgames/a/snap.htm),在我的版本中,如果出现一对,玩家必须点击中间的那堆。我目前有 4 个类,一个用于卡片(这是一个名为 cardValue_ 的 int),一个用于玩家手牌,一个用于原始纸牌,一个用于中间的一堆卡片。所以 Deck、Pile 和 Hand 类中有一个卡片列表。我现在正在尝试为包含卡片列表的 Deck 类编写一个 shuffle 方法。它将随机选择一张卡片并将其移动到新列表,直到所有卡片都被挑选出来,然后将它们移回原始列表,从而进行简单的洗牌。到目前为止,我的方法看起来像这样......

public List<Deck> Shuffle(List<Card> cardDeck)
    {
        int index = 0;
        Random randomCard = new Random();
        List<Card> newDeck = new List<Card>();

        while (index < cardDeck.Count)
        {
            int ran = randomCard.Next(0, cardDeck.Count);
            foreach (Card card in cardDeck)
            {

            }
        }
    }

我正在尝试弄清楚 foreach 循环中应该做什么(除非整个方法是错误的),但现在我想我已经在错误的地方声明了我的所有卡片,所有 52 张卡片目前都在表单中声明,还是我应该在 Deck 类中声明它们?

【问题讨论】:

标签: c#


【解决方案1】:

您与我的解决方法非常接近,我要做的是随机复制源列表直到它为空,然后重新填充它。你不需要返回一个列表,因为这只会打乱你传入的列表。

//Move this out of the function, if you are wondering why search SO for "Not random" and choose any of the 100's of people asking "why is random not random?" :)
private static Random randomCard = new Random(); //Not thread safe, if multi-threading use locks!!!

public static void Shuffle(List<Card> cardDeck)
{
    int index = 0;
    List<Card> tempDeck = new List<Card>();

    while (cardDeck.Count > 0)
    {
        int removal = randomCard.Next(0, cardDeck.Count);
        Card tempCard = cardDeck[removal];
        cardDeck.RemoveAt(removal);
        tempDeck.Add(tempCard);
    }

    //cardDeck is empty at this point, now we refill it with our randomized deck.
    cardDeck.AddRange(tempDeck);
}

如果您不想修改原始列表并且确实想要一个新的随机列表,只需先复制源列表即可。

public static List<Card> Shuffle(List<Card> cardDeck)
{
    int index = 0;
    List<Card> tempDeck = new List<Card>();
    List<Card> localCopy = new List<Card>(cardDeck);   //Creates a shallow copy of the list.      

    while (localCopy.Count > 0)
    {
        int removal = randomCard.Next(0, cardDeck.Count);
        Card tempCard = localCopy[removal];
        localCopy.RemoveAt(removal);
        tempDeck.Add(tempCard);
    }

    return tempDeck;
}

我建议使用Richard's method。它更简单。

【讨论】:

  • 这种洗牌是可以预测的。阅读codinghorror.com/blog/2007/12/shuffling.html
  • @RichardSchneider 嗯,感谢您的阅读。我没有想到通过诡计的顺序。将其发布为答案,我会投赞成票。
  • @RichardSchneider 但是,我会说调用NewGuid() 与调用Next(x,y) 一样可预测。如果你真的想“正确”地做,你需要打开System.Security.Cryptography
  • 嗯,在你的两个例子中都是出于某种原因。它在哪里说卡 tempCard...;我收到错误“无法将类型 'void' 隐式转换为 'Snap_Card_Game.Card”(Snap Card Game 是解决方案的名称)
  • 很抱歉用一个琐碎的问题打扰您,因为这个方法在一个类中,这是否意味着它会在我创建一个deckList 时自动执行,还是我仍然需要在某个地方调用该方法?这是我第一次使用多个类。
【解决方案2】:

阅读 Jeff 的blog on shuffling 了解所有详细信息。

public List<Card> Shuffle(List<Card> cards)
{
  return new List<Card>(cards)
   .OrderBy(a => Guid.NewGuid());
}

更新

Scott 建议 Guid 可能不够随机,而 Crypto RNG 会更好。所以使用 BigInteger 因为它实现了 IComparable 我们得到:

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

public List<Card> Shuffle(List<Card> cards)
{
  var r = new byte[32];
  return new List<Card>(cards)
   .OrderBy(a => new BigInteger(rng.GetBytes(r));
}

【讨论】:

  • 在你真正想要随机性的地方使用唯一性是错误的——不同的用例
猜你喜欢
  • 2021-08-25
  • 1970-01-01
  • 2014-06-25
  • 1970-01-01
  • 2018-05-01
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 2018-11-28
相关资源
最近更新 更多