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.
@@ -0,0 +1,415 @@
1
+ # server.py
2
+
3
+ import socket
4
+ import threading
5
+ from .poker_host import Player, TexasHoldem
6
+ import json
7
+ import time
8
+
9
+ class ServerPlayer(Player):
10
+ def __init__(self, player_number, chips=100, client_socket=None):
11
+ super().__init__(player_number, chips)
12
+ # ServerPlayer info is redundant, really only need the player_number and client_socket
13
+ self.client_socket = client_socket
14
+
15
+ # Server Class
16
+ class Server:
17
+ def __init__(self,num_players):
18
+ # initialize server socket with localhost ip address on port 5555
19
+ self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
20
+ self.host = "127.0.0.1"
21
+ self.port = 5555
22
+ self.server_socket.bind((self.host, self.port))
23
+ self.server_socket.listen(num_players)
24
+ print("Server is listening for connections...")
25
+ # Array for player socket
26
+ self.players = {}
27
+ # Game imported from poker_host
28
+ self.game = TexasHoldem(num_players)
29
+ self.num_players = num_players
30
+ self.num_players_connected = 0
31
+ self.lock = threading.Lock()
32
+ self.dealer_check_event = threading.Event()
33
+ # Players Recieved Message Counter
34
+ self.prm = 0
35
+ # Condition to play more rounds of poker
36
+ self.keep_playing = True
37
+ # Keeps track of players leaving
38
+ self.players_connected = True
39
+
40
+
41
+ # Function to send game state from the server to the client. Game state includes the board information as well as whose turn it is. Game state info is in json format
42
+ def send_game_state(self, player):
43
+ game_state = self.game.get_game_state(player.player_number)
44
+ json_data = json.dumps(game_state)
45
+ print(f"Sending game state to Player {player.player_number}: {json_data}")
46
+ player.client_socket.send(json_data.encode())
47
+
48
+ def reset_thread_management(self):
49
+ self.lock = threading.Lock()
50
+ self.dealer_check_event = threading.Event()
51
+
52
+ # PRM: Players recieved message. Reset to 0 for new message
53
+ def reset_prm_counter(self):
54
+ self.prm = 0
55
+
56
+ def send_game_state_to_all(self):
57
+ for _ , player in self.players.items():
58
+ self.send_game_state(player)
59
+
60
+ def send_global_message(self, message):
61
+ for _ , player in self.players.items():
62
+ player.client_socket.send(str(message).encode())
63
+
64
+ def check_for_early_win(self):
65
+ return list(self.game.players_in_round.values()).count(True) == 1
66
+
67
+ def get_early_winner(self):
68
+ for key, value in self.game.players_in_round.items():
69
+ if value is True:
70
+ return key
71
+
72
+ def round(self, name):
73
+
74
+ # all_in() checks for bet_amounts that empty a players chips
75
+ def all_in(player, bet_amount):
76
+ # Get the players chips
77
+ temp_chips = self.game.get_game_state(player.player_number)['chips'][player.player_number]
78
+
79
+ # Check if the bet is too large
80
+ if ((temp_chips - bet_amount) <= 0):
81
+ print(f"player: {player.player_number}")
82
+ print(f"chips: {temp_chips}")
83
+ print(f"bet flag: {bet_amount}")
84
+
85
+ # Player puts in all their chips
86
+ bet_amount = temp_chips
87
+ print(f"Player {player.player_number} is ALL IN!.")
88
+ self.send_global_message(f"Player {player.player_number} is ALL IN!.")
89
+ self.game.all_in = True
90
+ # current bet is the amount of chips they can bet + the chips they already bet = all their chips
91
+ self.game.current_bet = bet_amount + self.game.bets[player.player_number]
92
+ # Give back chips from side pot
93
+ # Fix Current pot
94
+ for player_number , other_player_bet in self.game.bets.items():
95
+ if other_player_bet > self.game.current_bet:
96
+ # Calculate the difference between the current bet and the players bets that are higher
97
+ diff = other_player_bet - self.game.current_bet
98
+ print(f"Diff: {diff}")
99
+ # Give back chips that go over current bet
100
+ self.game.cum_bets[player_number] -= diff
101
+ self.game.players[player_number].chips += diff
102
+ other_player_bet = self.game.current_bet
103
+ self.players[player_number].client_socket.send(str(f"GIVE~{diff}~").encode())
104
+ print(f"Gave player {player_number} {diff} chips")
105
+
106
+ return bet_amount
107
+
108
+ self.game.round = name
109
+ self.send_global_message(f"-----------------------------------------------------------------------\n{name} Round")
110
+ self.game.set_round(name)
111
+ print(f"\nRound Called: {name}")
112
+ # Big/Small Blind
113
+ if (name == "Pre-flop"):
114
+ for i in range(2,0,-1):
115
+ player = self.players[self.game.current_player]
116
+ if (self.game.bets[player.player_number] < 0):
117
+ self.game.bets[player.player_number] = 0
118
+ self.game.place_bet(player.player_number, i)
119
+ # Notify players of bets
120
+ if i == 1:
121
+ print(f"Player {player.player_number} placed the small blind.")
122
+ self.send_global_message(f"Player {player.player_number} placed the small blind.")
123
+ player.client_socket.send("SMALL".encode())
124
+ else:
125
+ print(f"Player {player.player_number} placed the big blind.")
126
+ self.send_global_message(f"Player {player.player_number} placed the big blind.")
127
+ player.client_socket.send("BIG".encode())
128
+ self.game.switch_player()
129
+
130
+ # Check if betting needs to continue
131
+ while(not self.game.check_bets_matched()):
132
+ # Set the current player
133
+ player = self.players[self.game.current_player]
134
+ if (self.game.bets[player.player_number] < self.game.current_bet):
135
+ # Send all users game state. The current player will be the only one who can interact
136
+ self.send_game_state_to_all()
137
+
138
+ # If the player folded, pass them
139
+ if self.game.players_in_round[player.player_number] == True:
140
+
141
+ # Get the active players choice
142
+ action = player.client_socket.recv(1024).decode()
143
+ if action == "1": # Check/Call
144
+ if (self.game.bets[player.player_number] < 0):
145
+ self.game.bets[player.player_number] = 0
146
+ if(self.game.bets[player.player_number] == self.game.current_bet):
147
+ print(f"Player {player.player_number} checks.")
148
+ self.send_global_message(f"Player {player.player_number} checks.")
149
+ else:
150
+ print(f"Player {player.player_number} calls.")
151
+ self.send_global_message(f"Player {player.player_number} checks.")
152
+
153
+ bet_amount = self.game.current_bet - self.game.bets[player.player_number]
154
+
155
+
156
+ # All in
157
+ bet_amount = all_in(player, bet_amount)
158
+
159
+
160
+ print(f"Player {player.player_number} bets {bet_amount} chips.")
161
+ self.game.place_bet(player.player_number, bet_amount)
162
+ elif action == "2": # Raise Bet
163
+ if (self.game.bets[player.player_number] < 0):
164
+ self.game.bets[player.player_number] = 0
165
+ bet_amount = int(player.client_socket.recv(1024).decode()) + self.game.current_bet
166
+
167
+ # All in
168
+ bet_amount = all_in(player, bet_amount)
169
+
170
+ self.game.place_bet(player.player_number, bet_amount)
171
+ print(f"Player {player.player_number} bets {bet_amount} chips.")
172
+ self.send_global_message(f"Player {player.player_number} bets {bet_amount} chips.")
173
+
174
+ elif action == "3": # Fold
175
+ print(f"Player {player.player_number} folds.")
176
+ self.send_global_message(f"Player {player.player_number} folds.")
177
+ self.game.players_in_round[player.player_number] = False
178
+ # self.players[i].hand = [] # Remove player's hand
179
+ else: # Theoretically never gets called
180
+ print("Invalid choice. Please choose again.")
181
+ print(f"Bets matched: {self.game.check_bets_matched()}")
182
+ print(f"Bets: {self.game.bets}")
183
+ print(f"Early Win Detected: {self.check_for_early_win()}")
184
+
185
+
186
+ if (self.game.check_bets_matched()):
187
+ break
188
+ if (self.check_for_early_win()):
189
+ winner = self.get_early_winner()
190
+ print(f"Winner (by betting): {winner}")
191
+ # self.send_global_message("END")
192
+ break
193
+ else:
194
+ self.game.switch_player()
195
+ print(f"Current Player: {self.game.current_player}")
196
+ # self.send_game_state(self.players[self.game.current_player])
197
+ print('\n')
198
+ else:
199
+ pass
200
+ else:
201
+ self.game.switch_player()
202
+ # if (self.game.check_bets_matched()):
203
+ # break
204
+ # Logic that the server runs to interact with the clients and handle game management
205
+ def handle_client(self, player):
206
+ def keep_playing_game(client_socket):
207
+ with self.lock:
208
+ self.game.reset_bets()
209
+ self.game.reset_players()
210
+ self.game.reset_deck()
211
+ self.game.reset_pot()
212
+ print(f"Player has sent their response")
213
+ answer = client_socket.recv(1024).decode()
214
+ print(f"Answer: {answer}")
215
+ if str(answer) == "n":
216
+ print("Game Ending.")
217
+ self.keep_playing = False
218
+ time.sleep(0.1)
219
+
220
+
221
+ def game_ended_early(player_number):
222
+ # Determine who won
223
+ winner = None
224
+ for key, value in self.game.players_in_round.items():
225
+ if value == True:
226
+ winner = key
227
+ break
228
+
229
+ pot = self.game.pot
230
+ # print(f"pot: {pot}")
231
+ # Send showdown information for client to display
232
+ if (player_number == self.game.dealer):
233
+
234
+ print(f"Player {winner} has won!")
235
+ self.send_global_message(f"All other players have folded. Player {winner} has won {pot} chips!")
236
+ self.game.give_winnings(winner)
237
+
238
+ for player_num , player in self.players.items():
239
+ if (player_num == winner):
240
+ player.client_socket.send(str(f"GIVE~{pot}~\n").encode())
241
+ time.sleep(0.1)
242
+ player.client_socket.send(str("WIN").encode())
243
+ else:
244
+ time.sleep(0.1)
245
+ player.client_socket.send(str("LOSS").encode())
246
+ self.game.dealer = (self.game.dealer % self.game.num_players) + 1
247
+ self.reset_prm_counter()
248
+
249
+
250
+ client_socket = player.client_socket
251
+ player_number = player.player_number
252
+
253
+ client_socket.send(str(player_number).encode())
254
+
255
+ # Wait for 2 players before interacting with the client further
256
+ while self.num_players_connected != self.game.num_players:
257
+ pass
258
+
259
+
260
+ # With self.lock, .set(), .wait(), .clear() used to lock threads so all players catch up after rounds
261
+ while self.keep_playing:
262
+ # Send game start code
263
+
264
+ with self.lock:
265
+ client_socket.send("GAME STARTED".encode())
266
+ self.prm+=1
267
+ print(f"PRM: {self.prm}, Num Players: {self.num_players_connected}")
268
+ if (self.prm==self.num_players_connected):
269
+ self.reset_prm_counter()
270
+ self.dealer_check_event.set()
271
+ self.dealer_check_event.wait()
272
+ self.dealer_check_event.clear()
273
+
274
+ print("Checkpoint 1")
275
+
276
+ # Pre-flop round
277
+ with self.lock:
278
+ if player_number == self.game.dealer:
279
+ self.game.deal_hole_cards()
280
+
281
+ self.round("Pre-flop")
282
+ print("Pre-Flop Betting Ended")
283
+ self.send_global_message("Pre-Flop Betting Ended")
284
+ self.game.deal_community_cards(3)
285
+ self.game.reset_bets()
286
+ self.dealer_check_event.set()
287
+
288
+ self.dealer_check_event.wait()
289
+ self.dealer_check_event.clear()
290
+
291
+ print("Checkpoint 2")
292
+
293
+ # Flop round
294
+ if not self.check_for_early_win():
295
+ with self.lock:
296
+ if player_number == self.game.dealer:
297
+ if (not self.game.all_in):
298
+ self.round("Flop")
299
+ print("Flop Betting Ended")
300
+ self.send_global_message("Flop Betting Ended")
301
+ self.game.deal_community_cards(1)
302
+ self.game.reset_bets()
303
+ print(self.game.bets)
304
+ self.dealer_check_event.set()
305
+ self.dealer_check_event.wait()
306
+ self.dealer_check_event.clear()
307
+ else:
308
+ game_ended_early(player_number)
309
+ keep_playing_game(client_socket)
310
+ continue
311
+
312
+ print("Checkpoint 3")
313
+
314
+ # Turn round
315
+
316
+ if not self.check_for_early_win():
317
+ with self.lock:
318
+ if player_number == self.game.dealer:
319
+ if (not self.game.all_in):
320
+ self.round("Turn")
321
+ print("Turn Betting Ended")
322
+ self.send_global_message("Turn Betting Ended")
323
+ self.game.deal_community_cards(1)
324
+ self.game.reset_bets()
325
+ print(self.game.bets)
326
+ self.dealer_check_event.set()
327
+ self.dealer_check_event.wait()
328
+ self.dealer_check_event.clear()
329
+ else:
330
+ game_ended_early(player_number)
331
+ keep_playing_game(client_socket)
332
+ continue
333
+
334
+ print("Checkpoint 4")
335
+
336
+ # River round
337
+ if not self.check_for_early_win():
338
+ with self.lock:
339
+ if player_number == self.game.dealer:
340
+ if (not self.game.all_in):
341
+ self.round("River")
342
+ print("River Betting Ended")
343
+ self.send_global_message("River Betting Ended")
344
+ self.game.reset_bets()
345
+ print(self.game.bets)
346
+ self.dealer_check_event.set()
347
+ self.dealer_check_event.wait()
348
+ self.dealer_check_event.clear()
349
+ else:
350
+ game_ended_early(player_number)
351
+ keep_playing_game(client_socket)
352
+ continue
353
+
354
+ print("Checkpoint 5\n")
355
+
356
+ # SHOWDOWN
357
+ with self.lock:
358
+ if player_number == self.game.dealer:
359
+ print("Showdown!")
360
+ self.game.set_round("Showdown!")
361
+ self.send_global_message("Showdown!")
362
+
363
+ # Determine who won
364
+ winner = self.game.determine_winner()
365
+ print(f"Player {winner} has won!")
366
+ game_state = self.game.get_showdown_game_state()
367
+ self.game.give_winnings(winner)
368
+
369
+ # Send showdown information for client to display
370
+ self.send_global_message(f"Player {winner} has won {game_state['pot']} chips! with a {game_state['rank']}")
371
+ for player_num , player in self.players.items():
372
+ json_data = json.dumps(game_state)
373
+ print(f"Sending showdown game state to Player {player.player_number}: {json_data}")
374
+ player.client_socket.send(json_data.encode())
375
+ if (player_num == winner):
376
+ player.client_socket.send(str("WIN").encode())
377
+ else:
378
+ player.client_socket.send(str("LOSS").encode())
379
+ self.dealer_check_event.set()
380
+
381
+ print("Checkpoint 6")
382
+
383
+ self.dealer_check_event.wait()
384
+ self.dealer_check_event.clear()
385
+
386
+ keep_playing_game(client_socket)
387
+
388
+
389
+ # If only one player has chips end the game
390
+ if self.check_for_early_win():
391
+ print("Only one player has chips. Game ending now.")
392
+ self.send_global_message("Only one player has chips. Game ending now.")
393
+ break
394
+
395
+
396
+
397
+ # Close connection to client when the game is over
398
+ try:
399
+ self.send_global_message("END")
400
+ finally:
401
+ print(f"Connection from {client_socket.getpeername()} has been closed.")
402
+ client_socket.close()
403
+ self.players_connected = False
404
+
405
+ def accept_connections(self):
406
+ # Repeatedly check for clients that will join
407
+ while self.players_connected and self.num_players_connected < self.num_players:
408
+ client_socket, addr = self.server_socket.accept()
409
+ print(f"Connection from {addr} has been established.")
410
+ # Add clients to players array for reference later
411
+ self.num_players_connected += 1
412
+ player = ServerPlayer(self.num_players_connected, chips=100*self.num_players_connected, client_socket = client_socket)
413
+ self.players[self.num_players_connected] = player
414
+ # Start a new threat for each client
415
+ threading.Thread(target=self.handle_client, args=(player,)).start()