用于映射5到7张卡片组合的散列函数

时间:2014-03-18 10:53:24

标签: hash-function

参考原始问题:Optimizing hand-evaluation algorithm for Poker-Monte-Carlo-Simulation

我有一个5到7张卡的列表,并希望将它们的值存储在哈希表中,哈希表应该是32位整数的数组,并且可以通过hashfunctions值作为索引直接访问。 关于52张牌中的大量可能组合,我不想浪费太多记忆。

编号:

  • 7张牌组合:133784560
  • 6张牌组合:20358520
  • 5张牌组合:2598960
  • 总计:156.742.040可能的组合

存储1.57亿32位整数值的成本约为580MB。因此,我希望通过在数组中为不需要的值保留内存来避免增加此数字。

所以问题是:哈希函数怎么样,将每个可能的,非重复的卡组合映射到0到156.742.040之间的连续值,或者至少接近它?

2 个答案:

答案 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)