-
Notifications
You must be signed in to change notification settings - Fork 0
/
deckparts.py
293 lines (233 loc) · 8.35 KB
/
deckparts.py
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
import itertools
import random
import operator
SUITS = set(['Hearts', 'Spades', 'Clubs', 'Diamonds'])
HAND_RESULTS = [(
'High Card', 10), ('Pair', 20), ('Two Pair', 30), ('Three of a Kind', 40), ('Straight', 50),
('Flush', 60), ('Full House', 70), ('Four of a Kind', 80), ('Straight Flush', 90), ('Royal Flush', 100)]
FACE_CARDS = {
1: {
'name': 'Ace',
'abbr': 'A',
'highnum': 14,
'lownum': 1,
},
11: {
'name': 'Jack',
'abbr': 'J',
'highnum': 11,
'lownum': 11,
},
12: {
'name': 'Queen',
'abbr': 'Q',
'highnum': 12,
'lownum': 12,
},
13: {
'name': 'King',
'abbr': 'K',
'highnum': 13,
'lownum': 13,
},
}
class Card(object):
def __init__(self, suit, name, abbr, high_num, low_num):
self.suit = suit
self.name = name
self.abbr = abbr
self.high_num = high_num
self.low_num = low_num
def __unicode__(self):
return "{s.name} of {s.suit}".format(s=self)
def __str__(self):
return self.__unicode__()
class Hand(object):
def __init__(self):
self.cards = set()
self.score = 0
def add_card(self, card):
self.cards.add(card)
def remove_card(self, card):
self.cards.remove(card)
def scorehand(self):
combos = list(itertools.combinations(self.cards, 5))
highest = 0
highest_hand = combos[0]
for combo in combos:
current = self.scorehand_5(combo)
if current > highest:
highest = current
highest_hand = combo
if current == highest:
highest_hand = self._compare_same(highest_hand, combo, highest)
return (highest, highest_hand)
def _compare_same(self, hand1, hand2, score):
result = hand1
if score[1] == 10:
# self._print_5_card_hand(hand1)
# print(type(list(hand1)))
# print(type(hand2))
result = self._dif_high_card(list(hand1), list(hand2))
"""
10 is highscard
20 is pair
30 is two pair
40 is three of kind
50 is straight
60 is flush
70 is full House
80 is four of kind
90 is straight flush
100 is Royal flush
"""
return result
def _dif_high_card(self, hand1, hand2):
result = hand1
hand1.sort(key=operator.attrgetter("high_num"), reverse=True)
hand2.sort(key=operator.attrgetter("high_num"), reverse=True)
for card_hand1, card_hand2 in zip(hand1, hand2):
if card_hand1.high_num > card_hand2.high_num:
result = hand1
break
elif card_hand1.high_num < card_hand2.high_num:
result = hand2
break
else:
pass
# return "It's a tie!" # this should throw an excpetion
return result
def _dif_pair(self, hand1, hand2):
result = hand1
# get the two cards that comprise the pair of each hand.
# compare them, if one is higher, it is the winner.
# if they are the same, then remove the pairs from each hand
# so that there are only three left. Then run the _dif_high_card
# function to determine who has the highest kicker.
# if all three kicker cards are equal, then throw tie exception for now.
return hand1
def _dif_two_pair(self, hand1, hand2):
result = hand1
# get pairs from each hand.
# compare the highest pair from each hand, highest wins.
# if they are same rank, compare the lesser pair from each hand, highest wins.
# if they are the same, compare remaining kicker card, higher kicker wins.
# if top pair, bottom pair and kicker are equal, throw tie excetion.
return result
def _dif_three_kind(self, hand1, hand2):
result = hand1
# same as _dif_pair only pull the three matching value cards and if tie,
# compare the two remaining kickers.
return result
def _dif_flush(self, hand1, hand2):
# If both hands are flushes, then just get the
# flush with the highest card(s).
return self._dif_high_card(hand1, hand2)
def _print_5_card_hand(self, hand):
print ('-' * 10)
for card in hand:
print "%s%s" % (' ' * 8, card)
def scorehand_5(self, card5):
result = HAND_RESULTS[0]
pairs = self._of_a_kind(card5, 2, "Pair of")
threes = self._of_a_kind(card5, 3, "Three of a kind, three ")
fours = self._of_a_kind(card5, 4, "Four of a kind, four ")
straight = self._has_straight(card5)
flush = self._has_flush(card5)
if len(pairs) == 2:
result = HAND_RESULTS[2]
elif pairs and not threes == 1:
result = HAND_RESULTS[1]
if not pairs and threes:
result = HAND_RESULTS[3]
if fours:
result = HAND_RESULTS[7]
# No need to check this if there
# is another scored hand
if straight:
result = HAND_RESULTS[4]
if flush:
result = HAND_RESULTS[5]
if pairs and threes:
result = HAND_RESULTS[6]
if straight and flush:
result = HAND_RESULTS[8]
return result
def _of_a_kind(self, card5, value, score_message):
result = []
for card in card5:
kind_present = self._filterbyvalue(self.cards, card)
if len(list(kind_present)) == value:
new_val = str.format("{} {}s.", score_message, card.name)
if not new_val in result:
result.append(new_val)
return result
def _has_flush(self, card5):
result = []
for card in card5:
flush_present = self._filterbysuit(self.cards, card)
if len(list(flush_present)) == 5:
new_val = str.format("Flush {}", card.suit)
if not new_val in result:
result.append(new_val)
break
return result
def _filterbyvalue(self, seq, value):
for el in seq:
if el.high_num == value.high_num:
yield el
def _filterbysuit(self, seq, value):
for el in seq:
if el.suit == value.suit:
yield el
def _has_straight(self, card5):
result = []
low_nums = []
high_nums = []
for card in card5:
low_nums.append(card.low_num)
high_nums.append(card.high_num)
if self._sequential_ints(low_nums) or self._sequential_ints(high_nums):
result.append("Straight.")
return result
def _sequential_ints(self, item_vals):
return len(item_vals) == len(set(item_vals)) == max(item_vals) - min(item_vals) + 1
class Player(object):
def __init__(self, name):
self.name = name
self.hand = Hand()
def __unicode__(self):
return self.name
def __str__(self):
return self.__unicode__()
class Deck(object):
def __init__(self):
self.cards = [self._create_card(s, c) for s, c in itertools.product(SUITS, range(1, 14))]
def _create_card(self, suit, value):
if value in FACE_CARDS:
return Card(suit, FACE_CARDS[value]['name'], FACE_CARDS[value]['abbr'],
FACE_CARDS[value]['highnum'], FACE_CARDS[value]['lownum'])
else:
return Card(suit, str(value), str(value), value, value)
def shuffle(self, numshuffles):
for i in xrange(numshuffles):
random.shuffle(self.cards)
class Game(object):
def __init__(self, max_players=0, cards_per_hand=0):
self.deck = Deck()
self.players = set()
self.max_players = max_players
self.cards_per_hand = cards_per_hand
def add_player(self, player):
if len(self.players) <= self.max_players:
self.players.add(player)
else:
raise Exception(
str.format("Max players {} are already in the game.", self.max_players))
def remove_player(self, player):
if player in self.players:
self.players.remove(player)
def deal(self):
for i in range(0, self.cards_per_hand):
for player in self.players:
player.hand.add_card(self.deck.cards.pop())