扑克牌有52张牌,因此52!或大致2^226可能的排列.
现在我想要完美地洗牌这样一副牌,真正随机的结果和均匀的分布,这样你就可以达到每一个可能的排列,每个都可能出现.
为什么这实际上是必要的?
或许,对于游戏来说,你并不需要完美的随机性,除非有钱可以获胜.除此之外,人类可能甚至不会察觉到随机性的"差异".
但是如果我没有弄错的话,如果你使用通常内置于流行编程语言中的混洗函数和RNG组件,你通常会获得不超过32位的熵和2^32状态.因此,52!当你洗牌时,你永远无法达到牌组的所有可能的排列,但只有......
0.000000000000000000000000000000000000000000000000000000005324900157%
...可能的排列.这意味着一大堆的所有可能的游戏可以在理论上可以播放或模拟永远不会真正在实践中可以看出.
顺便说一句,你可以进一步提高的结果,如果你不每次都重新设置为默认顺序洗牌前,而是与订单开始从上一次洗牌或保持"烂摊子"游戏已经被播放后,并从那里洗牌.
要求:
因此,为了完成上述操作,我需要了解以下三个组件:据我所知:
解决方案:
现在这可以实现吗?我们有什么?
window.crypto.getRandomValues我们可以生成所需的226位熵作为我们的种子.如果仍然不够,我们可以从其他来源添加更多的熵.题:
上述解决方案(以及要求)是否正确?那么如何在实践中使用JavaScript中的这些解决方案实现改组呢?如何将这三个组件组合成一个可行的解决方案?
我想我必须Math.random通过调用xorshift7 替换Fisher-Yates shuffle示例中的用法.但是RNG在[0, 1)浮点范围内输出一个值,而我需要[1, n]整数范围.缩放该范围时,我不想失去均匀分布.而且,我想要大约226位的随机性.如果我的RNG仅输出一个Number,那么随机性是否有效地降低到2 ^ 53(或2 ^ 64)位,因为输出没有更多的可能性?
为了生成RNG的种子,我想做这样的事情:
var randomBytes = generateRandomBytes(226);
function generateRandomBytes(n) {
var data = new Uint8Array(
Math.ceil(n / 8)
);
window.crypto.getRandomValues(data);
return data;
}
Run Code Online (Sandbox Code Playgroud)
它是否正确?我不知道如何randomBytes以任何方式将RNG作为种子传递给我,我不知道如何修改它以接受它.
多么随机crypto.randomBytes(20).toString('hex')?
这很简单,我需要知道的一切.