1

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

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

数字:

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

存储 1.57 亿个 32 位整数值大约需要 580MB。所以我想通过在数组中为不需要的值保留内存来避免增加这个数字。

所以问题是:散列函数看起来如何,将每个可能的、非重复的卡片组合映射到 0 到 156.742.040 之间的连续值,或者至少接近它?

4

2 回答 2

1

Paul Senzee 在这里有一篇很棒的帖子,有 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];
}

简而言之,它是一堆查找和按位运算,由基于完美散列的预先计算的查找表提供支持。

如果你回头看看这个网站,你可以得到 Senzee 用来创建 7 张牌哈希的完美哈希码,并为 5 张和 6 张牌表重复该过程(基本上index52c7.h为每张牌创建一个新的)。您也许可以将所有 3 个都粉碎到一张桌子上,但我还没有尝试过。

总而言之,应该是 ~628 MB(4 字节 * 157 M 条目)。或者,如果您想将其拆分,您可以将其映射到 16 位数字(因为我相信大多数扑克手牌评估者只需要 7,462 个独特的手牌分数),然后将这 7,462 个手牌分数单独映射到您的任何手牌类别想。那将是 314 MB。

于 2016-01-21T11:59:01.137 回答
0

这是基于 colex 函数概念的不同答案。它适用于按降序排序的位集。这是一个 Python 实现(都是递归的,因此您可以看到逻辑和迭代)。主要概念是,给定一个位集,您始终可以计算有多少位集具有相同数量的集位,但少于(在字典或数学意义上)给定位集。我从这篇关于手部同构的论文中得到了这个想法。

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)
于 2016-02-26T21:55:29.107 回答