Skip to content

Instantly share code, notes, and snippets.

@r3
Created April 25, 2012 00:12
Show Gist options
  • Save r3/2484778 to your computer and use it in GitHub Desktop.
Save r3/2484778 to your computer and use it in GitHub Desktop.
Udacity code up to #16
def poker(hands):
"""Return the best hand: poker([hand,...]) => hand"""
# Recall that providing a key is essentially calling
# that function on 'hands' and sorting the objects by
# the results.
return max(hands, key=hand_rank)
def card_ranks(cards):
"""Return hand sorted by card rank"""
# Dictionary, maps between one object and another
# ie. conv['T'] => 10
conv = {'T' : 10, 'J' : 11, 'Q' : 12, 'K' : 13, 'A' : 14}
# Ternary inside of a list comprehension. Expands to:
#
# result = []
# for x, y in cards:
# if x in conv:
# result.append(conv[x])
# else:
# result.append(int(x))
#
ranks = [conv[x] if x in conv else int(x) for x,y in cards]
ranks.sort(reverse = True)
return ranks
# In the videos, it was done as follows (as opposed to my list
# comprehension, but feels like an ugly hack to me.
#
# ranks = ['--23456789TJQKA'.index(r) for r,s in hand]
# ranks.sort(reverse = True)
# return ranks
def straight(ranks):
"""Return True if the ordered ranks form a 5-card straight"""
# See below for set information. Notice that we're using
# the set to ensure that there are no duplicate card ranks.
return (max(ranks) - min(ranks) == 4 and len(set(ranks)) == 5)
def flush(hand):
"""Return True if all the cards have the same suit."""
suits = [y for x,y in hand]
# Remember that a set will remove duplicates: set([1, 2, 3, 1, 3, 4])
# => 1, 2, 3, 4
# Also recognize that sets, like dictionaries, are unordered;
# If you choose to iterate over them, do not expect that the
# order will remain unchanged. Here, we don't care about the
# ordering. We gather a list of all the cards' suits, and ask
# if they're all the same by removing duplicates with the 'set'
# data model and check that its length is one.
return len(set(suits)) == 1
def two_pair(ranks):
"""If there are two pair, return the ranks as a tuple
(highest, lowest); otherwise return none
"""
# Create a shallow copy to avoid changing original
# (Side effects, especially unexpected ones, are bad)
pool = list(ranks)
result = []
for count in range(2):
found = kind(2, pool)
if found:
result.append(found)
# We remove the found card so that the next call
# to 'kind' will not return the same exact pair.
pool.remove(found)
if len(result) == 2:
return tuple(sorted(result, reverse=True))
def kind(number, ranks):
"""Returns the rank that occurs 'number' times"""
for card in ranks:
if ranks.count(card) == number:
return card
def hand_rank(hand):
"""Return a value indicating the ranking of a hand."""
ranks = card_ranks(hand)
# Straight Flush -> (8, high_rank)
if straight(ranks) and flush(hand):
return (8, max(ranks))
# 4 of a kind -> (7, rank, extra)
elif kind(4, ranks):
return (7, kind(4, ranks), kind(1, ranks))
# Full house -> (6, rank3, rank2)
elif kind(3, ranks) and kind(2, ranks):
return (6, kind(3, ranks), kind(2, ranks))
# Flush -> (5, [full_sorted_hand])
elif flush(hand):
return (5, ranks)
# Straight -> (4, high_rank)
elif straight(ranks):
return (4, max(ranks))
# 3 of a kind -> (3, rank, [full_sorted_hand])
elif kind(3, ranks):
return (3, kind(3, ranks), ranks)
# 2 pairs -> (2, high_rank, low_rank, [full_sorted_hand])
elif two_pair(ranks):
high, low = two_pair(ranks)
return (2, high, low, ranks)
# 2 of a kind -> (1, rank, [full_sorted_hand])
elif kind(2, ranks):
return (1, kind(2, ranks), ranks)
# Nothing -> (0, [full_sorted_hand])
else:
return (0, ranks)
def test():
"""Test cases for the functions in poker program."""
sf = "6C 7C 8C 9C TC".split() # Straight Flush
fk = "9D 9H 9S 9C 7D".split() # Four of a Kind
fh = "TD TC TH 7C 7D".split() # Full House
tp = "5S 5D 9H 9C 6S".split() # Two Pair
assert card_ranks(sf) == [10, 9, 8, 7, 6]
assert card_ranks(fk) == [9, 9, 9, 9, 7]
assert card_ranks(fh) == [10, 10, 10, 7, 7]
fkranks = card_ranks(fk)
tpranks = card_ranks(tp)
assert kind(4, fkranks) == 9
assert kind(3, fkranks) == None
assert kind(2, fkranks) == None
assert kind(1, fkranks) == 7
assert two_pair(fkranks) == None
assert two_pair(tpranks) == (9, 5)
assert poker([sf, fk, fh]) == sf
assert poker([fk, fh]) == fk
assert poker([fh, fh]) == fh
assert poker([sf]) == sf
assert poker([sf] + 99*[fh]) == sf
assert hand_rank(sf) == (8, 10)
assert hand_rank(fk) == (7, 9, 7)
assert hand_rank(fh) == (6, 10, 7)
return 'tests pass'
if __name__ == '__main__':
print(test())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment