1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
class InvalidCard(Exception): pass
class InvalidHand(Exception): pass
def powerset(L):
if L == []:
return [[]]
else:
return powerset(L[1:]) + \
[x + [L[0]] for x in powerset(L[1:])]
def is_straight(L):
if len(L) < 2:
return True
L.sort()
for i, n in enumerate(L[:-1]):
if n + 1 != L[i + 1]:
return False
return True
class Card(object):
def __init__(self, card_desc):
self.suits = {'C': 'Club',
'D': 'Diamond',
'H': 'Heart',
'S': 'Spade'}
self.value, self.suit = self._make_card(card_desc.upper())
def _make_card(self, card_desc):
valid_values = 'A23456789TJQK'
valid_suits = 'CDHS'
if len(card_desc) != 2:
raise InvalidCard('Invalid card description length')
if card_desc[0] not in valid_values:
raise InvalidCard('Invalid card description value')
if card_desc[1] not in valid_suits:
raise InvalidCard('Invalid card description suit')
value = valid_values.index(card_desc[0]) + 1
suit = self.suits[card_desc[1]]
return value, suit
def value_name(self):
values = {1: 'Ace',
11: 'Jack',
12: 'Queen',
13: 'King',
}
return values.get(self.value, str(self.value))
def real_value(self):
'''All figure cards have a value of 10. The ace
has a value of 1.'''
if self.value < 10:
return self.value
else:
return 10
def __cmp__(self, other):
return cmp(self.value, other.value)
def __str__(self):
return '%s of %s' % (self.value_name(), self.suit)
# TODO: Check validity of the hand
class Hand(object):
def __init__(self, pocket_cards, crib_card, is_crib=False):
self.pocket_cards = pocket_cards
self.crib_card = crib_card
self.all = pocket_cards + [crib_card]
self.is_crib = is_crib
def count(self):
'''Sum of the individual ways to make points.'''
return sum((self._count_pairs(),
self._count_triples(),
self._count_quadruples(),
self._count_jack(),
self._count_flush(),
self._count_15(),
self._count_straight()))
def _count_indentical_values(self, n):
values = [card.value for card in self.all]
d = {}
for value in values:
d[value] = values.count(value)
return len([x for x in d.itervalues() if x == n])
def _count_pairs(self):
'''Every pair is worth 2 points.'''
return self._count_indentical_values(2) * 2
def _count_triples(self):
'''Every triple is worth 6 points (there can only
be one per hand.)'''
return self._count_indentical_values(3) * 6
def _count_quadruples(self):
'''Every quadruple is worth 12 points (there can only
be one per hand.)'''
return self._count_indentical_values(4) * 12
def _count_jack(self):
'''If a the suit of a jack in the player\'s pocket
cards matches the suit of the crib card, the player
is awarded one point.'''
jacks_suits = [card.suit for card in self.pocket_cards
if card.value == 11]
return int(any(self.crib_card.suit == suit for suit in jacks_suits))
def _count_flush(self):
'''Pocket cards have the same suit: 4 points.
Pocket cards + crib card have the same suit: 5 points.
The 4 point flush is available only in the "normal" hand.'''
if all(card.suit == self.all[0].suit for card in self.all):
return 5
elif not self.is_crib and \
all(card.suit == self.pocket_cards[0].suit for card in
self.pocket_cards):
return 4
else:
return 0
def _count_15(self):
'''Every combination that adds up to 15 is worth 2 points.'''
values = powerset([card.real_value() for card in self.all])
return len([x for x in values if sum(x) == 15]) * 2
def _count_straight(self):
'''Every card that is part of a straight is worth one point.
A card can be counted more than once. Only straights of three
and more cards are considered.
E.g.: If a player has 2, 3, 3, 4, the two and four are counted
twice for a total of 6 points.'''
straights = [s for s in powerset([card.value for card in self.all])
if len(s) >= 3 and is_straight(s)]
if straights: # max() doesn't work with empty lists
longests = self._keep_longest(straights)
return sum(map(len, longests))
else:
return 0
def _keep_longest(self, straights):
length = len(max(straights, key=len))
return [s for s in straights if len(s) == length] |
Partager