import customtkinter as ctk from blackjack_game import BlackjackGame 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._create_start_screen() 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) # Action buttons (Hit, Stand, Double, Split) self.buttons = ActionButtons(self.app, self) # Hint button self.hint_button = ctk.CTkButton( self.app, text="Hint", command=self.show_hint, fg_color="white", text_color="black", font=("Arial", 20) ) self.hint_button.pack(pady=10) # Feedback label (centered — matches web layout) self.feedback_label = ctk.CTkLabel( self.app, text="", font=("Arial", 20), wraplength=550, anchor="center" ) self.feedback_label.pack(pady=20, padx=10, fill="x") # Next Round button self.next_round_button = ctk.CTkButton( self.app, text="Next Round", command=self.start_new_round, fg_color="white", text_color="black", font=("Arial", 20) ) self.next_round_button.pack(pady=10) self.next_round_button.configure(state="disabled") # Exit button self.exit_button = ctk.CTkButton( self.app, text="Exit", command=self._exit, fg_color="#555", text_color="#ccc", font=("Arial", 16), hover_color="#666" ) self.exit_button.pack(pady=(4, 10)) # Notifications self.notifications = NotificationSystem(self.app) # Hint system self.hints = HintSystem(self.app) self.hints.set_hint_button(self.hint_button) # Stats display self.stats = StatsDisplay(self.app) 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.hint_button.configure(state="normal") self.feedback_label.configure(text="") self.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.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.next_round_button.configure(state="normal") def _on_main_window_close(self): """Handle window close event — just close directly""" self.app.destroy() def _create_start_screen(self): """Create the start screen overlay""" if hasattr(self, 'start_frame') and self.start_frame and self.start_frame.winfo_exists(): return self.start_frame = ctk.CTkFrame(self.app, fg_color="#2b2b2b", corner_radius=0) self.start_frame.place(relx=0, rely=0, relwidth=1, relheight=1) content = ctk.CTkFrame(self.start_frame, fg_color="transparent") content.place(relx=0.5, rely=0.5, anchor="center") ctk.CTkLabel( content, text="\U0001F0CF Blackjack Theory Trainer", font=("Arial", 28, "bold"), text_color="white" ).pack(pady=(0, 20)) ctk.CTkLabel( content, text="This is a blackjack basic strategy trainer and not a real blackjack game.\n\nEach round you're dealt a hand and asked to make the correct play (Hit, Stand, Double, or Split) according to basic strategy. You get immediate feedback and track your accuracy over time.\n\nHave Fun!", font=("Arial", 15), text_color="#ccc", wraplength=450, justify="center" ).pack(pady=(0, 30)) ctk.CTkButton( content, text="Start Training", command=self._start_training, fg_color="#2aa44f", hover_color="#238c44", text_color="white", font=("Arial", 20, "bold"), height=45, width=200 ).pack(pady=(0, 10)) ctk.CTkButton( content, text="Quit", command=self._on_main_window_close, fg_color="#555", text_color="#ccc", font=("Arial", 16), height=35, width=120, hover_color="#666" ).pack() def _start_training(self): """Start button handler — enter game mode""" if hasattr(self, 'start_frame') and self.start_frame: self.start_frame.destroy() self.start_frame = None self.start_new_round() def _exit(self): """Exit button handler — show stats popup""" self.buttons._enable_action_buttons(False) self.next_round_button.configure(state="disabled") self.hint_button.configure(state="disabled") self.stats._show_exit_popup(self.game_logic.get_stats(), self._exit_to_start) def _exit_to_start(self): """Reset game state and return to start screen""" self.game_logic = BlackjackGame() self._create_start_screen() 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()