import customtkinter as ctk from game_logic import can_split, get_split_decision, get_correct_decision from .utils import load_card_images from .components.cards import CardDisplay from .components.buttons import ActionButtons from .components.notifications import NotificationSystem from .components.hints import HintSystem from .components.stats import StatsDisplay class BlackjackGUI: def __init__(self, blackjackGame): self.game_logic = blackjackGame self.card_images = load_card_images() self._setup_main_window() self._create_components() self.start_new_round() def _setup_main_window(self): """Initialize main application window""" self.app = ctk.CTk() self.app.title("Blackjack Theory Trainer") self.app.geometry("600x650+800+200") self.app.protocol("WM_DELETE_WINDOW", self._on_main_window_close) ctk.set_appearance_mode("dark") def _create_components(self): """Create all UI components""" # Card display self.card_display = CardDisplay(self.app, self.card_images) # Buttons (pass reference to self for callbacks) self.buttons = ActionButtons(self.app, self) # Notifications self.notifications = NotificationSystem(self.app) # Hint system self.hints = HintSystem(self.app) self.hints.set_hint_button(self.buttons.hint_button) # Stats display self.stats = StatsDisplay(self.app) # Feedback label (only remaining widget in main file) self.feedback_label = ctk.CTkLabel( self.app, text="", font=("Arial", 20), wraplength=550, anchor="w" ) self.feedback_label.pack(pady=20, padx=10, fill="x") def start_new_round(self): """Start a new round of the game""" self._reset_ui() self.game_logic.start_new_round() self._update_display() def _reset_ui(self): """Reset UI for new round""" self.hints._close_hint_window() self.buttons.hint_button.configure(state="normal") self.feedback_label.configure(text="") self.buttons.next_round_button.configure(state="disabled") self.buttons._enable_action_buttons(True) self.buttons._reset_button_colors() if hasattr(self.notifications, 'streak_label') and self.notifications.streak_label: self.notifications.streak_label.configure(text="") def _update_display(self): """Update all display elements""" # Update card display self.card_display.update_display( self.game_logic.dealer_card, self.game_logic.player_hand ) # Handle blackjack if self.game_logic.has_blackjack: self.feedback_label.configure( text="Blackjack! You win or get a push!", text_color="green" ) self.buttons._enable_action_buttons(False) self.buttons.next_round_button.configure(state="normal") # Handle split possibility can_split_bool = can_split(self.game_logic.player_hand) if can_split_bool: self.buttons.split_button.configure(state="normal") self.feedback_label.configure( text="You have a pair! Consider splitting.", text_color="white" ) else: self.buttons.split_button.configure(state="disabled") # Update notifications stats = self.game_logic.get_stats() self.notifications._update_streak_display(stats["current_streak"]) if stats.get("pending_streak_notification"): self.notifications._show_streak_notification(stats["pending_streak_notification"]) def _hit(self): self._handle_action("Hit", self.buttons.hit_button) def _stand(self): self._handle_action("Stand", self.buttons.stand_button) def _double(self): self._handle_action("Double", self.buttons.double_button) def _split(self): self._handle_action("Split", self.buttons.split_button) def _handle_action(self, action, button): """Process player actions""" # Determine scenario type scenario_type = "hard_totals" if can_split(self.game_logic.player_hand): scenario_type = "pairs" elif 'A' in [card.split('_')[-1] for card in self.game_logic.player_hand]: scenario_type = "soft_totals" # Check if player can split if can_split(self.game_logic.player_hand): decision, feedback = get_split_decision( self.game_logic.player_hand, self.game_logic.dealer_card ) correct = action == decision else: decision, feedback = get_correct_decision( self.game_logic.player_hand, self.game_logic.player_total, self.game_logic.dealer_card ) correct = action == decision # Update UI color = "green" if correct else "red" self.feedback_label.configure(text=feedback, text_color=color) self.buttons._mark_button(button, correct) self.game_logic.update_stats(correct, scenario_type) # Update button states self.buttons._enable_action_buttons(False) self.buttons.next_round_button.configure(state="normal") def _on_main_window_close(self): """Handle window close event""" self.app.configure(state="disabled") self.stats._show_final_stats(self.game_logic.get_stats()) def show_hint(self): """Delegate hint display to the HintSystem""" self.hints._disable_hint_button() self.hints.show_hint() def run(self): """Start application main loop""" self.app.mainloop()