Created
February 13, 2012 09:40
-
-
Save codeinthehole/1815506 to your computer and use it in GitHub Desktop.
Determine how wins poker game from input file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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