以比特存储扑克牌的更有效方式?

时间:2015-08-06 09:44:55

标签: python bit-shift playing-cards

我目前正在帮助教授计算机编程课程。 (我在高中三年级,为我的计算机程序设计老师学习。)现在学生们正在学习逐位运算符,但是一些更先进的运算符正在问我使用位和位运算将数据存储在位中。到目前为止,我们它们非常简单,但有效地给出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']

为此,我们可以使用Jack of Diamonds

步骤1.隔离套装并转换为bis。 'suit bits'等于二进制套装的索引号,因此Diamonds将为0b01或0b1

步骤2.将您的套装位向左移4位。 0b01 - > 0b010000

步骤3.隔离Rank并转换为位。 'rank bits'等于二进制数的索引,因此Jack(11)将为0b1011

步骤4.将等级位添加到套装位中。 0b010000 + 0b1011 = 0b011011

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

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

我想知道是否有更有效的方法来存储这些数据。我只是在计算机程序设计的第二年,而且我只接受过高中教育,所以我自己也不太了解。

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

3 个答案:

答案 0 :(得分:1)

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

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

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

通过对颜色下订单将1到52之间的任何数字映射到卡片很容易。

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

就尺寸而言,它相当于您使用的系统,我认为您不能用卡减少超过6位。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

有几种方法可以将其减少到每张卡 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')

不过,这个解决方案在排序中的位和每张卡片之间没有那么整齐的关系。如果库中没有通用的 Big Integer 支持,它可能不会那么容易地移植到语言中。