generated from cis3296f22/project-template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathranker.py
205 lines (171 loc) · 6.7 KB
/
ranker.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
import numpy as np
from card import Card
class Ranker:
@staticmethod
def rank_all_hands(hand_combos, return_all=False):
"""
Evaluates all combinations of hands provided and ranks them. Can return all rankings or only the highest one.
Args:
hand_combos (list[list[Card]]): A list containing lists of Card objects, each list representing a hand.
return_all (bool): If True, returns a list of all rankings. If False, returns only the highest ranked hand.
Returns:
list or tuple: Depending on 'return_all', a list of all rankings or a tuple for the highest ranked hand.
"""
rank_res_arr = np.zeros(shape=(len(hand_combos), len(hand_combos[0])))
for i, hand in enumerate(hand_combos):
for j, card_combo in enumerate(hand):
rank_res_arr[i, j] = Ranker.rank_one_hand(card_combo)
results = []
for hand in hand_combos:
rank, tie_breakers = Ranker.rank_one_hand(hand)
results.append((rank, tie_breakers))
if return_all:
return results
else:
highest_hand = max(results, key=lambda x: (x[0], x[1]))
return highest_hand
@staticmethod
def rank_one_hand(hand):
"""
Ranks a single poker hand.
Args:
hand (list[Card]): A list of Card objects.
Returns:
tuple: A tuple containing the rank of the hand and list of tie breakers.
"""
counts = np.array([card.count for card in hand])
colors = np.array([card.color for card in hand])
counts.sort()
suit_arr = Ranker.gen_suit_arr(colors)
straight_arr = Ranker.gen_straight_arr(counts)
rank = 0
tie_breakers = []
rank, tie_breakers = Ranker.straight_flush_check(counts, rank, straight_arr, suit_arr)
if rank == 0:
rank, tie_breakers = Ranker.four_of_a_kind_check(counts, rank)
if rank == 0:
rank, tie_breakers = Ranker.full_house_check(counts, rank)
if rank == 0:
rank, tie_breakers = Ranker.flush_check(rank, suit_arr, counts)
if rank == 0:
rank, tie_breakers = Ranker.straight_check(counts, rank, straight_arr)
if rank == 0:
rank, tie_breakers = Ranker.three_of_a_kind_check(counts, rank)
if rank == 0:
rank, tie_breakers = Ranker.two_pairs_check(counts, rank)
if rank == 0:
rank, tie_breakers = Ranker.one_pair_check(counts, rank)
if rank == 0:
tie_breakers = sorted(counts, reverse=True)
rank = 0
return rank, tie_breakers
@staticmethod
def gen_suit_arr(colors):
"""
Checks if all cards in the hand have the same suit.
Args:
colors (numpy.ndarray): Array of card color codes.
Returns:
bool: True if all cards have the same suit, otherwise False.
"""
return np.max(colors) == np.min(colors)
@staticmethod
def gen_straight_arr(counts):
"""
Determines if the hand is a straight.
Args:
counts (numpy.ndarray): Sorted array of card counts.
Returns:
bool: True if the cards form a straight, otherwise False.
"""
straight_check = 0
for i in range(4):
if counts[i] + 1 == counts[i + 1]:
straight_check += 1
straight_check += ((counts[0] == 2) and (counts[4] == 14))
return straight_check == 4
@staticmethod
def straight_flush_check(counts, rank, straight_arr, suit_arr):
"""
Evaluates whether the hand is a straight flush.
Args:
counts (numpy.ndarray): Array of card values sorted in ascending order.
rank (int): Current rank of the hand.
straight_arr (bool): Indicates if the hand is a straight.
suit_arr (bool): Indicates if all cards are of the same suit.
Returns:
int: The updated rank of the hand if a straight flush is found; otherwise, the original rank.
"""
if rank == 0 and straight_arr and suit_arr:
if counts[0] == 2 and counts[4] == 14:
counts[:] = np.roll(counts, -1)
return 8
return rank
@staticmethod
def four_of_a_kind_check(counts, rank):
"""
Checks if the hand contains four of a kind.
Args:
counts (numpy.ndarray): Array of card values.
rank (int): Current rank of the hand.
Returns:
int: Returns 7 (rank for four of a kind) if found, otherwise returns the current rank.
"""
if rank > 0:
return rank
if np.any(np.bincount(counts)[1:] == 4):
for i in range(3):
if counts[i] == counts[i+1]:
if counts[0] != counts[i]:
counts[:] = np.roll(counts, 4-i-1)
break
return 7
return rank
@staticmethod
def full_house_check(counts, rank):
"""
Checks if the hand is a full house.
Args:
counts (numpy.ndarray): Array of card values.
rank (int): Current rank of the hand.
Returns:
int: Returns 6 (rank for full house) if a full house is detected, otherwise returns the current rank.
"""
if rank > 0:
return rank
count_bin = np.bincount(counts)[1:]
if 3 in count_bin and 2 in count_bin:
return 6
return rank
@staticmethod
def flush_check(rank, suit_arr, counts):
"""
Evaluates if the hand is a flush.
Args:
rank (int): Current rank of the hand.
suit_arr (bool): Indicates if all cards are of the same suit.
counts (numpy.ndarray): Array of card values.
Returns:
int: Returns 5 (rank for flush) if a flush is found, otherwise returns the current rank.
"""
if rank > 0:
return rank
return 5 if suit_arr else rank
@staticmethod
def straight_check(counts, rank, straight_arr):
"""
Checks if the hand is a straight.
Args:
counts (numpy.ndarray): Array of card values sorted in ascending order.
rank (int): Current rank of the hand.
straight_arr (bool): Indicates if the hand is a straight.
Returns:
int: Returns 4 (rank for straight) if a straight is found, otherwise returns the current rank.
"""
if rank > 0:
return rank
if straight_arr:
if counts[0] == 2 and counts[4] == 14:
counts[:] = np.roll(counts, -1)
return 4
return rank