Skip to content

Instantly share code, notes, and snippets.

@codeinthehole
Created February 13, 2012 09:40
Show Gist options
  • Save codeinthehole/1815506 to your computer and use it in GitHub Desktop.
Save codeinthehole/1815506 to your computer and use it in GitHub Desktop.
Determine how wins poker game from input file
#!/usr/bin/env python
import sys
from optparse import OptionParser
import unittest
from collections import defaultdict
# Constants for each hand
ROYAL_STRAIGHT_FLUSH = 10
STRAIGHT_FLUSH = 9
FOUR_OF_A_KIND = 8
FULL_HOUSE = 7
FLUSH = 6
STRAIGHT = 5
THREE_OF_A_KIND = 4
TWO_PAIR = 3
PAIR = 2
HIGH_CARD = 1
def process_input_lines(lines):
num_player1_wins = 0
for line in lines:
if is_player1_win(line):
num_player1_wins += 1
print "Number of player 1 wins: %d" % num_player1_wins
def convert_to_int(string):
if string.isdigit():
return int(string)
return {
'T': 10,
'J': 11,
'Q': 12,
'K': 13,
'A': 14}[string]
class Hand(object):
def __init__(self, cards):
self.cards = cards
@property
def suits(self):
return [x[1] for x in self.cards]
@property
def numbers(self):
return [x[0] for x in self.cards]
def __str__(self):
return str(self.cards)
def all_same_suit(self):
return len(set(self.suits)) == 1
# Hand checking functions
# Each returns a number if the hand is matched, or None otherwise
def royal_straight_flush(hand):
if hand.all_same_suit() and set(hand.numbers) == set(range(10, 15)):
return 1
def straight_flush(hand):
if hand.all_same_suit():
return straight(hand)
def four_of_a_kind(hand):
return n_of_a_kind(hand, 4)
def full_house(hand):
three_num = three_of_a_kind(hand)
if three_num:
numbers = set([n for n in hand.numbers if n != three_num])
if len(numbers) == 1:
return three_num
def flush(hand):
if hand.all_same_suit():
return high_card(hand)
def straight(hand):
numbers = set(hand.numbers)
if are_numbers_consecutive(numbers):
return max(numbers)
# Check for aces low
if 14 not in numbers:
return None
numbers.remove(14)
numbers.add(1)
if are_numbers_consecutive(numbers):
return max(numbers)
def three_of_a_kind(hand):
return n_of_a_kind(hand, 3)
def two_pair(hand):
pairs = get_pair_numbers(hand)
if len(pairs) == 2:
return max(pairs)
def pair(hand):
pairs = get_pair_numbers(hand)
return max(pairs) if len(pairs) > 0 else None
def high_card(hand):
return max(hand.numbers)
# Utils
def get_pair_numbers(hand):
freqs = get_number_freqencies(hand.numbers)
pairs = []
for num, freq in freqs.items():
if freq == 2:
pairs.append(num)
return pairs
def n_of_a_kind(hand, n):
freqs = get_number_freqencies(hand.numbers)
for number, freq in freqs.items():
if freq == n:
return number
def get_number_freqencies(numbers):
freqs = defaultdict(int)
for n in numbers:
freqs[n] += 1
return freqs
def are_numbers_consecutive(numbers):
minimum = min(numbers)
return numbers == set(range(minimum, minimum+5))
# Engine
def is_player1_win(line):
cards = [(convert_to_int(x[0]), x[1]) for x in line.split()]
p1_hand, p2_hand = Hand(cards[:5]), Hand(cards[5:])
return get_best_hand(p1_hand) < get_best_hand(p2_hand)
def get_best_hand(hand):
for hand_type, f in HAND_TESTS:
score = f(hand)
if score is not None:
return (hand_type, score)
HAND_TESTS = [
(ROYAL_STRAIGHT_FLUSH, royal_straight_flush),
(STRAIGHT_FLUSH, straight_flush),
(FOUR_OF_A_KIND, four_of_a_kind),
(FULL_HOUSE, full_house),
(FLUSH, flush),
(STRAIGHT, straight),
(THREE_OF_A_KIND, three_of_a_kind),
(TWO_PAIR, two_pair),
(PAIR, pair),
(HIGH_CARD, high_card),
]
class AllTests(unittest.TestCase):
def test_royal_straight_flush(self):
cards = [(10, 'C'), (11, 'C'), (12, 'C'), (13, 'C'), (14, 'C')]
self.assertTrue(royal_straight_flush(Hand(cards)))
def test_straight_flush(self):
fixtures = [([(10, 'C'), (11, 'C'), (12, 'C'), (13, 'C'), (14, 'C')], 14),
([(2, 'C'), (3, 'C'), (5, 'C'), (4, 'C'), (6, 'C')], 6),
([(2, 'C'), (3, 'C'), (5, 'C'), (4, 'C'), (14, 'C')], 5),
]
for cards, score in fixtures:
self.assertEqual(score, straight_flush(Hand(cards)))
def test_straight(self):
fixtures = [([(10, 'S'), (11, 'C'), (12, 'C'), (13, 'C'), (14, 'C')], 14),
([(2, 'D'), (3, 'C'), (5, 'C'), (4, 'C'), (6, 'C')], 6),
([(2, 'D'), (3, 'H'), (5, 'C'), (4, 'C'), (14, 'C')], 5),
]
for cards, score in fixtures:
self.assertEqual(score, straight(Hand(cards)))
def test_four_of_a_kind(self):
fixtures = [([(10, 'S'), (10, 'C'), (10, 'D'), (10, 'C'), (14, 'C')], 10),
]
for cards, score in fixtures:
self.assertEqual(score, four_of_a_kind(Hand(cards)))
def test_three_of_a_kind(self):
fixtures = [([(9, 'S'), (10, 'C'), (10, 'D'), (10, 'C'), (14, 'C')], 10),
([(9, 'S'), (9, 'C'), (9, 'D'), (10, 'C'), (10, 'C')], 9),
]
for cards, score in fixtures:
self.assertEqual(score, three_of_a_kind(Hand(cards)))
def test_flush(self):
fixtures = [([(2, 'S'), (3, 'S'), (4, 'S'), (10, 'S'), (14, 'S')], 14),
]
for cards, score in fixtures:
self.assertEqual(score, flush(Hand(cards)))
def test_full_house(self):
fixtures = [([(9, 'S'), (9, 'C'), (9, 'D'), (10, 'C'), (10, 'C')], 9),
([(3, 'S'), (3, 'C'), (4, 'D'), (4, 'C'), (4, 'C')], 4),
]
for cards, score in fixtures:
self.assertEqual(score, full_house(Hand(cards)))
def test_two_pair(self):
fixtures = [([(9, 'S'), (9, 'C'), (3, 'D'), (10, 'C'), (10, 'C')], 10),
]
for cards, score in fixtures:
self.assertEqual(score, two_pair(Hand(cards)))
def test_pair(self):
fixtures = [([(9, 'S'), (9, 'C'), (3, 'D'), (10, 'C'), (10, 'C')], 10),
]
for cards, score in fixtures:
self.assertEqual(score, pair(Hand(cards)))
def test_high_card(self):
fixtures = [([(9, 'S'), (9, 'C'), (3, 'D'), (10, 'C'), (10, 'C')], 10),
]
for cards, score in fixtures:
self.assertEqual(score, high_card(Hand(cards)))
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('-t', '--test', dest='run_tests', action='store_true', default=False)
(options, args) = parser.parse_args()
if options.run_tests:
loader = unittest.TestLoader()
suite = loader.loadTestsFromName(__name__)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
else:
process_input_lines(sys.stdin.readlines())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment