Generating all 5 card poker hands

前端 未结 11 661
再見小時候
再見小時候 2020-12-23 09:53

This problem sounds simple at first glance, but turns out to be a lot more complicated than it seems. It\'s got me stumped for the moment.

There are 52c5 = 2,598,960

11条回答
  •  猫巷女王i
    2020-12-23 10:15

    Your overall approach is sound. I'm pretty sure the problem lies with your make_canonical function. You can try printing out the hands with num_cards set to 3 or 4 and look for equivalencies that you've missed.

    I found one, but there may be more:

    # The inputs are equivalent and should return the same value
    print make_canonical([8, 12 | 1]) # returns [8, 13]
    print make_canonical([12, 8 | 1]) # returns [12, 9]
    

    For reference, below is my solution (developed prior to looking at your solution). I used a depth-first search instead of a breadth-first search. Also, instead of writing a function to transform a hand to canonical form, I wrote a function to check if a hand is canonical. If it's not canonical, I skip it. I defined rank = card % 13 and suit = card / 13. None of those differences are important.

    import collections
    
    def canonical(cards):
        """
        Rules for a canonical hand:
        1. The cards are in sorted order
    
        2. The i-th suit must have at least many cards as all later suits.  If a
           suit isn't present, it counts as having 0 cards.
    
        3. If two suits have the same number of cards, the ranks in the first suit
           must be lower or equal lexicographically (e.g., [1, 3] <= [2, 4]).
    
        4. Must be a valid hand (no duplicate cards)
        """
    
        if sorted(cards) != cards:
            return False
        by_suits = collections.defaultdict(list)
        for suit in range(0, 52, 13):
            by_suits[suit] = [card%13 for card in cards if suit <= card < suit+13]
            if len(set(by_suits[suit])) != len(by_suits[suit]):
                return False
        for suit in range(13, 52, 13):
            suit1 = by_suits[suit-13]
            suit2 = by_suits[suit]
            if not suit2: continue
            if len(suit1) < len(suit2):
                return False
            if len(suit1) == len(suit2) and suit1 > suit2:
                return False
        return True
    
    def deal_cards(permutations, n, cards):
        if len(cards) == n:
            permutations.append(list(cards))
            return
        start = 0
        if cards:
            start = max(cards) + 1
        for card in range(start, 52):
            cards.append(card)
            if canonical(cards):
                deal_cards(permutations, n, cards)
            del cards[-1]
    
    def generate_permutations(n):
        permutations = []
        deal_cards(permutations, n, [])
        return permutations
    
    for cards in generate_permutations(5):
        print cards
    

    It generates the correct number of permutations:

    Cashew:~/$ python2.6 /tmp/cards.py | wc
    134459
    

提交回复
热议问题