poker-reinforcement-learning 0.1.8__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- poker_reinforcement_learning/__init__.py +10 -0
- poker_reinforcement_learning/client.py +220 -0
- poker_reinforcement_learning/deck.py +99 -0
- poker_reinforcement_learning/dummy_agent.py +240 -0
- poker_reinforcement_learning/limp_agent.py +236 -0
- poker_reinforcement_learning/poker_host.py +340 -0
- poker_reinforcement_learning/server.py +415 -0
- poker_reinforcement_learning-0.1.8.dist-info/LICENSE.txt +674 -0
- poker_reinforcement_learning-0.1.8.dist-info/METADATA +897 -0
- poker_reinforcement_learning-0.1.8.dist-info/RECORD +12 -0
- poker_reinforcement_learning-0.1.8.dist-info/WHEEL +5 -0
- poker_reinforcement_learning-0.1.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,236 @@
|
|
1
|
+
# client.py
|
2
|
+
import sys
|
3
|
+
# Import deck from parent directory
|
4
|
+
import socket
|
5
|
+
import json
|
6
|
+
from .poker_host import Player
|
7
|
+
from .deck import Card
|
8
|
+
|
9
|
+
|
10
|
+
"""
|
11
|
+
Limp Agent:
|
12
|
+
This agent participates based on the concept of "limping" through games. Essentially, the agent will simply match bets so that it can stay in the game but not increase bets to try and gain an advantage.
|
13
|
+
In the poker community, this is quite looked down upon. It kills the excitement of the game and becomes "predictable" and drags on games where players with bad hands should fold.
|
14
|
+
This is a perfect default agent for our purposes! It's strategically weak, extremely easy to implement, and if bugs are thrown I know that it's not because of internal logic.
|
15
|
+
Decision Making Logic:
|
16
|
+
The decision making function will return 1 every time to call every hand.
|
17
|
+
"""
|
18
|
+
class LimpAgent:
|
19
|
+
def __init__(self):
|
20
|
+
# initialize cliennt socket with localhost ip address on port 5555
|
21
|
+
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
22
|
+
self.host = "127.0.0.1"
|
23
|
+
self.port = 5555
|
24
|
+
self.client_socket.connect((self.host, self.port))
|
25
|
+
self.player_number = int(self.client_socket.recv(1024).decode())
|
26
|
+
self.player = Player(self.player_number)
|
27
|
+
self.player.chips *= self.player_number
|
28
|
+
print(f"You are Player {self.player_number}")
|
29
|
+
|
30
|
+
# Client messages Server
|
31
|
+
def send_message(self, message):
|
32
|
+
message = str(message)
|
33
|
+
self.client_socket.send(message.encode())
|
34
|
+
|
35
|
+
# Server messages Client
|
36
|
+
def receive_data(self):
|
37
|
+
data = self.client_socket.recv(1024).decode()
|
38
|
+
try:
|
39
|
+
return json.loads(data)
|
40
|
+
except json.JSONDecodeError:
|
41
|
+
return data
|
42
|
+
|
43
|
+
# Logic to play the game
|
44
|
+
def play_game(self):
|
45
|
+
def is_int(value):
|
46
|
+
try:
|
47
|
+
int(value)
|
48
|
+
return True
|
49
|
+
except ValueError:
|
50
|
+
return False
|
51
|
+
def is_str(value):
|
52
|
+
try:
|
53
|
+
str(value)
|
54
|
+
return True
|
55
|
+
except ValueError:
|
56
|
+
return False
|
57
|
+
|
58
|
+
while True:
|
59
|
+
game_state = self.receive_data()
|
60
|
+
# Wait for start code
|
61
|
+
if isinstance(game_state, str) and game_state == "GAME STARTED":
|
62
|
+
print("Game has started!")
|
63
|
+
|
64
|
+
|
65
|
+
# Big Blind
|
66
|
+
elif isinstance(game_state, str) and ("BIG" in game_state):
|
67
|
+
self.player.chips -= 2
|
68
|
+
# TODO: Handle when player cannot afford big blind
|
69
|
+
if (self.player.chips < 0):
|
70
|
+
self.player.chips = 0
|
71
|
+
|
72
|
+
# Small Blind
|
73
|
+
elif isinstance(game_state, str) and ("SMALL" in game_state):
|
74
|
+
self.player.chips -= 1
|
75
|
+
|
76
|
+
# Server gives chips back to player
|
77
|
+
elif isinstance(game_state, str) and ("GIVE" in game_state):
|
78
|
+
first_tilde_pos = game_state.find("~")
|
79
|
+
second_tilde_pos = game_state.find("~", first_tilde_pos + 1)
|
80
|
+
# Extract the value between the tilde characters
|
81
|
+
if first_tilde_pos != -1 and second_tilde_pos != -1:
|
82
|
+
chips = game_state[first_tilde_pos + 1:second_tilde_pos]
|
83
|
+
self.player.chips += int(chips)
|
84
|
+
print(f"You got {chips} chips back!")
|
85
|
+
else:
|
86
|
+
print("Tilde characters not found or value not present.")
|
87
|
+
|
88
|
+
# If the data is the cards make bets
|
89
|
+
elif isinstance(game_state, dict):
|
90
|
+
self.player.chips = game_state['chips'][str(self.player_number)]
|
91
|
+
# print(f"Round: {game_state['round']}")
|
92
|
+
if (game_state['round'] == 'Showdown!'):
|
93
|
+
self.print_showdown_cards(game_state)
|
94
|
+
if self.player.player_number == game_state['winner']:
|
95
|
+
self.player.chips += int(game_state['pot'])
|
96
|
+
chips_str = "\033[92m{}\033[0m".format(str(self.player.chips))
|
97
|
+
print(f"You now have {chips_str} chips!")
|
98
|
+
continue
|
99
|
+
|
100
|
+
# Add cards into players hands if hand is empty
|
101
|
+
if len(self.player.hand) == 0:
|
102
|
+
for card_str in game_state["player_hand"]:
|
103
|
+
card = Card.from_str(card_str)
|
104
|
+
self.player.hand.append(card)
|
105
|
+
|
106
|
+
print("\nCurrent Cards:")
|
107
|
+
self.print_cards(game_state)
|
108
|
+
# Active player makes their move
|
109
|
+
if game_state['current_player'] == self.player_number:
|
110
|
+
# Game Info
|
111
|
+
print(f"Current Player: Player {game_state['current_player']}", end=" | ")
|
112
|
+
print(f"Current Dealer: Player {game_state['current_dealer']}", end=" | ")
|
113
|
+
print(f"Current Pot: {game_state['pot']}")
|
114
|
+
chips_str = "\033[92m{}\033[0m".format(str(self.player.chips))
|
115
|
+
print(f"You have {chips_str} chips")
|
116
|
+
if (game_state['current_bet'] == 0):
|
117
|
+
print("What would you like to do?\nType 1 to check, 2 to raise, and 3 to fold")
|
118
|
+
if (game_state['current_bet'] > 0):
|
119
|
+
print("What would you like to do?\nType 1 to call, 2 to raise, and 3 to fold")
|
120
|
+
print("Bets:")
|
121
|
+
print("| ",end="")
|
122
|
+
for player,bet in game_state['bets'].items():
|
123
|
+
if bet < 0:
|
124
|
+
bet = 0
|
125
|
+
print(f"Player {player}: {bet} chips", end=" | ")
|
126
|
+
print(f"Current Bet: {game_state['current_bet']} |")
|
127
|
+
|
128
|
+
# Get players choice
|
129
|
+
action, bet = self.make_decision(game_state=game_state)
|
130
|
+
# while ((not is_int(action)) or (int(action) < 1) or (int(action) > 3)):
|
131
|
+
# print("Invalid choice.")
|
132
|
+
# action = self.make_decision(game_state=game_state)
|
133
|
+
|
134
|
+
self.send_message(action)
|
135
|
+
# TODO: Handle when player cannot bet but tries to anyways
|
136
|
+
if int(action) == 2:
|
137
|
+
|
138
|
+
# Player cannot make bet if the bet is not a number,
|
139
|
+
while ((not is_int(bet)) or (int(bet) < 0) or ((int(bet) + game_state['current_bet']) > self.player.chips)):
|
140
|
+
print("Invalid bet.")
|
141
|
+
raise Exception("Invalid Bet has occurred from automated bot")
|
142
|
+
self.player.chips -= int(bet) + game_state['current_bet']
|
143
|
+
self.send_message(bet)
|
144
|
+
|
145
|
+
# Action should always be 1
|
146
|
+
if int(action) == 1:
|
147
|
+
print("AI Called!!!")
|
148
|
+
if game_state['bets'][str(self.player.player_number)] >= 0:
|
149
|
+
self.player.chips += game_state['bets'][str(self.player.player_number)]
|
150
|
+
self.player.chips -= int(game_state['current_bet'])
|
151
|
+
|
152
|
+
print()
|
153
|
+
else:
|
154
|
+
print("Waiting for the other player's move...")
|
155
|
+
# If the move is invalid, the player is prompted again
|
156
|
+
elif isinstance(game_state, str) and game_state == "INVALID_MOVE":
|
157
|
+
print("Invalid move. Please try again.")
|
158
|
+
continue
|
159
|
+
|
160
|
+
elif isinstance(game_state, str) and ("WIN" in game_state):
|
161
|
+
print("Congratulations! You won!")
|
162
|
+
self.player.hand = []
|
163
|
+
|
164
|
+
action = input("Do you want to play again? (y/n)")
|
165
|
+
action = action.lower()
|
166
|
+
while not is_str(action) or (action != "y" and action != "n"):
|
167
|
+
print('invalid entry')
|
168
|
+
action = input("Do you want to play again? (y/n)")
|
169
|
+
action = action.lower()
|
170
|
+
self.send_message(action)
|
171
|
+
|
172
|
+
elif isinstance(game_state, str) and ("LOSS" in game_state):
|
173
|
+
print("Sorry, you lost...")
|
174
|
+
self.player.hand = []
|
175
|
+
|
176
|
+
action = input("Do you want to play again? (y/n)")
|
177
|
+
action = action.lower()
|
178
|
+
while not is_str(action) or (action != "y" and action != "n"):
|
179
|
+
print('invalid entry')
|
180
|
+
action = input("Do you want to play again? (y/n)")
|
181
|
+
action = action.lower()
|
182
|
+
self.send_message(action)
|
183
|
+
|
184
|
+
# Break code when the game ends
|
185
|
+
elif isinstance(game_state, str) and ("END" in game_state):
|
186
|
+
print("Game ended.")
|
187
|
+
break
|
188
|
+
elif isinstance(game_state, str):
|
189
|
+
print(game_state)
|
190
|
+
|
191
|
+
# Close client socket
|
192
|
+
def close_connection(self):
|
193
|
+
self.client_socket.close()
|
194
|
+
|
195
|
+
@staticmethod
|
196
|
+
def make_decision(game_state):
|
197
|
+
# Shoutout raiden. You'd be so proud.
|
198
|
+
return 1, 0
|
199
|
+
|
200
|
+
|
201
|
+
# Helper methods for formatting
|
202
|
+
@staticmethod
|
203
|
+
def print_cards(game_state):
|
204
|
+
print(f"Your Hand:")
|
205
|
+
print("| ", end="")
|
206
|
+
for card_str in game_state["player_hand"]:
|
207
|
+
card = Card.from_str(card_str)
|
208
|
+
print(card.print_card(),end = " | ")
|
209
|
+
print("\n---------------------------")
|
210
|
+
if (len(game_state['community_cards']) > 0):
|
211
|
+
print(f"Community Cards:")
|
212
|
+
print("| ", end="")
|
213
|
+
for card_str in game_state["community_cards"]:
|
214
|
+
card = Card.from_str(card_str)
|
215
|
+
print(card.print_card(),end = " | ")
|
216
|
+
print()
|
217
|
+
@staticmethod
|
218
|
+
def print_showdown_cards(game_state):
|
219
|
+
for player, hand in game_state['players_hand'].items():
|
220
|
+
print(f"Player {player}'s Hand:")
|
221
|
+
print("| ", end="")
|
222
|
+
for card_str in hand:
|
223
|
+
card = Card.from_str(card_str)
|
224
|
+
print(card.print_card(),end = " | ")
|
225
|
+
print("\n---------------------------")
|
226
|
+
if (len(game_state['community_cards']) > 0):
|
227
|
+
print(f"Community Cards:")
|
228
|
+
print("| ", end="")
|
229
|
+
for card_str in game_state["community_cards"]:
|
230
|
+
card = Card.from_str(card_str)
|
231
|
+
print(card.print_card(),end = " | ")
|
232
|
+
print()
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
|
@@ -0,0 +1,340 @@
|
|
1
|
+
import sys
|
2
|
+
# Import deck from parent directory
|
3
|
+
# sys.path.append("../")
|
4
|
+
|
5
|
+
from .deck import *
|
6
|
+
from collections import Counter
|
7
|
+
|
8
|
+
|
9
|
+
flag = False
|
10
|
+
def cprint(str):
|
11
|
+
if flag:
|
12
|
+
print(str)
|
13
|
+
def rank_hand(hand):
|
14
|
+
# Helper function to rank the hand
|
15
|
+
# Returns a tuple with two values:
|
16
|
+
# - The rank of the hand (higher is better)
|
17
|
+
# - The value(s) used for tie-breaking if ranks are equal
|
18
|
+
def is_subarray(subarray, array):
|
19
|
+
# Helper function to check if subarray is a subarray of array
|
20
|
+
m, n = len(subarray), len(array)
|
21
|
+
i = 0
|
22
|
+
while i <= n - m:
|
23
|
+
if array[i:i + m] == subarray:
|
24
|
+
return True # subarray found
|
25
|
+
i += 1
|
26
|
+
return False
|
27
|
+
|
28
|
+
def has_flush(suits):
|
29
|
+
# Helper function to check for a flush
|
30
|
+
# Returns True if there are 5 or more cards of the same suit, False otherwise
|
31
|
+
suit_counts = Counter(suits)
|
32
|
+
return any(count >= 5 for count in suit_counts.values())
|
33
|
+
def has_consecutive_values(arr):
|
34
|
+
n = len(arr)
|
35
|
+
if n < 5:
|
36
|
+
return False, []
|
37
|
+
sorted_arr = sorted(arr)
|
38
|
+
for i in range(n - 4):
|
39
|
+
sub_array = sorted_arr[i : i + 5]
|
40
|
+
# print(sub_array)
|
41
|
+
if all((sub_array[j] + 1) % 13 == sub_array[j + 1] % 13 for j in range(4)) or set(sub_array) == {12, 0, 1, 2, 3}:
|
42
|
+
|
43
|
+
return True, sub_array
|
44
|
+
return False, []
|
45
|
+
values = [card.value for card in hand]
|
46
|
+
suits = [card.suit for card in hand]
|
47
|
+
|
48
|
+
flush = has_flush(suits)
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
if is_subarray([10, 11, 12, 13, 14], sorted(values)) and flush:
|
55
|
+
# print("Royal Flush!")
|
56
|
+
return (10, [14])
|
57
|
+
|
58
|
+
|
59
|
+
straight_values = [value - 2 for value in values]
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
if flush:
|
65
|
+
is_straight_flush, returned = has_consecutive_values(straight_values)
|
66
|
+
if is_straight_flush:
|
67
|
+
# print("Straight Flush!")
|
68
|
+
return (9, [[value + 2 for value in returned][4]])
|
69
|
+
|
70
|
+
# If it's not a straight flush but all suits are the same, it's a flush
|
71
|
+
# Note: You should sort the values in descending order, not just reverse
|
72
|
+
return (6, sorted(values, reverse=True))
|
73
|
+
|
74
|
+
|
75
|
+
for value, count in Counter(values).items():
|
76
|
+
if count == 4:
|
77
|
+
# print("Four of a kind!")
|
78
|
+
return (8, [value, max(set(values) - {value})])
|
79
|
+
|
80
|
+
three_of_a_kind = None
|
81
|
+
pair = None
|
82
|
+
for value, count in Counter(values).items():
|
83
|
+
if count == 3:
|
84
|
+
three_of_a_kind = value
|
85
|
+
elif count == 2:
|
86
|
+
pair = value
|
87
|
+
|
88
|
+
if three_of_a_kind is not None and pair is not None:
|
89
|
+
# print("Full House!")
|
90
|
+
return (7, [three_of_a_kind, pair])
|
91
|
+
|
92
|
+
|
93
|
+
is_straight, returned = has_consecutive_values(straight_values)
|
94
|
+
if (is_straight):
|
95
|
+
# print("Straight!")
|
96
|
+
return (5, [[value + 2 for value in returned][4]])
|
97
|
+
|
98
|
+
for value, count in Counter(values).items():
|
99
|
+
if count == 3:
|
100
|
+
# print("3 of a kind!")
|
101
|
+
return (4, [value] + sorted(set(values) - {value}, reverse=True)[:2])
|
102
|
+
|
103
|
+
pairs = [value for value, count in Counter(values).items() if count == 2]
|
104
|
+
if len(pairs) >= 2:
|
105
|
+
# print("Two Pair!")
|
106
|
+
return (3, sorted(pairs, reverse=True) + sorted(set(values) - set(pairs), reverse=True)[:1])
|
107
|
+
|
108
|
+
for value, count in Counter(values).items():
|
109
|
+
if count == 2:
|
110
|
+
# print("One Pair!")
|
111
|
+
return (2, [value] + sorted(set(values) - {value}, reverse=True)[:3])
|
112
|
+
|
113
|
+
# print("High Card!")
|
114
|
+
return (1, sorted(values, reverse=True))
|
115
|
+
|
116
|
+
class Player:
|
117
|
+
def __init__(self, player_number, chips=100):
|
118
|
+
self.chips = chips
|
119
|
+
self.hand = []
|
120
|
+
self.player_number = player_number
|
121
|
+
|
122
|
+
class TexasHoldem:
|
123
|
+
|
124
|
+
def __init__(self, num_players=2):
|
125
|
+
# Initialize Deck, players hands, community cards
|
126
|
+
self.deck = Deck()
|
127
|
+
self.deck.shuffle()
|
128
|
+
self.community_cards = []
|
129
|
+
self.player_hands = {player: [] for player in range(1, num_players + 1)}
|
130
|
+
self.round = ""
|
131
|
+
self.winning_rank = ""
|
132
|
+
self.all_in = False
|
133
|
+
|
134
|
+
|
135
|
+
# Initialize players
|
136
|
+
self.num_players = num_players
|
137
|
+
self.players = {player: Player(player, chips=100*player) for player in range(1, num_players + 1)}
|
138
|
+
self.dealer = 1
|
139
|
+
self.current_player = (self.dealer % self.num_players) + 1
|
140
|
+
|
141
|
+
self.players_in_round = {player: True for player in range(1, num_players + 1)}
|
142
|
+
|
143
|
+
# Initialize bets
|
144
|
+
self.cum_bets = {player: 0 for player in range(1, num_players + 1)}
|
145
|
+
self.bets = {player: -1 for player in range(1, num_players + 1)}
|
146
|
+
self.current_bet = 0
|
147
|
+
self.pot = 0
|
148
|
+
|
149
|
+
|
150
|
+
def reset_deck(self):
|
151
|
+
self.deck = Deck()
|
152
|
+
self.deck.shuffle()
|
153
|
+
self.community_cards = []
|
154
|
+
self.player_hands = {player: [] for player in range(1, self.num_players + 1)}
|
155
|
+
self.set_round("Pre-flop")
|
156
|
+
self.winning_hand = ""
|
157
|
+
self.all_in = False
|
158
|
+
self.players_in_round = {player: self.players[player].chips != 0 for player in range(1, self.num_players + 1)}
|
159
|
+
|
160
|
+
def reset_players(self):
|
161
|
+
for _, player in self.players.items():
|
162
|
+
player.hand = []
|
163
|
+
|
164
|
+
def reset_bets(self):
|
165
|
+
self.bets = {player: -1 for player in range(1, self.num_players + 1)}
|
166
|
+
self.current_player = (self.dealer % self.num_players) + 1
|
167
|
+
self.current_bet = 0
|
168
|
+
|
169
|
+
def reset_pot(self):
|
170
|
+
self.pot = 0
|
171
|
+
self.current_bet = 0
|
172
|
+
self.bets = {player: -1 for player in range(1, self.num_players + 1)}
|
173
|
+
|
174
|
+
def set_round(self, round):
|
175
|
+
self.round = round
|
176
|
+
|
177
|
+
def get_game_state(self, player_num):
|
178
|
+
"""
|
179
|
+
Get the game state for a specific player.
|
180
|
+
|
181
|
+
Parameters:
|
182
|
+
- player_num (int): The player number.
|
183
|
+
|
184
|
+
Returns:
|
185
|
+
- dict: The game state for the specified player.
|
186
|
+
"""
|
187
|
+
player_state = {
|
188
|
+
"round": self.round,
|
189
|
+
"player_hand": [str(card) for card in self.player_hands[player_num]],
|
190
|
+
"community_cards": [str(card) for card in self.community_cards],
|
191
|
+
"current_bet": self.current_bet,
|
192
|
+
"pot": self.pot,
|
193
|
+
"current_player": self.current_player,
|
194
|
+
"current_dealer": self.dealer,
|
195
|
+
"bets": self.bets,
|
196
|
+
"cum_bets": self.cum_bets,
|
197
|
+
"chips": {player.player_number: player.chips for player in self.players.values() },
|
198
|
+
"probabilities": self.draw_probabilities(self.community_cards)
|
199
|
+
}
|
200
|
+
|
201
|
+
return player_state
|
202
|
+
def get_showdown_game_state(self):
|
203
|
+
"""
|
204
|
+
Get the game state for a specific player.
|
205
|
+
|
206
|
+
Parameters:
|
207
|
+
- player_num (int): The player number.
|
208
|
+
|
209
|
+
Returns:
|
210
|
+
- dict: The game state for the specified player.
|
211
|
+
"""
|
212
|
+
player_state = {
|
213
|
+
"round": self.round,
|
214
|
+
"players_hand": {player_num: [str(card) for card in self.player_hands[player_num]] for player_num in self.players.keys()},
|
215
|
+
"community_cards": [str(card) for card in self.community_cards],
|
216
|
+
"winner": self.determine_winner(),
|
217
|
+
"pot": self.pot,
|
218
|
+
"rank": self.winning_rank,
|
219
|
+
"chips": {player.player_number: player.chips for player in self.players.values() }
|
220
|
+
}
|
221
|
+
|
222
|
+
return player_state
|
223
|
+
|
224
|
+
def deal_hole_cards(self):
|
225
|
+
for _ in range(2):
|
226
|
+
for _ , hand in self.player_hands.items():
|
227
|
+
hand.append(self.deck.deal_card())
|
228
|
+
|
229
|
+
|
230
|
+
def deal_community_cards(self, num_cards):
|
231
|
+
for _ in range(num_cards):
|
232
|
+
self.community_cards.append(self.deck.deal_card())
|
233
|
+
|
234
|
+
def determine_winner(self):
|
235
|
+
all_hands = [hand + self.community_cards for hand in self.player_hands.values()]
|
236
|
+
|
237
|
+
best_hands = [rank_hand(player_hand) for player_hand in all_hands]
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
# Sort the best hands by rank and then by the highest card value
|
242
|
+
sorted_best_hands = sorted(enumerate(best_hands), key=lambda x: (x[1][0], x[1][1]), reverse=True)
|
243
|
+
|
244
|
+
# Determine the winner
|
245
|
+
winner_key = list(self.player_hands.keys())[sorted_best_hands[0][0]] # Get the key of the first (highest) hand
|
246
|
+
winning_hand = all_hands[sorted_best_hands[0][0]]
|
247
|
+
|
248
|
+
# Update winning_hand_frequency dictionary based on the hand rank
|
249
|
+
rank, _ = best_hands[sorted_best_hands[0][0]]
|
250
|
+
rank_mapping = {
|
251
|
+
10: "Royal Flush",
|
252
|
+
9: "Straight Flush",
|
253
|
+
8: "Four of a Kind",
|
254
|
+
7: "Full House",
|
255
|
+
6: "Flush",
|
256
|
+
5: "Straight",
|
257
|
+
4: "Three of a Kind",
|
258
|
+
3: "Two Pair",
|
259
|
+
2: "One Pair",
|
260
|
+
1: "High Card",
|
261
|
+
}
|
262
|
+
print("Winning Hand:" + rank_mapping[rank] + " with rank " + str(rank))
|
263
|
+
self.winning_rank = rank_mapping[rank]
|
264
|
+
print("| ", end="")
|
265
|
+
for i in winning_hand:
|
266
|
+
print(i.print_card(),end =" | ")
|
267
|
+
print()
|
268
|
+
|
269
|
+
return winner_key
|
270
|
+
|
271
|
+
def place_bet(self, player_number, bet_amount):
|
272
|
+
self.players[player_number].chips -= bet_amount
|
273
|
+
self.pot += bet_amount
|
274
|
+
self.bets[player_number] += bet_amount
|
275
|
+
self.cum_bets[player_number] += bet_amount
|
276
|
+
if (not self.all_in):
|
277
|
+
self.current_bet = max(self.bets.values())
|
278
|
+
|
279
|
+
def give_winnings(self, player_num):
|
280
|
+
self.players[player_num].chips += self.pot
|
281
|
+
self.pot = 0
|
282
|
+
|
283
|
+
|
284
|
+
def switch_player(self):
|
285
|
+
self.current_player = (self.current_player % self.num_players) + 1
|
286
|
+
|
287
|
+
@staticmethod
|
288
|
+
def draw_probabilities(cards):
|
289
|
+
probabilities = {
|
290
|
+
"Royal Flush": 0,
|
291
|
+
"Straight Flush": 0,
|
292
|
+
"Four of a Kind": 0,
|
293
|
+
"Full House": 0,
|
294
|
+
"Flush": 0,
|
295
|
+
"Straight": 0,
|
296
|
+
"Three of a Kind": 0,
|
297
|
+
"Two Pair": 0,
|
298
|
+
"One Pair": 0,
|
299
|
+
"High Card": 0,
|
300
|
+
}
|
301
|
+
|
302
|
+
rank_mapping = {
|
303
|
+
10: "Royal Flush",
|
304
|
+
9: "Straight Flush",
|
305
|
+
8: "Four of a Kind",
|
306
|
+
7: "Full House",
|
307
|
+
6: "Flush",
|
308
|
+
5: "Straight",
|
309
|
+
4: "Three of a Kind",
|
310
|
+
3: "Two Pair",
|
311
|
+
2: "One Pair",
|
312
|
+
1: "High Card",
|
313
|
+
}
|
314
|
+
deck = Deck()
|
315
|
+
deck.cards = [card for card in deck.cards if all(card.name != other_card.name for other_card in cards)]
|
316
|
+
i = 0
|
317
|
+
for card1 in deck.cards:
|
318
|
+
for card2 in deck.cards:
|
319
|
+
if card1 != card2:
|
320
|
+
temp_cards = cards + [card1 , card2]
|
321
|
+
rank, _ = rank_hand(temp_cards)
|
322
|
+
probabilities[rank_mapping[rank]] += 1
|
323
|
+
i+=1
|
324
|
+
|
325
|
+
for key in probabilities:
|
326
|
+
probabilities[key] /= i
|
327
|
+
|
328
|
+
return probabilities
|
329
|
+
|
330
|
+
def check_bets_matched(self):
|
331
|
+
if (max(self.bets.values()) < 0):
|
332
|
+
return False
|
333
|
+
# Iterate through players still in the round
|
334
|
+
for player_num, in_round in self.players_in_round.items():
|
335
|
+
if in_round:
|
336
|
+
# Check if the player's bet matches the current bet
|
337
|
+
if self.bets[player_num] < self.current_bet:
|
338
|
+
return False
|
339
|
+
# If all players' bets match the current bet, return True
|
340
|
+
return True
|