import itertools
def numeric_ranks(cards):
"""
Changes the input list of card strings to a list of
strings with numbers substituting for face cards.
ex.
numeric_ranks(['AS','3S','4S','5S','JC'])
returns ['14S','3S','4S','5S','11C']
"""
suits = get_suits(cards)
face_numbers = {'A': 14, 'J': 11, 'Q': 12, 'K': 13}
for index, card in enumerate(cards):
rank = card[0:-1]
try:
int(rank)
except:
# Rank is a letter, not a number
cards[index] = str(face_numbers[rank])+suits[index]
return cards
def get_ranks(cards):
"""
Returns a list of ints containing the rank of each card in cards.
ex.
get_ranks(['2S','3C','5C','4D','6D'])
returns [2,3,5,4,6]
"""
cards = numeric_ranks(cards) # Convert rank letters to numbers (e.g. J to 11)
return [int(card[0:-1]) for card in cards]
def get_suits(cards):
"""
Returns a list of strings containing the suit of each card in cards.
ex.
get_ranks(['2S','3C','5C','4D','6D'])
returns ['S','C','C','D','D']
"""
return [card[-1] for card in cards]
def evaluate_hand(hand):
"""
Returns a string containing the name of the hand in poker.
Input hand must be a list of 5 strings.
ex.
evaluate_hand(['2S','3C','5C','4D','6D'])
returns 'Straight'
"""
hand = numeric_ranks(hand)
ranks = get_ranks(hand)
suits = get_suits(hand)
if len(set(hand)) < len(hand) or max(ranks) > 14 or min(ranks) < 1:
# There is a duplicate
return 'Invalid hand'
if isconsecutive(ranks):
# The hand is a type of straight
if all_equal(suits):
# Hand is a flush
if max(ranks) == 14:
# Highest card is an ace
return 'Royal flush'
return 'Straight flush'
return 'Straight'
if all_equal(suits):
return 'Flush'
total = sum([ranks.count(x) for x in ranks])
hand_names = {
17: 'Four of a kind',
13: 'Full house',
11: 'Three of a kind',
9: 'Two pair',
7: 'One pair',
5: 'High card'
}
return hand_names[total]
def all_equal(lst):
"""
Returns True if all elements of lst are the same, False otherwise
ex.
all_equal(['S,'S','S']) returns True
"""
return len(set(lst)) == 1
def show_cards(cards):
""" Prints the rank and suit for each card in cards. """
cards = sort_cards(cards)
all_suits = ['C','D','H','S']
symbols = dict(zip(all_suits,['\u2667','\u2662','\u2661','\u2664']))
faces = {14: 'A', 11: 'J', 12: 'Q', 13: 'K'}
card_symbols = []
for card in cards:
rank = card[0:-1]
if int(rank) in faces:
card_symbols.append(faces[int(rank)] + symbols[card[-1]])
else:
card_symbols.append(rank + symbols[card[-1]])
for symbol in card_symbols:
print(symbol, end = ' ')
print('')
return card_symbols
def isconsecutive(lst):
"""
Returns True if all numbers in lst can be ordered consecutively, and False otherwise
"""
return len(set(lst)) == len(lst) and max(lst) - min(lst) == len(lst) - 1
def sort_cards(cards):
"""
Sorts cards by their rank.
If rank is a string (e.g., 'A' for Ace), then the rank is changed to a number.
Cards of the same rank are not sorted by suit.
ex.
sort_cards(['AS','3S','4S','5S','JC'])
returns
['3S','4S','5S','11C','14S']
"""
cards = numeric_ranks(cards)
rank_list = get_ranks(cards)
# Keep track of the sorting permutation
new_order = sorted((e,i) for i,e in enumerate(rank_list))
unsorted_cards = list(cards)
for index, (a, b) in enumerate(new_order):
cards[index] = unsorted_cards[b]
return cards
def get_best_hand(cards):
"""
Returns the best hand of five cards, from a larger list of cards.
If ranks are alphabetical (e.g., A for ace), it will convert the rank to a number.
ex.
get_best_hand(['7C', '7S', '2H', '3C', 'AC', 'AD', '5S'])
returns
['5S', '7C', '7S', '14C', '14D']
"""
# All combinations of 5 cards from the larger list
all_hand_combos = itertools.combinations(cards, 5)
hand_name_list = [
'Invalid hand',
'High card',
'One pair',
'Two pair',
'Three of a kind',
'Straight',
'Flush',
'Full house',
'Four of a kind',
'Straight flush',
'Royal flush'
]
num_hand_names = len(hand_name_list)
max_value = 0
best_hands = {x: [] for x in range(num_hand_names)}
for combo in all_hand_combos:
hand = list(combo)
hand_name = evaluate_hand(hand) # Get the type of hand (e.g., one pair)
hand_value = hand_name_list.index(hand_name)
if hand_value >= max_value:
# Stronger or equal hand has been found
max_value = hand_value
best_hands[hand_value].append(hand) # Store hand in dictionary
max_hand_idx = max(k for k, v in best_hands.items() if len(best_hands[k])>0)
rank_sum, max_sum = 0, 0
# The strongest hand type out of the combinations has been found
for hand in best_hands[max_hand_idx]:
# Iterate through hands of this strongest type
ranks = get_ranks(hand)
rank_sum = sum(ranks)
if rank_sum > max_sum:
max_sum = rank_sum
best_hand = hand # Choose hand with highest ranking cards
return best_hand
table = ['2H', '5C', 'AC', 'AD', '6C']
hand = ['7C','AS']
cards = hand + table
best_hand = get_best_hand(cards)
print('Hand:')
show_cards(hand), print('')
print('Cards on table:')
show_cards(table), print('')
print('Best hand of five:')
show_cards(best_hand)
print(evaluate_hand(best_hand))
This prints out:
Hand:
7♧ A♤
Cards on table:
2♡ 5♧ 6♧ A♧ A♢
Best hand of five:
6♧ 7♧ A♤ A♧ A♢
Three of a kind