我正在进行扑克模拟,现在我必须有效地排名:
每手牌都是5张牌的组合,代表uint64_t
从0(黑桃王牌),1(心中的王牌)到51(两个俱乐部)的每一位表示相应的牌是否是手的一部分(比特== 1)或不是部分(比特== 0) 。从52到63的位始终设置为零,并且不保存任何信息。
我已经知道理论上我是如何生成一个表的,因此每个有效的手都可以映射到1(2,3,4,5,7之间 - 不在同一个范围内的范围(表示为uint16_t
)颜色)和7462(皇家同花顺)和所有其他的铃声零。
因此,一个天真的查找表(使用卡的整数值作为索引)将具有巨大大小
2 bytes * 2^52 >= 9.007 PB
。
大部分内存都会被零填充,因为从0到2 ^ 52-1的几乎所有uint64_t
都是无效的手,因此有一个等于零的范围。
有价值的数据只占用
2 bytes * 52!/(47!*5!) = 5.198 MB
。
我可以使用什么方法进行映射,这样我只需要保存有效卡中的等级和一些开销(最多100 MB),但仍然不需要进行一些昂贵的搜索...... 它应该尽可能快!
如果您有任何其他想法,欢迎您! ;)
答案 0 :(得分:3)
您只需要一张13 ^ 5 * 2的表格,其中包含额外的信息,指示所有卡牌是否属于同一套牌。如果出于某种原因“心脏”超过“钻石”,你最多还需要一张尺寸为13 ^ 6的桌子,因为最后一条信息编码为'0 =无图案,1 =所有黑桃,2 =所有心,等。
哈希表可能也是一种好的快速方法 - 从nCk(52,5)组合创建表并不需要花费太多时间(与所有可能的手相比)。但是,人们需要为每个条目存储65位信息,以存储密钥(52位)和秩(13位)。
加快对手的评价,先从面具中排除非法组合:
if (popcount(mask) != 5)
;之后一次可以使用足够的比特来自例如crc32(mask),至少在i7架构中具有指令级支持。
答案 1 :(得分:1)
如果我正确理解你的方案,你只需要知道特定手的海明重量正好是5,因为它是一个有效的手。有关如何计算汉明重量的信息,请参阅Calculating Hamming Weight in O(1)。
从那里开始,你似乎可以自己解决剩下的问题。就个人而言,我想将结果存储在一些持久性内存中(如果它在您选择的平台上可用),以便后续运行更快,因为它们不需要生成索引表。
答案 2 :(得分:0)
我想到的一个简单实现是将您的方案更改为基数52中的5位数。用于保存所有这些值的结果表仍然会比必要的大,但实现起来非常简单,它会很容易适应现代计算机上的RAM。
编辑:您还可以通过仅存储每张卡的等级和另外的标记(例如,最低位)来指定更多,以指定所有卡是否具有相同的套装(即,可以刷新)。然后,这将在基数13 +一位用于排名表示。那么你可能需要分别存储卡片的特定套装,以重建精确的显示手等。
答案 3 :(得分:0)
我会以不同的方式代表你的手: 只有4个套装= 2比特,只有13个卡= 4比特,总共6比特* 5 = 30 - 所以我们适合32比特的int - 我们也可以强迫这个按照你的订单排序
[suit 0] [suit 1] [suit 2] [suit 3] [suit 4] [value 0] [value 1] [value 2] [value 3] [value 4]
然后我会使用单独的哈希:
然后使用3个哈希来计算你的排名 在5MB时,您可能会有足够的缓存问题,这将使数学和三个小查找更快
答案 4 :(得分:0)
这是一个很好的来源 Cactus Kev's
对于一只手,你可以利用最多4件西装
等级(0-12)为4位,套装为2位
6位* 5张卡只有30位
称之为4个字节
只有2598960手
总尺寸略小于10 mb