Split the poker classes into their own library

git-svn-id: file:///srv/svn/euler@5 e5f4c3ec-3c0c-11df-b522-21efaa4426b5
This commit is contained in:
Correl Roush 2010-03-31 13:54:35 +00:00
parent cf3359807d
commit dd7bda3d51
3 changed files with 159 additions and 158 deletions

View file

@ -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'

129
054/poker.py Normal file
View file

@ -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

View file

@ -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()