mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 22:43:02 +02:00
- Move puzzle_solver/, poker_modifier_app/, articles/, tests/ into python_pkg/ - Move moviepy_showcase.py and _moviepy_*.py into python_pkg/moviepy_showcase/ - Update all imports to use python_pkg. prefix - Update pyproject.toml per-file-ignores and pytest testpaths - Add pre-commit hook to enforce Python files under python_pkg/
267 lines
9.4 KiB
Python
267 lines
9.4 KiB
Python
"""Texas Hold'em poker game modifier application."""
|
|
|
|
import logging
|
|
import secrets
|
|
import tkinter as tk
|
|
|
|
from python_pkg.poker_modifier_app._poker_gui import PokerGuiMixin
|
|
from python_pkg.poker_modifier_app._poker_modifiers import (
|
|
ENDGAME_MODIFIERS,
|
|
REGULAR_MODIFIERS,
|
|
)
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
# Use cryptographically secure random number generator
|
|
_rng = secrets.SystemRandom()
|
|
|
|
|
|
class PokerModifierApp(PokerGuiMixin):
|
|
"""GUI application for poker game modifiers."""
|
|
|
|
def __init__(self) -> None:
|
|
"""Initialize the poker modifier app with default settings."""
|
|
self.modifiers = list(REGULAR_MODIFIERS)
|
|
self.endgame_modifiers = list(ENDGAME_MODIFIERS)
|
|
|
|
# Remove endgame modifiers from regular modifier list
|
|
endgame_modifier_names = [mod["name"] for mod in self.endgame_modifiers]
|
|
self.modifiers = [
|
|
mod for mod in self.modifiers if mod["name"] not in endgame_modifier_names
|
|
]
|
|
|
|
# Game state tracking
|
|
self.rounds_played = 0
|
|
self.modifiers_applied = 0
|
|
self.total_game_rounds = 20 # Default game length
|
|
self.endgame_threshold = 0.8 # Start endgame modifiers at 80% of total rounds
|
|
self.debug_mode = False
|
|
self.force_endgame = False
|
|
|
|
self.setup_gui()
|
|
|
|
def update_prob_display(self, value: str) -> None:
|
|
"""Update the probability percentage display."""
|
|
self.prob_label.config(text=f"{value}%")
|
|
|
|
def update_length_display(self, value: str) -> None:
|
|
"""Update the game length display."""
|
|
self.length_label.config(text=str(value))
|
|
self.total_game_rounds = int(value)
|
|
|
|
def toggle_debug_mode(self) -> None:
|
|
"""Toggle debug mode and show/hide debug controls."""
|
|
self.debug_mode = self.debug_var.get()
|
|
if self.debug_mode:
|
|
self.force_endgame_button.pack(side=tk.LEFT, padx=(0, 10))
|
|
_logger.debug("Debug mode enabled")
|
|
else:
|
|
self.force_endgame_button.pack_forget()
|
|
self.force_endgame = False
|
|
_logger.debug("Debug mode disabled")
|
|
|
|
def toggle_force_endgame(self) -> None:
|
|
"""Toggle forced endgame mode for testing."""
|
|
self.force_endgame = not self.force_endgame
|
|
if self.force_endgame:
|
|
self.force_endgame_button.config(text="Stop Force Endgame", bg="#4CAF50")
|
|
_logger.debug("Forcing endgame modifiers")
|
|
else:
|
|
self.force_endgame_button.config(text="Force Endgame", bg="#ff6b6b")
|
|
_logger.debug("Normal modifier selection restored")
|
|
|
|
def is_endgame(self) -> bool:
|
|
"""Determine if we're in endgame phase."""
|
|
if self.debug_mode and self.force_endgame:
|
|
return True
|
|
|
|
endgame_round = int(self.total_game_rounds * self.endgame_threshold)
|
|
return self.rounds_played >= endgame_round
|
|
|
|
def start_round(self) -> None:
|
|
"""Start a new poker round and determine if modifier should be applied."""
|
|
# Button animation effect
|
|
self.start_button.config(relief=tk.SUNKEN)
|
|
self.root.after(100, lambda: self.start_button.config(relief=tk.RAISED))
|
|
|
|
# Update round counter
|
|
self.rounds_played += 1
|
|
self.rounds_label.config(text=str(self.rounds_played))
|
|
|
|
# Update game phase indicator
|
|
self.update_phase_indicator()
|
|
|
|
# Get current probability
|
|
modifier_chance = self.prob_var.get()
|
|
|
|
# Determine if modifier should be applied
|
|
random_value = _rng.random() * 100
|
|
should_apply_modifier = random_value < modifier_chance
|
|
|
|
if should_apply_modifier:
|
|
self.apply_random_modifier()
|
|
else:
|
|
self.show_no_modifier()
|
|
|
|
def update_phase_indicator(self) -> None:
|
|
"""Update the game phase indicator based on current round."""
|
|
if self.is_endgame():
|
|
self.phase_label.config(text="Endgame", fg="#ff6b6b")
|
|
elif self.rounds_played >= self.total_game_rounds * 0.6:
|
|
self.phase_label.config(text="Late", fg="#ffa500")
|
|
elif self.rounds_played >= self.total_game_rounds * 0.3:
|
|
self.phase_label.config(text="Mid", fg="#ffeb3b")
|
|
else:
|
|
self.phase_label.config(text="Early", fg="#4CAF50")
|
|
|
|
def apply_random_modifier(self) -> None:
|
|
"""Apply a random modifier and update display."""
|
|
# Update modifier counter
|
|
self.modifiers_applied += 1
|
|
self.mods_label.config(text=str(self.modifiers_applied))
|
|
|
|
# Determine which modifier pool to use
|
|
if self.is_endgame():
|
|
modifier_pool = self.endgame_modifiers
|
|
modifier_type = "🏁 ENDGAME"
|
|
bg_color = "#4a2d2d" # Darker red for endgame
|
|
else:
|
|
modifier_pool = self.modifiers
|
|
modifier_type = "🎲"
|
|
bg_color = "#2d4a2d" # Green for normal
|
|
|
|
# Select random modifier from appropriate pool
|
|
selected_modifier = _rng.choice(modifier_pool).copy()
|
|
|
|
# Special handling for Steel Cards - randomize the rank
|
|
if selected_modifier["name"] == "Steel Cards":
|
|
ranks = [
|
|
"2",
|
|
"3",
|
|
"4",
|
|
"5",
|
|
"6",
|
|
"7",
|
|
"8",
|
|
"9",
|
|
"10",
|
|
"Jack",
|
|
"Queen",
|
|
"King",
|
|
"Ace",
|
|
]
|
|
steel_rank = _rng.choice(ranks)
|
|
selected_modifier["description"] = selected_modifier["description"].format(
|
|
steel_rank=steel_rank
|
|
)
|
|
|
|
# Update result frame styling for modifier
|
|
self.result_frame.config(
|
|
bg=bg_color, highlightbackground="#ffd700", highlightthickness=2
|
|
)
|
|
|
|
# Update display with modifier info
|
|
modifier_text = (
|
|
f"{modifier_type} {selected_modifier['name']}\n\n"
|
|
f"{selected_modifier['description']}"
|
|
)
|
|
|
|
# Add endgame indicator if applicable
|
|
if self.is_endgame():
|
|
rounds_left = self.total_game_rounds - self.rounds_played
|
|
if rounds_left > 0:
|
|
modifier_text += f"\n\n⚠️ Endgame Phase - {rounds_left} rounds left"
|
|
else:
|
|
modifier_text += "\n\n⚠️ FINAL ROUND!"
|
|
|
|
self.result_label.config(
|
|
text=modifier_text, fg="#ffd700", bg=bg_color, font=("Arial", 14, "bold")
|
|
)
|
|
|
|
def show_no_modifier(self) -> None:
|
|
"""Show no modifier message."""
|
|
# Update result frame styling for no modifier
|
|
self.result_frame.config(
|
|
bg="#2d2d2d", highlightbackground="#666666", highlightthickness=1
|
|
)
|
|
|
|
# Update display
|
|
self.result_label.config(
|
|
text="No modifier this round\n\nPlay normally",
|
|
fg="#cccccc",
|
|
bg="#2d2d2d",
|
|
font=("Arial", 14),
|
|
)
|
|
|
|
def reset_game(self) -> None:
|
|
"""Reset the game to initial state."""
|
|
self.rounds_played = 0
|
|
self.modifiers_applied = 0
|
|
self.force_endgame = False
|
|
|
|
# Update displays
|
|
self.rounds_label.config(text="0")
|
|
self.mods_label.config(text="0")
|
|
self.phase_label.config(text="Early", fg="#4CAF50")
|
|
|
|
# Reset result frame
|
|
self.result_frame.config(
|
|
bg="#2d2d2d", highlightbackground="#666666", highlightthickness=1
|
|
)
|
|
self.result_label.config(
|
|
text="Click 'Start Round' to begin!",
|
|
fg="#cccccc",
|
|
bg="#2d2d2d",
|
|
font=("Arial", 14),
|
|
)
|
|
|
|
# Reset force endgame button if visible
|
|
if self.debug_mode:
|
|
self.force_endgame_button.config(text="Force Endgame", bg="#ff6b6b")
|
|
|
|
_logger.info("Game reset to initial state")
|
|
|
|
def add_modifier(self, name: str, description: str) -> None:
|
|
"""Add a new modifier to the list."""
|
|
self.modifiers.append({"name": name, "description": description})
|
|
|
|
def get_stats(self) -> dict[str, int | float | bool]:
|
|
"""Get current statistics."""
|
|
modifier_rate = (
|
|
0
|
|
if self.rounds_played == 0
|
|
else (self.modifiers_applied / self.rounds_played) * 100
|
|
)
|
|
rounds_remaining = max(0, self.total_game_rounds - self.rounds_played)
|
|
|
|
return {
|
|
"rounds_played": self.rounds_played,
|
|
"modifiers_applied": self.modifiers_applied,
|
|
"modifier_rate": round(modifier_rate, 1),
|
|
"total_game_rounds": self.total_game_rounds,
|
|
"rounds_remaining": rounds_remaining,
|
|
"is_endgame": self.is_endgame(),
|
|
"debug_mode": self.debug_mode,
|
|
"force_endgame": self.force_endgame,
|
|
}
|
|
|
|
def run(self) -> None:
|
|
"""Start the application."""
|
|
_logger.info("Texas Hold'em Modifier App started!")
|
|
_logger.info(
|
|
"Available methods: app.get_stats(), app.add_modifier(name, description)"
|
|
)
|
|
_logger.info(
|
|
"Debug features: Toggle debug mode to access force endgame controls"
|
|
)
|
|
_logger.info("Default game length: %s rounds", self.total_game_rounds)
|
|
endgame_pct = int(self.endgame_threshold * 100)
|
|
endgame_rounds = int(self.total_game_rounds * self.endgame_threshold)
|
|
_logger.info("Endgame threshold: %s%% (%s rounds)", endgame_pct, endgame_rounds)
|
|
self.root.mainloop()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = PokerModifierApp()
|
|
app.run()
|