diff --git a/054/e054.py b/054/e054.py index 3b3465b..6502176 100644 --- a/054/e054.py +++ b/054/e054.py @@ -1,132 +1,4 @@ -import operator - -class InvalidCard(Exception): - pass -class InvalidHand(Exception): - pass - -class PokerCard: - values = {'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14} - def __init__(self, string): - self.value = string[0] - if self.value in '23456789': - self.value = int(self.value) - else: - try: - self.value = PokerCard.values[self.value] - except KeyError as e: - raise InvalidCard - self.suit = string[1] - if not self.suit in ['H', 'C', 'S', 'D']: - raise InvalidCard - @staticmethod - def compare(a, b): - if a.value > b.value: - return 1 - elif a.value == b.value: - return 0 - else: - return -1 - -class PokerHand: - HIGH_CARD = 0 - ONE_PAIR = 1 - TWO_PAIRS = 2 - THREE_OF_A_KIND = 3 - STRAIGHT = 4 - FLUSH = 5 - FULL_HOUSE = 6 - FOUR_OF_A_KIND = 7 - STRAIGHT_FLUSH = 8 - ROYAL_FLUSH = 9 - RANKS = [ - 'High Card', - 'One Pair', - 'Two Pairs', - 'Three of a Kind', - 'Straight', - 'Flush', - 'Full House', - 'Four of a Kind', - 'Straight Flush', - 'Royal Flush' - ] - def __init__(self, cards): - self._rank = None - self._cards = sorted([PokerCard(c) for c in cards], cmp=PokerCard.compare, reverse=True) - self._values = [] - self.rank() - def __str__(self): - return str.format("Cards: {0} Rank: '{1}' Values: {2}", - [str(c.value) + c.suit for c in self._cards], - PokerHand.RANKS[self.rank()], - self.values()) - def rank(self): - if self._rank: - return self._rank - flush = True - straight = False - last = None - merged = {} - for c in self._cards: - if last: - if flush and c.suit != last.suit: - flush = False - last = c - if c.value in merged: - merged[c.value] = merged[c.value] + 1 - else: - merged[c.value] = 1 - if (len(merged)) == 5: - # All unique cards, check for a straight - if self._cards[0].value - self._cards[4].value == 4 or \ - (self._cards[4].value == 2 and self._cards[1].value == 5 and self._cards[0].value == 14): - straight = True - if straight and flush: - if self._cards[0].value == 14: - self._rank = PokerHand.ROYAL_FLUSH - else: - self._rank = PokerHand.STRAIGHT_FLUSH - elif flush: - self._rank = PokerHand.FLUSH - elif straight: - self._rank = PokerHand.STRAIGHT - else: - self._rank = PokerHand.HIGH_CARD - self._values = [c.value for c in self._cards] - else: - multiples = [m for m in sorted(merged.items(), key = operator.itemgetter(1), reverse = True) if m[1] > 1] - if len(multiples) > 1: - if multiples[0][1] == multiples[1][1]: - self._rank = PokerHand.TWO_PAIRS - else: - self._rank = PokerHand.FULL_HOUSE - else: - if multiples[0][1] > 3: - self._rank = PokerHand.FOUR_OF_A_KIND - elif multiples[0][1] == 3: - self._rank = PokerHand.THREE_OF_A_KIND - else: - self._rank = PokerHand.ONE_PAIR - mvalues = [m[0] for m in multiples] - self._values = mvalues + [c.value for c in self._cards if c.value not in mvalues] - - return self._rank - def values(self): - if not self._values: - self.rank() - return self._values - @staticmethod - def compare(a, b): - # Compare hand rankings - result = cmp(a.rank(), b.rank()) - if (result == 0): - # Compare hand values - for i in range(len(a.values())): - result = cmp(a.values()[i], b.values()[i]) - if (result != 0): - return result - return result +import poker if __name__ == '__main__': wins = 0 @@ -138,9 +10,9 @@ if __name__ == '__main__': break counter = counter + 1 cards = line.strip().split() - one = PokerHand(cards[:5]) - two = PokerHand(cards[-5:]) - result = PokerHand.compare(one, two) + one = poker.Hand(cards[:5]) + two = poker.Hand(cards[-5:]) + result = poker.Hand.compare(one, two) if result > 0: wins = wins + 1 outcome = 'Player One wins' diff --git a/054/poker.py b/054/poker.py new file mode 100644 index 0000000..21b8856 --- /dev/null +++ b/054/poker.py @@ -0,0 +1,129 @@ +import operator + +class InvalidCard(Exception): + pass +class InvalidHand(Exception): + pass + +class Card: + values = {'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14} + def __init__(self, string): + self.value = string[0] + if self.value in '23456789': + self.value = int(self.value) + else: + try: + self.value = Card.values[self.value] + except KeyError as e: + raise InvalidCard + self.suit = string[1] + if not self.suit in ['H', 'C', 'S', 'D']: + raise InvalidCard + @staticmethod + def compare(a, b): + if a.value > b.value: + return 1 + elif a.value == b.value: + return 0 + else: + return -1 + +class Hand: + HIGH_CARD = 0 + ONE_PAIR = 1 + TWO_PAIRS = 2 + THREE_OF_A_KIND = 3 + STRAIGHT = 4 + FLUSH = 5 + FULL_HOUSE = 6 + FOUR_OF_A_KIND = 7 + STRAIGHT_FLUSH = 8 + ROYAL_FLUSH = 9 + RANKS = [ + 'High Card', + 'One Pair', + 'Two Pairs', + 'Three of a Kind', + 'Straight', + 'Flush', + 'Full House', + 'Four of a Kind', + 'Straight Flush', + 'Royal Flush' + ] + def __init__(self, cards): + self._rank = None + self._cards = sorted([Card(c) for c in cards], cmp=Card.compare, reverse=True) + self._values = [] + self.rank() + def __str__(self): + return str.format("Cards: {0} Rank: '{1}' Values: {2}", + [str(c.value) + c.suit for c in self._cards], + Hand.RANKS[self.rank()], + self.values()) + def rank(self): + if self._rank: + return self._rank + flush = True + straight = False + last = None + merged = {} + for c in self._cards: + if last: + if flush and c.suit != last.suit: + flush = False + last = c + if c.value in merged: + merged[c.value] = merged[c.value] + 1 + else: + merged[c.value] = 1 + if (len(merged)) == 5: + # All unique cards, check for a straight + if self._cards[0].value - self._cards[4].value == 4 or \ + (self._cards[4].value == 2 and self._cards[1].value == 5 and self._cards[0].value == 14): + straight = True + if straight and flush: + if self._cards[0].value == 14: + self._rank = Hand.ROYAL_FLUSH + else: + self._rank = Hand.STRAIGHT_FLUSH + elif flush: + self._rank = Hand.FLUSH + elif straight: + self._rank = Hand.STRAIGHT + else: + self._rank = Hand.HIGH_CARD + self._values = [c.value for c in self._cards] + else: + multiples = [m for m in sorted(merged.items(), key = operator.itemgetter(1), reverse = True) if m[1] > 1] + if len(multiples) > 1: + if multiples[0][1] == multiples[1][1]: + self._rank = Hand.TWO_PAIRS + else: + self._rank = Hand.FULL_HOUSE + else: + if multiples[0][1] > 3: + self._rank = Hand.FOUR_OF_A_KIND + elif multiples[0][1] == 3: + self._rank = Hand.THREE_OF_A_KIND + else: + self._rank = Hand.ONE_PAIR + mvalues = [m[0] for m in multiples] + self._values = mvalues + [c.value for c in self._cards if c.value not in mvalues] + + return self._rank + def values(self): + if not self._values: + self.rank() + return self._values + @staticmethod + def compare(a, b): + # Compare hand rankings + result = cmp(a.rank(), b.rank()) + if (result == 0): + # Compare hand values + for i in range(len(a.values())): + result = cmp(a.values()[i], b.values()[i]) + if (result != 0): + return result + return result \ No newline at end of file diff --git a/054/test.py b/054/test.py index 37f9a6a..ce0dff5 100644 --- a/054/test.py +++ b/054/test.py @@ -1,60 +1,60 @@ -from e054 import * +import poker import unittest class TestCards(unittest.TestCase): def setUp(self): pass def test_valid_number_card(self): - card = PokerCard('9D') + card = poker.Card('9D') self.assertEqual(card.value, 9) def test_valid_face_card(self): - card = PokerCard('QH') + card = poker.Card('QH') self.assertEqual(card.value, 12) def test_invalid_card_value(self): - self.assertRaises(InvalidCard, PokerCard, 'ZH') + self.assertRaises(poker.InvalidCard, poker.Card, 'ZH') def test_invalid_card_suit(self): - self.assertRaises(InvalidCard, PokerCard, '9Z') + self.assertRaises(poker.InvalidCard, poker.Card, '9Z') def test_compare(self): cards = ['QH', '9D', 'JS'] - cards_sorted = sorted([PokerCard(c) for c in cards], cmp=PokerCard.compare, reverse=True) + cards_sorted = sorted([poker.Card(c) for c in cards], cmp=poker.Card.compare, reverse=True) self.assertEqual([c.value for c in cards_sorted], [12, 11, 9]) class TestFiveCardHands(unittest.TestCase): def setUp(self): self.rank_hands = { - PokerHand.HIGH_CARD: PokerHand(['5D', '8C', '9S', 'JS', 'AC']), - PokerHand.ONE_PAIR: PokerHand(['5H', '5C', '6S', '7S', 'KD']), - PokerHand.TWO_PAIRS: PokerHand(['2D', '3C', '2H', '7S', '7H']), - PokerHand.THREE_OF_A_KIND: PokerHand(['AS', '2D', 'TH', 'AH', 'AC']), - PokerHand.STRAIGHT: PokerHand(['9D', '5S', '7H', '8S', '6S']), - PokerHand.FLUSH: PokerHand(['7S', 'TS', 'KS', '3S', 'JS']), - PokerHand.FULL_HOUSE: PokerHand(['6S', '2D', '2H', '6D', '6H']), - PokerHand.FOUR_OF_A_KIND: PokerHand(['7S', '7H', '7D', '2H', '7C']), - PokerHand.STRAIGHT_FLUSH: PokerHand(['JS', '8S', 'QS', 'TS', '9S']), - PokerHand.ROYAL_FLUSH: PokerHand(['QH', 'TH', 'JH', 'KH', 'AH']), + poker.Hand.HIGH_CARD: poker.Hand(['5D', '8C', '9S', 'JS', 'AC']), + poker.Hand.ONE_PAIR: poker.Hand(['5H', '5C', '6S', '7S', 'KD']), + poker.Hand.TWO_PAIRS: poker.Hand(['2D', '3C', '2H', '7S', '7H']), + poker.Hand.THREE_OF_A_KIND: poker.Hand(['AS', '2D', 'TH', 'AH', 'AC']), + poker.Hand.STRAIGHT: poker.Hand(['9D', '5S', '7H', '8S', '6S']), + poker.Hand.FLUSH: poker.Hand(['7S', 'TS', 'KS', '3S', 'JS']), + poker.Hand.FULL_HOUSE: poker.Hand(['6S', '2D', '2H', '6D', '6H']), + poker.Hand.FOUR_OF_A_KIND: poker.Hand(['7S', '7H', '7D', '2H', '7C']), + poker.Hand.STRAIGHT_FLUSH: poker.Hand(['JS', '8S', 'QS', 'TS', '9S']), + poker.Hand.ROYAL_FLUSH: poker.Hand(['QH', 'TH', 'JH', 'KH', 'AH']), } def test_hand_rankings(self): for rank, hand in self.rank_hands.iteritems(): - self.assertEqual(hand.rank(), rank, 'Ranking hand: {0}'.format(PokerHand.RANKS[rank])) + self.assertEqual(hand.rank(), rank, 'Ranking hand: {0}'.format(poker.Hand.RANKS[rank])) def test_ace_high_straight(self): - hand = PokerHand(['AH', 'KS', 'QC', 'JS', 'TS']) - self.assertEqual([hand.rank(), hand.values()], [PokerHand.STRAIGHT, [14, 13, 12, 11, 10]]) + hand = poker.Hand(['AH', 'KS', 'QC', 'JS', 'TS']) + self.assertEqual([hand.rank(), hand.values()], [poker.Hand.STRAIGHT, [14, 13, 12, 11, 10]]) def test_ace_low_straight(self): - hand = PokerHand(['AH', '2S', '3C', '4S', '5S']) - self.assertEqual([hand.rank(), hand.values()], [PokerHand.STRAIGHT, [14, 5, 4, 3, 2]]) + hand = poker.Hand(['AH', '2S', '3C', '4S', '5S']) + self.assertEqual([hand.rank(), hand.values()], [poker.Hand.STRAIGHT, [14, 5, 4, 3, 2]]) def test_compare_ace_low_straight(self): - low = PokerHand(['AH', '2S', '3C', '4S', '5S']) - high = PokerHand(['2S', '3C', '4S', '5S', '6S']) + low = poker.Hand(['AH', '2S', '3C', '4S', '5S']) + high = poker.Hand(['2S', '3C', '4S', '5S', '6S']) self.assertTrue(low < high) def test_compare_ranks(self): for rank, hand in self.rank_hands.iteritems(): for rank2, hand2 in self.rank_hands.iteritems(): if (rank == rank2): - self.assertEqual(hand.rank(), hand2.rank(), '{0} == {1}'.format(PokerHand.RANKS[rank], PokerHand.RANKS[rank2])) + self.assertEqual(hand.rank(), hand2.rank(), '{0} == {1}'.format(poker.Hand.RANKS[rank], poker.Hand.RANKS[rank2])) elif (rank < rank2): - self.assertTrue(hand.rank() < hand2.rank(), '{0} < {1}'.format(PokerHand.RANKS[rank], PokerHand.RANKS[rank2])) + self.assertTrue(hand.rank() < hand2.rank(), '{0} < {1}'.format(poker.Hand.RANKS[rank], poker.Hand.RANKS[rank2])) else: - self.assertTrue(hand.rank() > hand2.rank(), '{0} > {1}'.format(PokerHand.RANKS[rank], PokerHand.RANKS[rank2])) + self.assertTrue(hand.rank() > hand2.rank(), '{0} > {1}'.format(poker.Hand.RANKS[rank], poker.Hand.RANKS[rank2])) if __name__ == '__main__': unittest.main() \ No newline at end of file