mirror of
https://github.com/correl/euler.git
synced 2024-11-30 11:09:52 +00:00
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:
parent
cf3359807d
commit
dd7bda3d51
3 changed files with 159 additions and 158 deletions
136
054/e054.py
136
054/e054.py
|
@ -1,132 +1,4 @@
|
||||||
import operator
|
import poker
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
wins = 0
|
wins = 0
|
||||||
|
@ -138,9 +10,9 @@ if __name__ == '__main__':
|
||||||
break
|
break
|
||||||
counter = counter + 1
|
counter = counter + 1
|
||||||
cards = line.strip().split()
|
cards = line.strip().split()
|
||||||
one = PokerHand(cards[:5])
|
one = poker.Hand(cards[:5])
|
||||||
two = PokerHand(cards[-5:])
|
two = poker.Hand(cards[-5:])
|
||||||
result = PokerHand.compare(one, two)
|
result = poker.Hand.compare(one, two)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
wins = wins + 1
|
wins = wins + 1
|
||||||
outcome = 'Player One wins'
|
outcome = 'Player One wins'
|
||||||
|
|
129
054/poker.py
Normal file
129
054/poker.py
Normal 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
|
52
054/test.py
52
054/test.py
|
@ -1,60 +1,60 @@
|
||||||
from e054 import *
|
import poker
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
class TestCards(unittest.TestCase):
|
class TestCards(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
pass
|
pass
|
||||||
def test_valid_number_card(self):
|
def test_valid_number_card(self):
|
||||||
card = PokerCard('9D')
|
card = poker.Card('9D')
|
||||||
self.assertEqual(card.value, 9)
|
self.assertEqual(card.value, 9)
|
||||||
def test_valid_face_card(self):
|
def test_valid_face_card(self):
|
||||||
card = PokerCard('QH')
|
card = poker.Card('QH')
|
||||||
self.assertEqual(card.value, 12)
|
self.assertEqual(card.value, 12)
|
||||||
def test_invalid_card_value(self):
|
def test_invalid_card_value(self):
|
||||||
self.assertRaises(InvalidCard, PokerCard, 'ZH')
|
self.assertRaises(poker.InvalidCard, poker.Card, 'ZH')
|
||||||
def test_invalid_card_suit(self):
|
def test_invalid_card_suit(self):
|
||||||
self.assertRaises(InvalidCard, PokerCard, '9Z')
|
self.assertRaises(poker.InvalidCard, poker.Card, '9Z')
|
||||||
def test_compare(self):
|
def test_compare(self):
|
||||||
cards = ['QH', '9D', 'JS']
|
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])
|
self.assertEqual([c.value for c in cards_sorted], [12, 11, 9])
|
||||||
|
|
||||||
class TestFiveCardHands(unittest.TestCase):
|
class TestFiveCardHands(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.rank_hands = {
|
self.rank_hands = {
|
||||||
PokerHand.HIGH_CARD: PokerHand(['5D', '8C', '9S', 'JS', 'AC']),
|
poker.Hand.HIGH_CARD: poker.Hand(['5D', '8C', '9S', 'JS', 'AC']),
|
||||||
PokerHand.ONE_PAIR: PokerHand(['5H', '5C', '6S', '7S', 'KD']),
|
poker.Hand.ONE_PAIR: poker.Hand(['5H', '5C', '6S', '7S', 'KD']),
|
||||||
PokerHand.TWO_PAIRS: PokerHand(['2D', '3C', '2H', '7S', '7H']),
|
poker.Hand.TWO_PAIRS: poker.Hand(['2D', '3C', '2H', '7S', '7H']),
|
||||||
PokerHand.THREE_OF_A_KIND: PokerHand(['AS', '2D', 'TH', 'AH', 'AC']),
|
poker.Hand.THREE_OF_A_KIND: poker.Hand(['AS', '2D', 'TH', 'AH', 'AC']),
|
||||||
PokerHand.STRAIGHT: PokerHand(['9D', '5S', '7H', '8S', '6S']),
|
poker.Hand.STRAIGHT: poker.Hand(['9D', '5S', '7H', '8S', '6S']),
|
||||||
PokerHand.FLUSH: PokerHand(['7S', 'TS', 'KS', '3S', 'JS']),
|
poker.Hand.FLUSH: poker.Hand(['7S', 'TS', 'KS', '3S', 'JS']),
|
||||||
PokerHand.FULL_HOUSE: PokerHand(['6S', '2D', '2H', '6D', '6H']),
|
poker.Hand.FULL_HOUSE: poker.Hand(['6S', '2D', '2H', '6D', '6H']),
|
||||||
PokerHand.FOUR_OF_A_KIND: PokerHand(['7S', '7H', '7D', '2H', '7C']),
|
poker.Hand.FOUR_OF_A_KIND: poker.Hand(['7S', '7H', '7D', '2H', '7C']),
|
||||||
PokerHand.STRAIGHT_FLUSH: PokerHand(['JS', '8S', 'QS', 'TS', '9S']),
|
poker.Hand.STRAIGHT_FLUSH: poker.Hand(['JS', '8S', 'QS', 'TS', '9S']),
|
||||||
PokerHand.ROYAL_FLUSH: PokerHand(['QH', 'TH', 'JH', 'KH', 'AH']),
|
poker.Hand.ROYAL_FLUSH: poker.Hand(['QH', 'TH', 'JH', 'KH', 'AH']),
|
||||||
}
|
}
|
||||||
def test_hand_rankings(self):
|
def test_hand_rankings(self):
|
||||||
for rank, hand in self.rank_hands.iteritems():
|
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):
|
def test_ace_high_straight(self):
|
||||||
hand = PokerHand(['AH', 'KS', 'QC', 'JS', 'TS'])
|
hand = poker.Hand(['AH', 'KS', 'QC', 'JS', 'TS'])
|
||||||
self.assertEqual([hand.rank(), hand.values()], [PokerHand.STRAIGHT, [14, 13, 12, 11, 10]])
|
self.assertEqual([hand.rank(), hand.values()], [poker.Hand.STRAIGHT, [14, 13, 12, 11, 10]])
|
||||||
def test_ace_low_straight(self):
|
def test_ace_low_straight(self):
|
||||||
hand = PokerHand(['AH', '2S', '3C', '4S', '5S'])
|
hand = poker.Hand(['AH', '2S', '3C', '4S', '5S'])
|
||||||
self.assertEqual([hand.rank(), hand.values()], [PokerHand.STRAIGHT, [14, 5, 4, 3, 2]])
|
self.assertEqual([hand.rank(), hand.values()], [poker.Hand.STRAIGHT, [14, 5, 4, 3, 2]])
|
||||||
def test_compare_ace_low_straight(self):
|
def test_compare_ace_low_straight(self):
|
||||||
low = PokerHand(['AH', '2S', '3C', '4S', '5S'])
|
low = poker.Hand(['AH', '2S', '3C', '4S', '5S'])
|
||||||
high = PokerHand(['2S', '3C', '4S', '5S', '6S'])
|
high = poker.Hand(['2S', '3C', '4S', '5S', '6S'])
|
||||||
self.assertTrue(low < high)
|
self.assertTrue(low < high)
|
||||||
def test_compare_ranks(self):
|
def test_compare_ranks(self):
|
||||||
for rank, hand in self.rank_hands.iteritems():
|
for rank, hand in self.rank_hands.iteritems():
|
||||||
for rank2, hand2 in self.rank_hands.iteritems():
|
for rank2, hand2 in self.rank_hands.iteritems():
|
||||||
if (rank == rank2):
|
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):
|
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:
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
Loading…
Reference in a new issue