参考原始问题:Optimizing hand-evaluation algorithm for Poker-Monte-Carlo-Simulation
我有一个5到7张卡的列表,并希望将它们的值存储在哈希表中,哈希表应该是32位整数的数组,并且可以通过hashfunctions值作为索引直接访问。 关于52张牌中的大量可能组合,我不想浪费太多记忆。
编号:
存储1.57亿32位整数值的成本约为580MB。因此,我希望通过在数组中为不需要的值保留内存来避免增加此数字。
所以问题是:哈希函数怎么样,将每个可能的,非重复的卡组合映射到0到156.742.040之间的连续值,或者至少接近它?
答案 0 :(得分:1)
Paul Senzee在here上发了7张牌的好帖子。
他的代码基本上是一堆预先计算的表,然后是一个函数来查找给定7张牌的数组索引(表示为64位数字,最低52位表示牌):
inline unsigned index52c7(unsigned __int64 x)
{
const unsigned short *a = (const unsigned short *)&x;
unsigned A = a[3], B = a[2], C = a[1], D = a[0],
bcA = _bitcount[A], bcB = _bitcount[B], bcC = _bitcount[C], bcD = _bitcount[D],
mulA = _choose48x[7 - bcA], mulB = _choose32x[7 - (bcA + bcB)], mulC = _choose16x[bcD];
return _offsets52c[bcA] + _table4[A] * mulA +
_offsets48c[ (bcA << 4) + bcB] + _table [B] * mulB +
_offsets32c[((bcA + bcB) << 4) + bcC] + _table [C] * mulC +
_table [D];
}
简而言之,它是一组基于完美散列的预先计算的查找表驱动的查找和按位运算。
如果您回过头来查看this website,您可以获得Senzee用于创建7卡哈希的完美哈希码,并重复5和6卡表的过程(基本上创建一个新的每个index52c7.h
。你可以将所有3个粉碎成一张桌子,但我还没试过。
所有人都说应该是~628 MB(4字节* 157 M条目)。或者,如果你想将它拆分,你可以将它映射到16位数字(因为我相信大多数扑克手评估者只需要7,462个独特的手牌得分),然后从7,462手牌得分到任何手牌类别的单独地图你想。那将是314 MB。
答案 1 :(得分:0)
这是基于colex功能概念的不同答案。它适用于按降序排序的位集。这是一个Python实现(都是递归的,所以你可以看到逻辑和迭代)。主要概念是,给定一个bitset,你总是可以计算出具有相同数量的设置位但有多少(在字典或数学意义上)你的给定位集的位集。我从this paper on hand isomorphisms得到了这个想法。
from math import factorial
def n_choose_k(n, k):
return 0 if n < k else factorial(n) // (factorial(k) * factorial(n - k))
def indexset_recursive(bitset, lowest_bit=0):
"""Return number of bitsets with same number of set bits but less than
given bitset.
Args:
bitset (sequence) - Sequence of set bits in descending order.
lowest_bit (int) - Name of the lowest bit. Default = 0.
>>> indexset_recursive([51, 50, 49, 48, 47, 46, 45])
133784559
>>> indexset_recursive([52, 51, 50, 49, 48, 47, 46], lowest_bit=1)
133784559
>>> indexset_recursive([6, 5, 4, 3, 2, 1, 0])
0
>>> indexset_recursive([7, 6, 5, 4, 3, 2, 1], lowest_bit=1)
0
"""
m = len(bitset)
first = bitset[0] - lowest_bit
if m == 1:
return first
else:
t = n_choose_k(first, m)
return t + indexset_recursive(bitset[1:], lowest_bit)
def indexset(bitset, lowest_bit=0):
"""Return number of bitsets with same number of set bits but less than
given bitset.
Args:
bitset (sequence) - Sequence of set bits in descending order.
lowest_bit (int) - Name of the lowest bit. Default = 0.
>>> indexset([51, 50, 49, 48, 47, 46, 45])
133784559
>>> indexset([52, 51, 50, 49, 48, 47, 46], lowest_bit=1)
133784559
>>> indexset([6, 5, 4, 3, 2, 1, 0])
0
>>> indexset([7, 6, 5, 4, 3, 2, 1], lowest_bit=1)
0
"""
m = len(bitset)
g = enumerate(bitset)
return sum(n_choose_k(bit - lowest_bit, m - i) for i, bit in g)