所有可能的牌/扑克牌组合,适用于一组玩家

时间:2014-03-12 16:39:18

标签: python combinations permutation poker playing-cards

我正在寻找一个优雅(快速)的python函数,它可以生成以下两个数组的每个组合。

cards = ["8H", "8S", "8C", "8D", "9H", "9S", "9C", "9D", "10H", "10S", "10C", "10D", "AH", "AS", "AC", "AD"]
players = ["_1", "_1", "_1", "_2", "_2", "_2", "_3", "_3", "_3", "_4", "_4", "_4", "_To", "_To", "_To", "_Tc"]

组合看起来像:

[('8H', '_1'), ('8S', '_1'), ('8C', '_1'), ('8D', '_2'), ('9H', '_2'), ('9S', '_2'), ('9C', '_3'), ('9D', '_3'), ('10H', '_3'), ('10S', '_4'), ('10C', '_4'), ('10D', '_4'), ('AH', '_To'), ('AS', '_To'), ('AC', '_To'), ('AD', '_Tc')]

但是!没有平等,我的意思是什么。 例如:

如果卡片是:

["a", "b", "c", "d"]

如果玩家是:

["1", "1", "2", "2"]

结果:

[1a, 1b, 2c, 2d]
[1a, 1c, 2b, 2d]
[1a, 1d, 2b, 2c]
[1b, 1c, 2a, 2d]
[1b, 1d, 2a, 2c]
[1c, 1d, 2a, 2b]

不是例如:

[1a, 1b, 2d, 2c]

具有(c和d)的玩家2等于(d和c)

我尝试了itertools的功能,例如combinationspermutations,但没有运气。由于状态空间爆炸,在所有组合之后拒绝等于并不是真正的选择。

我希望有人有解决方案,因为Google搜索此特定问题失败了。

3 个答案:

答案 0 :(得分:3)

我建议使用递归算法。

我正在使用生成器来使代码在恒定空间中运行,并且尽快开始生成结果,而不是最后的巨大结果;如果您之前没有听说过发电机,请参见http://www.dabeaz.com/generators/

作为旁注,我建议使用标准化数据结构来保存您的玩家列表和手牌大小,以便根本不需要groupby的行...在任何情况下,默认/大部分时间保持数据规范化通常是一个好主意,并且只使用非规范化/扁平化形式,例如对于某些可能需要或运行速度更快的平面结构算法。

这是代码;随意提出清理/简化:

from itertools import combinations, groupby, islice

cards = ["a", "b", "c", "d"]
players = ["1", "1", "2", "2"]

def hand_combinations(players, cards):
    # convert ["1", "1", "2", "2"] into [("1", 2), ("2", 2)]
    players = list((x, len(list(y))) for x, y in groupby(players))

    # sets are faster to operate on in our case
    cards = set(cards)

    def generate(players, cards):
        if not players:
            yield []
        else:
            # pick the first player
            player_name, player_hand_size = players[0]
            # and then walk over all the possible hands for this player
            for player_hand in combinations(cards, player_hand_size):
                # for each hand, use the cards that are left to build all the
                # possible hands for the rest of the players in this iteration
                for tail in generate(players[1:], cards - set(player_hand)):
                    yield [(player_name, player_hand)] + tail

    return generate(players, cards)

# take only the 100 first combinations; otherwise it'll take
# forever with the larger example
combos = islice(hand_combinations(players, cards), 0, 100)

# convert back to the flat structure
flattened = [
    ' '.join(
        player_name + ':' + card
        for player_name, player_cards in combo
        for card in player_cards
    )
    for combo in combos
]

from pprint import pprint
pprint(flattened)

<强>输出:

['1:a 1:c 2:b 2:d',
 '1:a 1:b 2:c 2:d',
 '1:a 1:d 2:c 2:b',
 '1:c 1:b 2:a 2:d',
 '1:c 1:d 2:a 2:b',
 '1:b 1:d 2:a 2:c']

或与更大的考官一起:

['_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:10D _Tc:8S',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:8S _Tc:10D',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:10D _To:8S _Tc:9S',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:9S _To:10D _To:8S _Tc:AH',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8D _Tc:8S',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8S _Tc:8D',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:8D _To:8S _Tc:9S',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:9S _To:8D _To:8S _Tc:AH',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:10D _Tc:8D',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:8D _Tc:10D',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:10D _To:8D _Tc:9S',
 '_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:9S _To:10D _To:8D _Tc:8S',
...

答案 1 :(得分:1)

好的,你真正想要的是:

set(tuple(zip(p, players)) for p in it.permutations(cards))

但这需要花费太多时间。所以,试试吧。

cards = set(["8H", "8S", "8C", "8D", "9H", "9S", "9C", "9D", "10H", "10S", "10C", "10D", "AH", "AS", "AC", "AD"])

def deals(cards, players, cards_per_player):
    if not cards:
        yield []
        return
    for hand in it.combinations(cards, cards_per_player[0]):
        hand = set(hand)
        for deal in deals(cards - hand, players[1:], cards_per_player[1:]):
            yield zip([players[0]]*len(hand), hand) + deal

> for deal in deals(cards, ['_1', '_2', '_3', '_4', '_Tc', '_To'], [3,3,3,3,1,3]):
      print deal

这还需要很长时间,但处理这些卡的方法很多。

答案 2 :(得分:0)

你可以每人使用一系列卡片,并按顺序放置卡片,所以当你匹配这两个阵列时,它们将是相同的。 您可以为每张卡使用元组(大小为2),其中第一个元素可以表示范围(13)中的值,第二个元素可以是颜色(也用范围(4)中的数字表示)。您可以轻松生成带有双循环的套牌,也许作为字典,在处理完卡片后,您可以删除已经使用过的卡片,这样就不会有重复,并且当您处理所有的手牌时(如果有的话)代码很容易修改它以拥有不同数量的玩家)你可以订购手,将它与你已经拥有的数据库进行比较,如果有匹配则不保存它,你也可以保存如果你想要的话,你可以做一些统计数据的剩余部分,而不是你可以为每种情况进行所有可能的交易,无论如何都是一个庞大的数据库。通过这种方式,您将拥有所有可能性,手中或玩家手中没有重复。 (玩家一方在不同的交易中拥有玩家二的手,反之亦然) 我希望这对你或其他人有所帮助。 我没有提供代码示例,因为这个问题更像是如何解决这个问题,其他人给了你编码提示。即使你刚刚启动python并且直到现在才做了一些教程,这种方法也可以完成。 祝你好运;)