当我需要在Java / Android中洗牌时,我当然使用Collections.shuffle(List<?> list)
。我一直这样做,结果似乎可以接受。但他们不是。
如this paper所述,有52个! 52张牌扑克牌可能独一无二的洗牌。这相当于大约2 ^ 226。
但Collections.shuffle(List<?> list)
默认情况下使用new Random()
使用48-bit seed,因此只能创建2 ^ 48个唯一的随机播放 - 这只是所有可能的随机播放的3.49*10^(-52)
%!
那么如何以正确的方式洗牌?
我已经开始使用SecureRandom
,但这还够吗?
List<Card> cards = new ArrayList<Card>();
...
SecureRandom secureRandom;
try {
secureRandom = SecureRandom.getInstance("SHA1PRNG");
}
catch (NoSuchAlgorithmException e) {
secureRandom = new SecureRandom();
}
secureRandom.nextBytes(new byte[20]); // force SecureRandom to seed itself
Collections.shuffle(cards, secureRandom);
答案 0 :(得分:4)
你可能只能从特定的首发安排得到2 48 不同的牌,但并不要求你每次都以相同的安排开始。
据推测,在牌组完成后(扑克牌,二十一点等),它将处于不确定的顺序,任何一个重新排列都将是合适的。
而且,如果您担心每次启动程序时都从固定安排开始,只需在退出时保留订单并在下次重新加载。
在任何情况下,2 48 仍然有很多可能性(大约280,000,000,000,000),对于纸牌游戏来说已经足够了,当你意识到这是限制洗牌而不是安排。除非你是一位认真的统计学家或密码学家,否则你应该没事。
答案 1 :(得分:2)
虽然您使用的是SecureRandom
,但状态仍然有限。只要输入种子的范围小于52!它不能完全随机。
事实上,SHA1PRNG
is 160 bit seeded,这意味着它仍然不够随机。关注this link,它在几年前通过使用名为UnCommons Math
的第三方库找到了解决方案。
答案 2 :(得分:1)
如果你想要真正的随机性,你可以跳过伪随机生成器并寻找更好的东西,比如从大气噪声产生的随机数。
random.org提供了一个API来将以这种方式生成的随机数整合到您自己的软件中。
答案 3 :(得分:0)
从你链接的文章中窃取答案:
START WITH FRESH DECK
GET RANDOM SEED
FOR CT = 1, WHILE CT <= 52, DO
X = RANDOM NUMBER BETWEEN CT AND 52 INCLUSIVE
SWAP DECK[CT] WITH DECK[X]
随机数生成器应该是好的并且使用你不可预测地选择的64位种子,最好是使用硬件。
答案 4 :(得分:0)
如何真的洗牌?
(剥离/上手):
Cut the deck in two
Add a small (pseudorandom) amount of one half to the front of the front of the other
Add a small (pseudorandom) amount of one half to the front of the back of the other
Do this until one hand is empty
Repeat
或(Riffle):
Cut the deck in two
Set down a small (pseudorandom) portion of one half
Set down a small (pseudorandom) portion of the other
Do this until both hands are empty, and you have a new deck
Repeat
此外,还有更多内容,详见上面的链接。
无论如何,有很多组合甚至完美的改组算法都会让机器每秒探索2*10^50
个唯一的排列,以便在宇宙存在的时候完成每个排列的探索。现在计算机预计到2019年将达到1次ExaFLOP(每秒1*10^18
次浮点运算)。
没有人类洗牌器会探索这种可能性,而你是,我相信(在最基本的层面上)模拟人类洗牌,对吗?你是否会发现一个赌场管理员可能会在一次洗牌中将增量排序的牌组改组为递减顺序?要在奇数之前用偶数等级拆分牌组,在一次洗牌中?
我不觉得将自己局限于每个洗牌中相位空间(2^48
可能的随机数)的一个(虽然极其)小的部分是不可接受的,只要你不连续播种它方式等。
在52张卡片组中,正好有52个因子(用简写表示为52!)卡的可能排序。这大约是8×10 67 可能的排序或具体为:
80,658,175,170,943,878,571,660,636,856,403,766,975,289,505,440,883,277,824,000,000,000,000
这个数字的大小意味着,即使在宇宙的历史中,两个随机选择的,真正随机化的甲板也将是相同的。然而,尽管所有的确切序列都是如此。随机牌组中的牌是不可预测的,有可能对未充分随机化的牌组进行一些概率预测。
〜Wikipedia
另外,值得注意的是拜耳&amp; Diaconis在1992年证明只需要7次好的随机播放就可以正确地随机化一个套牌,here是维基百科上的一个部分,它与论文有很多联系。