algorithm - 扑克游戏的商业级随机化

标签 algorithm random mapping poker

我需要一些关于如何解决算法问题的建议(即不是编程本身)。以下是我的需求以及我如何满足它们。欢迎提出任何改进意见。
首先让我解释一下我的目标。我想打10亿次扑克。也许我正在尝试创建下一个pokerstars.net,也许我只是疯了。
我想创建一个程序,可以产生更好的随机卡组,而不是说典型的程序调用random()。这些需要由高质量随机数创建的生产质量甲板。我听说商业级的扑克服务器对每一张牌都使用64位向量,这样就保证了每天数百万个扑克游戏的随机性。
我想把我写的东西保持简单。为此,程序应该只需要一个输入就可以实现指定的目标。我已经决定,每当程序开始时,它将记录当前时间并以此作为起点。我意识到这种方法在商业环境中是不可行的,但是只要它能支持几十亿个游戏,比更简单的选择,我会很高兴。
我开始编写伪代码来解决这个问题,但是遇到了一个棘手的问题。我很清楚,但可能不是你,所以请告诉我。
psuedo代码如下:

    Start by noting the system time.
    Hash the current time (with MD5) around ten times (I chose the ten arbitrarily).
    Take the resulting hash, and use it as the seed to the language-dependent random() function.
    Call random() 52 times and store the results.
    Take the values produced by random() and hash them.
    Any hash function that produces at least 64-bits of output will do for this.
    Truncate (if the hash is too big) so the hashes will fit inside a 64-bit double.
    Find a way to map the 52 doubles (which should be random now, according to my calculations) into 52 different cards, so we can play some poker.

我的问题是最后一步。我想不出一种方法来正确地将每个64位值映射到对应的卡,而不必担心两个数字相同(不太可能)或失去任何随机性(可能)。
我的第一个想法是将0x0000000000000000-0xffffffffffffffff分成四个偶数部分(代表诉讼)。但我们不能保证每一节都能找到13张卡片,这是不好的。
既然你知道我的处境,你将如何克服这个挑战?
--编辑--
实际上,从/dev/random读取字节会工作得很好。但这仍然让我迷失了如何转换?(假设我读的字节足够52张卡)。
我真正的愿望是采取一些简单和可预测的东西,如系统时间,并将其转换成随机牌组。将random()与系统时间一起播种是一种不好的方法。因此对时间进行哈希运算,并对random()中的值进行哈希运算。
该死,如果我想的话,我可以从/dev/random中散列字节,只是为了垃圾和傻笑。散列可以改善事物的随机性,不是吗?这难道不是现代密码管理器存储经过数千次哈希运算的密码的原因吗?
--编辑2--
所以我读了你们的答案,我发现自己被你们许多人暗示的结论搞糊涂了。我在第一次编辑时就暗示过,但这真的让我大吃一惊。我只想指出这一点并继续前进。
彩虹表存在,它做的数学和聪明魔术本质上充当一个查找表,常见的散列映射到特定的密码。据我所知,更长更好的密码不太可能出现在彩虹表中。但事实仍然是,尽管许多用户密码很常见,经过数千次哈希运算后,哈希密码仍然是安全的。
那么,在这种情况下,许多确定性操作增加了原始密码的随机性(或者看起来是这样?)我不是说我是对的,我只是说那是我的感觉。
我要指出的第二件事是我在做向后的事情。
我的意思是你们都建议我用一副分类的,可预测的,非随机的牌,然后用费舍尔·耶茨洗牌。我相信fisher-yates是一个很好的算法,但是不管什么原因你都不能使用它。
你能取一个随机的字节流吗,比如416字节(52张卡,每张卡8字节),bam生成一组已经随机的卡?字节是随机的,所以这样做应该不会太难。
大多数人会从一副52张(随机或不随机)的卡片开始,然后在一堆时间内交换它们(通过选择随机索引进行交换)。如果你能做到这一点,那么你可以取52个随机数,对它们进行一次遍历,然后生成随机组。
我可以简单地描述一下,
接受随机字节流并查看每个8字节块的算法。它将每个块映射到一张卡上。
例如0x123映射到黑桃的王牌
例如,0x456映射到钻石之王
例如,0x789映射到3个俱乐部
……等等。
只要我们为映射选择了一个好的模型,就可以了。不需要洗牌。程序将简化为两个步骤。
步骤1:从一个好的源获取足够数量的随机字节
步骤2:将这个字节流分成52个块,每个块对应一个卡组
步骤2a:运行52块,根据我们的地图将它们转换成卡片值。
这有道理吗?

最佳答案

你把问题复杂化了。您需要两个组件来解决问题:
洗牌算法
一个足够高质量的随机数生成器,供洗牌算法使用。
第一种方法很简单,只需使用Fisher-Yates shuffle算法。
第二,如果你想要sufficient degrees of freedom能够产生(52个)所有可能的排列!那么你至少需要226位熵。无论执行多少冗余散列,使用系统时钟不会给您带来超过32或64位的熵(实际上,由于大多数位都是可预测的,所以要少得多)。找到一个使用256位种子的rng,并将其种子化为256个随机位(这是一个引导问题,但是可以使用/dev/random或硬件rng设备)。

关于algorithm - 扑克游戏的商业级随机化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5345141/

相关文章:

java - Hibernate 一对一映射

Python - 升级我的迷宫求解器程序

c# - 将 CreateMap 和 Map 的实例版本与 WCF 服务一起使用?

java.sql.SQLSyntaxErrorException : Unknown column 'column_name' in 'field list' - mappings in entity are the same in as database

c - 如何生成不从 0 ( 50 - 100) 等开始的随机数?

excel - 如何生成一个随机范围的数字,这些数字总和为结束参数

c++ - 使用 C++ rand() 获取随机方向(上/下/左/右)——总是起床

c++ - 六边形网格算法

检查颜色相似性的算法

算法 : allocation of N railway stations in a M villages which are on a straight line