In [47]:
def card_ranks(cards):
"Return a list of the ranks, sorted with higher first."
ranks = ["--23456789TJQKA".index(r) for r,s in cards]
ranks.sort(reverse=True)
return [5, 4, 3, 2, 1] if (ranks == [14, 5, 4, 3, 2]) else ranks
In [48]:
def straight(ranks):
"Return True if the ordered ranks form a 5-card straight."
return (max(ranks) - min(ranks)) == 4 and len(set(ranks)) == 5
In [49]:
def flush(hand):
"Return True if all the cards have the same suit."
suits = [card[1] for card in hand]
return len(set(suits)) == 1
In [50]:
def kind(n, ranks):
"""Return the first rank that this hand has exactly n of.
Return None if there is no n-of-a-kind in the hand."""
for rank in ranks:
if ranks.count(rank) == n: return rank
return None
In [51]:
def two_pair(ranks):
"""If there are two pair, return the two ranks as a
tuple: (highest, lowest); otherwise return None."""
pairs = set([rank for rank in ranks if ranks.count(rank) == 2])
if len(pairs) != 2:
return None
else:
return (max(pairs), min(pairs))
In [52]:
def hand_rank(hand):
"Return a value indicating the ranking of a hand."
ranks = card_ranks(hand)
if straight(ranks) and flush(hand): # Straight flush
return (8, max(ranks))
elif kind(4, ranks): # Four of a kind
return (7, kind(4, ranks), kind(1, ranks))
elif kind(3, ranks) and kind(2, ranks): # Full house
return (6, kind(3, ranks), kind(2, ranks))
elif flush(hand): # Flush
return (5, ranks)
elif straight(ranks): # Straight
return (4, max(ranks))
elif kind(3, ranks): # Three of a kind
return (3, kind(3, ranks), ranks)
elif two_pair(ranks): # Two pair
return (2, two_pair(ranks), ranks)
elif kind(2, ranks): # One pair
return (1, kind(2, ranks), ranks)
else: # High card
return (0, ranks)
In [53]:
def allmax(iterable, key=None):
"Return a list of all items equal to the max of the iterable."
key = key or (lambda x: x)
Max = max(iterable, key=key)
return [item for item in iterable if key(item) == key(Max)]
In [54]:
def poker(hands):
"Return a list of winning hands: poker([hand,...]) => [hand,...]"
return allmax(hands, key=hand_rank)
In [55]:
def test():
"Test cases for the functions in poker program"
sf = "6C 7C 8C 9C TC".split()
sf2 = "6D 7D 8D 9D TD".split()
fk = "9D 9H 9S 9C 7D".split()
fh = "TD TC TH 7C 7D".split()
tp = "TD TC AD AC 9C".split()
sf_ranks = card_ranks(sf)
fk_ranks = card_ranks(fk)
tp_ranks = card_ranks(tp)
# Test cases for card_ranks
assert card_ranks(['AC', '3D', '4S', 'KH']) == [14, 13, 4, 3]
assert card_ranks(sf) == [10, 9, 8, 7, 6]
assert card_ranks(['AC', '2D', '3C', '4D', '5H']) == [5, 4, 3, 2, 1]
# Test cases straight
assert straight(sf_ranks) == True
assert straight(fk_ranks) == False
# Test cases for flush
assert flush(sf) == True
assert flush(fk) == False
# Test cases for kind
assert kind(4, fk_ranks) == 9
assert kind(4, sf_ranks) == None
# Test cases for two pairs
assert two_pair(tp_ranks) == (14, 10)
assert two_pair(fk_ranks) == None
# Test cases for poker
assert poker([sf, fk, fh]) == [sf]
assert poker([fk, fh]) == [fk]
assert poker([fh, fh]) == [fh, fh]
assert poker([sf]) == [sf]
assert poker([sf] + 99*[fh]) == [sf]
assert poker([sf, sf2, fk]) == [sf, sf2]
# Test cases for hand_rank
assert hand_rank(sf) == (8, 10)
assert hand_rank(fk) == (7, 9, 7)
assert hand_rank(fh) == (6, 10, 7)
print "All tests pass!"
test()
In [56]:
import random
mydeck = [r+s for r in '23456789TJQKA' for s in 'SHDC']
def deal(numhands, n=5, deck=mydeck):
random.shuffle(mydeck)
hands = []
for i in range(numhands):
hands.append(mydeck[i*n:(i+1)*n])
return hands
print deal(2)
In [57]:
from tqdm import tnrange
def hand_percentage(n=1*1000):
counts = [0]*9
hand_names = ["High card", "One pair", "Two pair", "Three of a kind", "Straight",
"Flush", "Full house", "Four of a kind", "Straight flush"]
for i in tnrange(n/10):
for hand in deal(10):
ranking = hand_rank(hand)[0]
counts[ranking] += 1
for i in reversed(range(9)):
print "{:16}: {:06.3f}".format(hand_names[i], 100.*counts[i]/n)
In [58]:
hand_percentage(100*1000)
In [59]:
def group(items):
groups = [(items.count(item), item) for item in set(items)]
return sorted(groups, reverse=True)
In [60]:
def hand_rank(hand):
groups = group(["--23456789TJQKA".index(r) for r,s in hand])
counts, ranks = zip(*groups)
if ranks == (14, 5, 4, 3, 2):
ranks = (5, 4, 3, 2, 1)
isStraight = straight(ranks)
isFlush = flush(hand)
return (8 if isStraight and isFlush else
7 if (4, 1) == counts else
6 if (3, 2) == counts else
5 if isFlush else
4 if isStraight else
3 if (3, 1, 1) == counts else
2 if (2, 2, 1) == counts else
1 if (2, 1, 1, 1) == counts else
0), ranks
In [61]:
def test():
"Test cases for the functions in poker program"
sf = "6C 7C 8C 9C TC".split()
sf2 = "6D 7D 8D 9D TD".split()
fk = "9D 9H 9S 9C 7D".split()
fh = "TD TC TH 7C 7D".split()
tp = "TD TC AD AC 9C".split()
# Test cases for group
assert group([6, 7, 8, 9, 10]) == [(1, 10), (1, 9), (1, 8), (1, 7), (1, 6)]
assert group([9, 9, 9, 9, 7]) == [(4, 9), (1, 7)]
assert group([10, 10, 10, 7, 7]) == [(3, 10), (2, 7)]
# Test cases for group
assert hand_rank(sf) == (8, (10, 9, 8, 7, 6))
assert hand_rank(fk) == (7, (9, 7))
assert hand_rank(fh) == (6, (10, 7))
assert hand_rank(tp) == (2, (14, 10, 9))
print "All tests pass!"
test()
In [62]:
import itertools
def best_hand(hand):
"""From a more than 5 card hand, return the best 5-card hand."""
return max(itertools.combinations(hand, 5), key=hand_rank)
In [97]:
allranks = "23456789TJQKA"
Blacks = [x+y for x in allranks for y in "SC"]
Reds = [x+y for x in allranks for y in "DH"]
def best_wild_hand(hand):
"""Try all values for jokers in all 5-card selections."""
allhands = set(best_hand(set(h)) for h in itertools.product(*map(replacement, hand)) if len(set(h)) >= 5)
return max(allhands, key=hand_rank)
def replacement(card):
if card == "?B": return Blacks
elif card == "?R": return Reds
else: return [card]
In [ ]: