【问题标题】:Hashfunction to map combinations of 5 to 7 cards哈希函数映射 5 到 7 张卡片的组合
【发布时间】:2014-03-18 10:53:24
【问题描述】:

参考原问题: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 之间的连续值,或者至少接近它?

【问题讨论】:

  • 呃,也许是一张代表卡片的位图?
  • 每张牌都有一个代表它的 ID:方块中的两个 = 0,梅花中的王牌 = 51。现在我想为 5 到 7 的所有非重复可能组合设置一个唯一值将其映射到数组的卡片。
  • 嗯:两个方块 = 1<<0 和梅花 A 是 1<<51 并将它们相加。瞧:一个位掩码。 (如果少于 52 张卡,您可能会发明更紧凑的代码)
  • 计算机国际象棋已经存在了五十多年。重新发明轮子很难
  • 嗯,连续的订单让这成为一个问题。 hash function 不授予连续订单。您想要的正确数学术语是map function。我对你想要什么有一个想法,让我看看我今天或明天能不能找到一些时间来充实它。

标签: hash-function


【解决方案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 张牌表重复该过程(本质上是创建一个新的@987654324 @每个)。您也许可以将所有 3 个都粉碎到一张桌子上,但我还没有尝试过。

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

【讨论】:

  • 是的,这就是我需要的。谢谢!
【解决方案2】:

这是基于 colex 函数概念的不同答案。它适用于按降序排序的位集。这是一个 Python 实现(都是递归的,因此您可以看到逻辑和迭代)。主要概念是,给定一个位集,您始终可以计算有多少位集具有相同数量的集位,但少于(在字典或数学意义上)给定位集。我是从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)

【讨论】:

    猜你喜欢
    • 2012-08-05
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多