class OptionsFrame(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.parent = parent self.games_amount = tk.IntVar(value=100) self.use_decision_table_value = tk.BooleanVar() self.dealer_threshold = tk.IntVar(value=17) self.player_threshold = tk.IntVar(value=17) self.result_percentage = tk.StringVar() self.decision_table_value = tk.BooleanVar() self.games_amount_label = tk.Label( self, text='Number of rounds to play (max 10000):', bg='#cccccc') self.games_amount_entry = tk.Entry(self, width=5, textvariable=self.games_amount) self.use_decision_table_checkbox = tk.Checkbutton( self, text='Use decision table for player', command=self.use_decision_table_checkbox_clicked, variable=self.use_decision_table_value, bg='#cccccc') self.dealer_threshold_label = tk.Label( self, text='Dealer\'s threshold for hitting:', bg='#cccccc') self.dealer_threshold_entry = tk.Entry( self, width=2, textvariable=self.dealer_threshold) self.player_threshold_label = tk.Label( self, text='Player\'s threshold for hitting:', bg='#cccccc') self.player_threshold_entry = tk.Entry( self, width=2, textvariable=self.player_threshold) self.simulation_button = tk.Button( self, text='Simulate', command=self.simulate_button_pressed, bg='#cccccc') self.log_text = tk.Text(self, height=10, width=32, cursor="arrow") self.log_scrollbar = tk.Scrollbar(self) self.result_percentage_label = tk.Label( self, textvariable=self.result_percentage, bg='#cccccc') self.decision_table_frame = DecisionTableFrame(self, bg='#cccccc') self.decision_table_aces_frame = DecisionTableAcesFrame(self, bg='#cccccc') self.games_amount_label.grid(row=0, column=0, sticky='w', padx=2, pady=(6, 0)) self.games_amount_entry.grid(row=0, column=1, sticky='w', padx=2) self.use_decision_table_checkbox.grid(row=1, column=0, sticky='w', padx=2) self.dealer_threshold_label.grid(row=2, column=0, sticky='w', padx=2) self.dealer_threshold_entry.grid(row=2, column=1, sticky='w', padx=2) self.player_threshold_label.grid(row=3, column=0, sticky='w', padx=2) self.player_threshold_entry.grid(row=3, column=1, sticky='w', padx=2) self.simulation_button.grid(row=5, column=0, sticky='s', padx=(50, 0), pady=(12, 0)) self.log_text.grid(row=6, columnspan=2, column=0, sticky='nsw', padx=2) self.log_scrollbar.grid(row=6, column=2, sticky='nsw') self.log_scrollbar.config(command=self.log_text.yview) self.log_text.configure(yscrollcommand=self.log_scrollbar.set, state='disabled') self.simulation_game = Game() def use_decision_table_checkbox_clicked(self): if self.use_decision_table_value.get(): self.player_threshold_label.configure(foreground='gray') self.player_threshold_entry.grid_forget() self.decision_table_frame.grid(row=8, column=0, columnspan=2, sticky='s') self.decision_table_aces_frame.grid(row=9, column=0, columnspan=2, sticky='s') else: self.player_threshold_label.configure(foreground='black') self.player_threshold_entry.grid(row=3, column=1, sticky='w') self.decision_table_frame.grid_forget() self.decision_table_aces_frame.grid_forget() def simulate_button_pressed(self): if self.games_amount.get() > 10_000: self.games_amount.set(10_000) self.log_text.configure(state='normal') self.log_text.delete('1.0', tk.END) self.log_text.configure(state='disabled') win_counter = 0 tie_counter = 0 loss_counter = 0 for i in range(self.games_amount.get()): self.simulation_game.start() result = self.play_simulation(self.dealer_threshold.get(), self.player_threshold.get(), self.use_decision_table_value.get()) if result == 'WIN': win_counter += 1 if result == 'TIE': tie_counter += 1 if result == 'LOSS': loss_counter += 1 round_summary = 'Dealer: {' cards_code = [] for card in self.simulation_game.dealer_hand.cards: cards_code.append(str(card.code + card.suit[0])) round_summary += ' '.join(cards_code) + '} (' + str( self.simulation_game.dealer_hand.value) + ')\nPlayer: {' cards_code = [] for card in self.simulation_game.player_hand.cards: cards_code.append(str(card.code + card.suit[0])) round_summary += ' '.join(cards_code) + '} (' + str( self.simulation_game.player_hand.value) + ')\n' round_summary += result + '\n***\n' self.simulation_game.put_cards_back() self.log_text.configure(state='normal') self.log_text.insert(tk.END, round_summary + '\n') self.log_text.configure(state='disabled') win_percentage = round(win_counter / self.games_amount.get() * 100, 3) tie_percentage = round(tie_counter / self.games_amount.get() * 100, 3) loss_percentage = round(loss_counter / self.games_amount.get() * 100, 3) self.result_percentage.set('Win percentage: ' + str(win_percentage) + '%' + '| Tie: ' + str(tie_percentage) + '%' + '| Lose: ' + str(loss_percentage) + '%') self.result_percentage_label.grid(row=7, column=0, columnspan=2, sticky='w') def play_simulation(self, dealer_threshold=17, player_threshold=17, use_decision_table=False): player_hand_value = self.simulation_game.player_hand.value dealer_hand_value = self.simulation_game.dealer_hand.value dealer_visible_card_value = self.simulation_game.dealer_hand.cards[ 1].value if player_hand_value != 21: if use_decision_table: if self.simulation_game.player_hand.aces > 0: decision_table = self.decision_table_aces_frame.decision_table_aces_value_list else: decision_table = self.decision_table_frame.decision_table_value_list decision = decision_table[20 - player_hand_value][ dealer_visible_card_value - 2] while decision != 'S': self.simulation_game.player_hand.add_card( self.simulation_game.deck.deal()) player_hand_value = self.simulation_game.player_hand.value if player_hand_value > 20: decision = 'S' else: decision = decision_table[20 - player_hand_value][ dealer_visible_card_value - 2] else: while player_hand_value < player_threshold: self.simulation_game.player_hand.add_card( self.simulation_game.deck.deal()) player_hand_value = self.simulation_game.player_hand.value if player_hand_value > 21: return 'LOSS' while (dealer_hand_value < player_hand_value) and dealer_hand_value < dealer_threshold: self.simulation_game.dealer_hand.add_card( self.simulation_game.deck.deal()) dealer_hand_value = self.simulation_game.dealer_hand.value if dealer_hand_value > 21: return 'WIN' if dealer_hand_value == player_hand_value: return 'TIE' if dealer_hand_value > player_hand_value: return 'LOSS' else: return 'WIN'
class GameFrame(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.parent = parent self.hand_frame_height = 315 self.result_text = tk.StringVar() self.image_manager = ImageManager() self.result_label = tk.Label(self, font=('', 24), textvariable=self.result_text) self.dealer_hand_frame = HandFrame(self, bg='#f0f0f0', bd=10) self.player_hand_frame = HandFrame(self, bg='#f0f0f0', bd=10) self.hit_button = tk.Button(self, text='Hit', font=('', 16), command=self.hit_button_pressed) self.pass_button = tk.Button(self, text='Pass', font=('', 16), command=self.pass_button_pressed) self.play_button = tk.Button(self, text='Play', font=('', 20), command=self.play_button_pressed) self.parent = parent self.game = Game() self.resized_card_images = {} self.hidden_card = Card('', '', 'red_back', 0) self.add_card_image(self.hidden_card) self.play_button.place(rely=0.47, relx=0.46) def update_hands(self, dealer_hand, player_hand, hidden_card=True): self.dealer_hand_frame.place(rely=0.10, relheight=0.35, relwidth=1) self.dealer_hand_frame.show_cards(dealer_hand, hidden_card) self.player_hand_frame.place(rely=0.55, relheight=0.35, relwidth=1) self.player_hand_frame.show_cards(player_hand, False) def end_game(self, result): if result == 'win': self.result_text.set('You won') elif result == 'tie': self.result_text.set("It's a tie") elif result == 'lose': self.result_text.set('You lost') self.result_label.pack(side='top', pady=(10, 0)) self.hit_button.place_forget() self.pass_button.place_forget() self.update_hands(self.game.dealer_hand, self.game.player_hand, False) self.game.put_cards_back() self.play_button.place(rely=0.47, relx=0.46) def hit_button_pressed(self): self.game.player_hand.add_card(self.game.deck.deal()) self.add_card_image(self.game.player_hand.cards[-1]) self.update_hands(self.game.dealer_hand, self.game.player_hand, True) if self.game.player_hand.is_hand_over(): self.end_game('lose') def pass_button_pressed(self): while (self.game.dealer_hand.value < self.game.player_hand.value) and \ self.game.dealer_hand.value < 17: self.game.dealer_hand.add_card(self.game.deck.deal()) self.add_card_image(self.game.dealer_hand.cards[-1]) if self.game.dealer_hand.is_hand_over(): self.end_game('win') elif self.game.player_hand.value > self.game.dealer_hand.value: self.end_game('win') elif self.game.player_hand.value == self.game.dealer_hand.value: self.end_game('tie') else: self.end_game('lose') def play_button_pressed(self): self.result_label.pack_forget() self.hit_button.place(rely=0.48, relx=0.32) self.pass_button.place(rely=0.48, relx=0.65) self.play_button.place_forget() self.game.start() for card in self.game.dealer_hand.cards: self.add_card_image(card) for card in self.game.player_hand.cards: self.add_card_image(card) self.update_hands(self.game.dealer_hand, self.game.player_hand, True) def add_card_image(self, card): card_code_suit = card.code + card.suit[ 0] if card.code != 'red_back' else card.code if card_code_suit not in self.resized_card_images: card_name = card_code_suit + '.png' self.resized_card_images[ card_code_suit] = self.image_manager.add_image( card_name, self.hand_frame_height * 0.8)