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
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…