【问题标题】:More efficient way to store Playing Cards in bits?以位存储扑克牌的更有效方法?
【发布时间】:2015-08-06 09:44:54
【问题描述】:

我目前正在帮助教授计算机编程课程。 (我在高中四年级,为我的计算机编程老师做助教。)现在学生们正在学习按位运算符,但一些更高级的学生正在询问我如何使用位和按位运算来将数据存储在位中。到目前为止,我们他们非常简单,但有效地提供了 50%(给或取 5%)的压缩率。我们拿我们的扑克牌,比如说一张方块八,然后把它变成一个 7 位的值 0b1011000。这适用于所有通用扑克牌 Ace - King 和所有花色,您只需将位(或整数)放入函数中,您就会得到一张扑克牌。

这是他们迄今为止的想法。

0b1 SS VVVV

0b1 使所有“扑克牌转位”的长度保持一致。

SS 是花色值

VVVV是卡值

这是他们如何形成自己的比特

suits = ['Hearts','Diamonds','Spades','Clubs']
ranks = ['Ace','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten','Jack','Queen','King']

为此,让我们使用钻石杰克

步骤 1. 隔离西装并转换为 bis。 “花色位”等于花色的二进制索引号,因此钻石将是 0b01 或 0b1

第 2 步。将西装位左移 4 位。 0b01 -> 0b010000

步骤 3. 隔离秩并转换为位。 “等级位”等于二进制花色编号的索引,因此 Jack (11) 将是 0b1011

第 4 步。将您的等级位添加到您的套装位中。 0b010000 + 0b1011 = 0b011011

第 5 步。将组合的 rank\suit 位添加到 0b10000000 以在所有值中提供一致的长度。 0b011011 + 0b1000000 = 0b1011011

在一副完整的纸牌中(所有 52 张牌都没有小丑),牌名中有 741 个字符。 一副转换为位的卡片以 364 位存储,压缩率为 49%,同时仍保留 100% 的数据。

我想知道是否有更有效的方法来存储这些数据。我只是计算机编程的第二年,而且我只有高中水平的教育,所以我自己对此不太了解。

这是他们的代码http://repl.it/BA56

【问题讨论】:

    标签: python bit-shift playing-cards


    【解决方案1】:

    另一种方法是给每张卡一个从 1 到 52 的数字

    定义颜色顺序可能会很有趣,例如在 Belote 纸牌游戏中定义的顺序。

    所以: 0 = 1 个俱乐部 1 = 2 个俱乐部 ... 12 = 俱乐部之王 13 = 1 颗钻石 ... 等等。

    通过颜色顺序可以轻松地将 1 到 52 之间的任何数字映射到卡片。

    最后你只需要从 1 到 52 的数字来代表整个纸牌游戏。那是从 '000000' 到 '110001' 的数字,只有 6 位卡。

    大小和你使用的系统相当,我认为你不能通过卡减少超过6bit。

    【讨论】:

      【解决方案2】:

      如果您订购卡片 2c,2d,2h,2s,3c,3d,3h,3s...Ac,Ad,Ah,As,那么您可以将它们简单地视为从 0 到 51 的整数,并且视为位-fields,因为花色变成了两个低位。这也使按排名进行比较更快,因为您不必分开排名来比较它们(即,“排名> 10”只是变成“卡片> 35”)。它还使使用查找表中的数字变得简单。我发现这是最有效的通用表示,也是我在模拟库中使用的表示。

      【讨论】:

        【解决方案3】:

        有几种方法可以将其进一步减少到每张卡 6 位以上。首先,使用提到的其他答案的系统枚举您的卡片,例如:

        import itertools
        
        suits = ['Hearts','Diamonds','Spades','Clubs']
        ranks = ['Ace','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten','Jack','Queen','King']
        cards = list(itertools.product(ranks, suits))
        

        任何卡片现在都可以表示为卡片列表中的索引,这需要足够的位来存储 0 到 len(cards) 范围内的值,可计算如下:

        from math import ceil, log2
        
        def bits_for_index(sequence):
            return ceil(log2(len(sequence)))
        

        所以,bits_for_index(cards) 返回 6。

        但是您可以观察到,对于牌组的排序,在您选择了每张牌之后,下一张牌的可能性就会减少(例如,没有洗牌会包含两次红桃 A)。如果您通过从您的排序中选择一张卡片,从您的卡片列表中删除该卡片,然后从剩余卡片中选择下一张来生成洗牌,bits_for_index(cards) 的值最终将从 6 下降到 5,然后是 4、3 、2 和 1。

        此技术所需的总位数由 sum(map(ceil, map(log2, range(52, 1, -1)))) 计算,最终为 249。您可以使用以下内容打印 shuffle 及其二进制表示:

        from random import randrange
        
        def ordering(sequence):
            sequence = sequence[:]
            value = 0
            while sequence:
                index = randrange(len(sequence))
                print(sequence.pop(index))
                if sequence:
                    value += index
                    value <<= bits_for_index(sequence)
            return value
        
        ordering_compressed = ordering(cards)
        binary_representation = '{:0249b}'.format(ordering_compressed)
        print('Compressed to', len(binary_representation), 'bits:', binary_representation)
        

        要提取排序,您需要反转过程,屏蔽和移位一位,然后是两位,然后是两位,然后是三位,依此类推,直到您在总卡片列表中获得索引列表:

        def extract_ordering(value, sequence):
            indexes = [0]
            while value:
                indexes.append(0)
                bits = bits_for_index(indexes)
                indexes[-1] = value & ((1 << bits) - 1)
                value >>= bits
            padded = [0] * (len(sequence) - len(indexes))
            indexes.extend(padded)
            sequence = sequence[:]
            for idx in reversed(indexes):
                print(sequence.pop(idx))
        

        此外,您可以通过枚举所有可能的顺序并选择一个来进一步压缩一副纸牌,这需要 ceil(log2(factorial(len(cards)))) 或 226 位:

        def ordering(sequence):
            return randrange(factorial(len(sequence)))
        
        def extract_ordering(value, sequence):
            indexes = []
            digit = 1
            while value:
                indexes.append(value % digit)
                value //= digit
                digit += 1
            sequence = sequence[:]
            while indexes:
                print(sequence.pop(indexes.pop()))
            if sequence:
                print(*sequence, sep='\n')
        

        不过,此解决方案在排序中的位与每张卡片之间的关系并不十分清晰。而且它可能不会那么容易地移植到它们的库中没有通用大整数支持的语言。

        【讨论】:

          猜你喜欢
          • 2017-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-09
          相关资源
          最近更新 更多