-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathblackjack_game.py
More file actions
282 lines (232 loc) · 10.2 KB
/
blackjack_game.py
File metadata and controls
282 lines (232 loc) · 10.2 KB
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
import random
import json
# import redis
class BlackjackGame:
def __init__(self, state=None):
if state:
self.load_state(state)
else:
self.initialize_new_game()
def initialize_new_game(self):
self.player_hand = []
self.dealer_hand = []
self.player_score = 0
self.dealer_score = 0
self.player_chips = 0
self.bet = 0
self.continue_betting = True
self.deck = self.card_deck()
self.winner = None # In reference to the player winning
self.message = ""
self.game_status = "start"
def load_state(self, state):
self.player_hand = state.get('player_hand', [])
self.dealer_hand = state.get('dealer_hand', [])
self.player_score = state.get('player_score', 0)
self.split_player_scores = state.get('split_player_scores', [0, 0])
self.dealer_score = state.get('dealer_score', 0)
self.player_chips = state.get('player_chips', 0)
self.bet = state.get('bet', 0)
self.continue_betting = state.get('continue_betting', True)
# Ensure deck is properly initialized
deck_data = state.get('deck', None)
if deck_data is not None and isinstance(deck_data, list):
self.deck = self.card_deck(deck_data)
else:
self.deck = self.card_deck()
self.winner = state.get('winner')
self.message = state.get('message')
self.game_status = state.get('game_status', "start")
self.split_player_hand = state.get('split_player_hand', [])
def serialize_state(self):
return {
'player_hand': self.player_hand,
'dealer_hand': self.dealer_hand,
'player_score': self.player_score,
'split_player_scores': self.split_player_scores,
'dealer_score': self.dealer_score,
'player_chips': self.player_chips,
'bet': self.bet,
'continue_betting': self.continue_betting,
'deck': self.deck.deck,
'winner': self.winner,
'message': self.message or '',
'game_status': self.game_status or 'start',
'split_player_hand': self.split_player_hand
}
class card_deck:
def __init__(self, deck=None):
self.card_categories = ['hearts', 'diamonds', 'clubs', 'spades']
self.cards_list = ["2", "3", "4", "5", "6", "7",
"8", "9", "10", "jack", "queen", "king", "ace"]
if deck is None:
self.deck = [([card, category])
for category in self.card_categories for card in self.cards_list]
else:
self.deck = deck
@staticmethod
def card_value(card):
if card[0] in ['jack', 'queen', 'king']:
return 10
elif card[0] == 'ace':
return 11 # Adjusted to return 11 for Aces
else:
return int(card[0])
# Imagine a dealer is shuffling the deck and dealing the cards here ---
def deal_initial_hands(self):
if self.game_status == "ongoing":
return
random.shuffle(self.deck.deck)
self.player_hand = [self.deck.deck.pop(), self.deck.deck.pop()]
self.dealer_hand = [self.deck.deck.pop(), self.deck.deck.pop()]
# Use calculate_aces to adjust scores dynamically
self.player_score = self.calculate_aces(self.player_hand)
self.dealer_score = self.calculate_aces(self.dealer_hand)
def calculate_aces(self, hand):
score = sum(self.card_value(card) for card in hand)
aces_count = sum(1 for card in hand if self.card_value(card) == 11)
while score > 21 and aces_count > 0:
score -= 10
aces_count -= 1
return score
def get_action(self):
return self.action
def set_action(self, action):
self.action = action
return self.action
def process_hands_for_split(self):
split_player_hand = []
iteration_counter = 0
for i in self.player_hands:
self.set_action("stay")
self.continue_betting = True
self.player_score = self.split_player_scores[iteration_counter]
self.player_hand = i
self.result(self.bet) # run evaluation
split_player_hand.extend(i)
self.split_player_hand = split_player_hand
iteration_counter += 1
def result(self, bet):
if self.continue_betting is False: # if the player has already stayed or busted
return
self.game_status = "ongoing" # Flag to signal game is ongoing
self.bet = bet
message = ""
self.serialize_state()
# This specifically checks if split is True from front-end - not great variable name at moment
if self.get_action() == True:
# Ensure the player has exactly two cards of the same rank to split
if len(self.player_hand) == 2 and self.card_value(self.player_hand[0]) == self.card_value(self.player_hand[1]):
# Splitting the hand into two hands
hand_one = [self.player_hand[0]]
hand_two = [self.player_hand[1]]
# Dealing a new card to each hand
hand_one_new_card = self.deck.deck.pop()
hand_two_new_card = self.deck.deck.pop()
hand_one.append(hand_one_new_card)
hand_two.append(hand_two_new_card)
# Update the player's hands to the new split hands
# Note the change to player_hands to indicate multiple hands
self.player_hands = [hand_one, hand_two]
# Recalculate scores for both hands (if needed)
# This is a placeholder; actual implementation depends on how you want to handle scores for split hands
# 11 is to account for the value of an ace
self.split_player_scores = [self.calculate_aces(
hand_one), self.calculate_aces(hand_two)]
self.process_hands_for_split()
else:
pass
elif self.get_action() == "hit":
# Add a new card to the player's hand
new_card = self.deck.deck.pop()
self.player_hand.append(new_card)
# Recalculate player's score after adding the new card
self.player_score = sum(self.card_value(card)
for card in self.player_hand)
# Adjust for ace after recalculating score
# if 'ace' in [card[0] for card in self.player_hand] and self.player_score + 10 <= 21:
# self.player_score += 10
# Correcting the logic to handle aces when the player's score is over 21
self.player_score = self.calculate_aces(self.player_hand)
# Check if player busts after hitting
if self.player_score > 21:
self.message = "Bust! Dealer wins."
self.player_chips -= self.bet
self.continue_betting = False
self.game_status = "start"
self.serialize_state()
elif self.get_action() == "stay":
while self.dealer_score < 17:
new_card = self.deck.deck.pop()
self.dealer_hand.append(new_card)
self.dealer_score += self.card_value(new_card)
self.dealer_score = self.calculate_aces(self.dealer_hand)
self.serialize_state()
if self.player_score == 21 and len(self.player_hand) == 2:
if self.dealer_score == 21 and len(self.dealer_hand) == 2:
self.message = "Push. It is a tie."
else:
self.message = "Blackjack! Player wins!"
self.player_chips += self.bet * 1.5
elif self.dealer_score > 21 or self.player_score > self.dealer_score:
self.message = "Player wins!"
self.player_chips += self.bet
elif self.dealer_score > self.player_score:
self.message = "Dealer wins."
self.player_chips -= self.bet
else:
self.message = "Push. It is a tie."
self.continue_betting = False
self.game_status = "start"
self.serialize_state()
def who_wins(self, winner):
self.winner = winner
print(self.winner, "wins")
return game_state
""" Everything below this is only for testing purposes """
def test_blackjack_games(chips):
game = BlackjackGame()
game.player_chips = chips
game.deal_initial_hands()
print("Player Chips:", game.player_chips)
bet = int(input("Amount to bet: "))
## the front end will make these queries ##
player_stayed_flag = False
while True:
# print(game.deck.deck)
state = game.serialize_state()
# Serialize the state to a JSON string
state_json = json.dumps(state)
# print(state_json)
# Save the JSON string to a file
print("Player Chips:", state['player_chips'])
print(bet)
print("Dealer's First Card:", state['dealer_hand'][0])
print("Player's Hand:", state['player_hand'])
print("Player's Score:", state['player_score'])
# print("state", state)
# Check if the player has not stayed yet
if not player_stayed_flag and state['player_score'] <= 21:
action = input("Player action (hit/stay): ").lower()
if action not in ['hit', 'stay']:
print("Invalid action. Please type 'hit' or 'stay'.")
continue
game.set_action(action)
if action == 'stay':
player_stayed_flag = True # Set the flag if the player chooses to stay
# Process the action and get the result
game.result(bet) # play hand
print(state['message'])
print(state['player_score'])
print(state['dealer_score'])
print(f"Final chip count: {state['player_chips']}")
if int(state['player_chips']) <= 0:
test_blackjack_games(11000) # new game
if state['message'] != '':
break
test_blackjack_games(state['player_chips'])
def main():
# game = BlackjackGame()
test_blackjack_games(10000)
if __name__ == '__main__':
main()