洗牌的随机性

时间:2017-04-29 04:57:53

标签: java arraylist random playing-cards

我有一张包含52张牌的阵列列表。我想洗牌。

这就是我所做的。

  1. 创建了一个新的阵列列表。
  2. 生成0到甲板大小之间的随机索引。
  3. 随机索取卡片并添加到新列表中。
  4. 从卡座中取出卡
  5. 重复直到甲板为空。
  6. 这是我的代码:

    String[] Number = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
    String[] Suits = {"Club","Diamonds","Hearts","Spades"};
    ArrayList<Card> deck = new ArrayList<Card>();
    
    // create a deck    
    
    for(int i=0;i<13;i++){
            for(int j=0;j<4;j++){
                Card card = new Card(Suits[j],Number[i]);
                deck.add(card);
            }    
        }
    
    // shuffle of deck
    
    ArrayList<Card> new_deck = new ArrayList<Card>();
        while(deck.size()!=0){   
    
            Random rand = new Random();
            int  n = rand.nextInt(deck.size());
    
            new_deck.add(deck.get(n));
            deck.remove(n);
        }
    
    // Display
    
    for(int i=0;i<52;i++){
            System.out.println(new_deck.get(i).getSuit()+" : "+new_deck.get(i).getValue());
        }
    

    最后,我从新的ArrayList获得了混乱的套牌。

    它的随机性是否足够好?

    我应该怎么做才能增加随机性?

4 个答案:

答案 0 :(得分:4)

  

它的随机性是否足够?

定义足够好(!!)

您当前的方法将提供一个良好的洗牌,没有明显的偏见... 除了可能由随机数生成器引入的偏差。

在这种情况下,确实值得关注。 Random被指定为线性同余生成器,并且LC生成在它们生成的数量中具有不同的模式。 (在统计学上,它们表现出强烈的自相关性。)如果你将第n个随机数与n进行比较,这一点非常清楚。

要提高随机性,您应该使用更好的随机数生成器。 SecureRandom生成器应该足够好:javadoc

如果使用Collections.shuffle方法,则会对随机性产生同样的担忧。对于良好(或一致)shuffle,您应该在提供Random实现的情况下使用方法重载...并选择一个好的。

答案 1 :(得分:3)

我建议您只需使用Collections.shuffle(),如下所示,而不是重新发明已由Collections API提供的改组逻辑:

Collections.shuffle(deck);//Pass your ArrayList<Card> object i.e., deck

因此,通过重用现有的Collections API,您可以清除对deck对象随机性的所有怀疑。

答案 2 :(得分:1)

你应该定义你的概念&#34;随机性&#34;以一种精确的方式。 &#34;增加随机性&#34;是一个相当模糊的术语。

我将假设&#34;随机&#34;,你想要的是你牌上的uniform distribution permutation。也就是说,你希望你的牌组重新排序,使得下一张牌是特定牌的机会相等。

这里有两个不同的因素:

  • 你如何洗牌
  • 随机生成器Random有多好

你如何改组

就你如何洗牌而言,它是统一的。 conditional probability可以证明任何位置的任何卡都是1/52。

util.Random有多好

首先,要清楚,util.Random 实际上是随机的。这是pseudorandom number generator(PRNG)。这意味着他们所做的不是产生真正随机的数字。相反,他们尝试,并且根据应用要求,它就足够了。

util.Randomlinear congruential generator,就PRNG来说,它非常弱。如果你不关心真的随机化你的套牌,它会正常工作。但是,如果您需要更强大的功能,here是一个起点。

答案 3 :(得分:0)

这里没有提到一个关于java.util.Random的问题:它是否可以生成52项列表的所有排列。这是基于它的时期。通常,伪随机数发生器(PRNG)不能产生比其周期更多的随机数序列的排列(参见&#34; Shuffling&#34;在我的article on randomness中进行进一步讨论)。

java.util.Random的周期不高于2 48 ,因为它使用48位种子长度。但是,52个项目列表有52个因子排列,并且高于2个 225 - 超过java.util.Random个周期的许多订单数量级。因此,java.util.Random无法生成52个项目列表的许多很多排列(使用相同的混洗技术)。 (这适用于任何 PRNG,其周期小于52因子,而不仅仅是线性同余生成器,尤其是java.util.Random。)因此,需要对52-进行洗牌的应用程序项目清单建议使用一个生成器,用于生成成本过高而无法预测的随机数(例如Java SecureRandom)或使用周期为52-factorial或更高的PRNG(尽管高的时期本身可能不足以确保PRNG能够产生该列表的所有排列。)

编辑:最近的两个问题讨论了如何产生足够的随机性来改组数字&#34;套牌&#34; 52卡:

Is java.util.Random really that random? How can I generate 52! (factorial) possible sequences?

Where can I get a reliable source of entropy (real randomness byte[])?

解决方案的要点是,您需要找到一种生成226位或更多 entropy (随机性)的方法,并使用它来帮助生成随机排列。有关详细信息,请参阅相关问题,另请参阅我在nondeterministic sources and seed generation上的部分。