import random from support.game_settings import CODENAMES_WORDS, NAMES, TEAM_MODEL_PRESETS, ALL_MODELS from support.load_models import create_model from support.settings import AVATAR_PATHS from typing import List, Optional class Player: def __init__(self, name: str, model_name: str, model, avatar: str): self.name = name self.model_name = model_name self.model = model self.avatar = avatar self.team: Optional[str] = None self.role: Optional[str] = None class Game: def __init__( self, selected_team: str = None, red_team: str = "google", blue_team: str = "openai", api_keys: dict = None, ): """ Initialize a new game. Either provide `selected_team` (legacy mode) or `red_team` and `blue_team`. - red_team / blue_team: choose from ["openai", "google", "anthropic", "opensource", "random"] - selected_team: legacy single-team mode (both teams use same preset) """ # Backward compatibility if selected_team and not (red_team or blue_team): self.red_team_choice = selected_team.lower() self.blue_team_choice = selected_team.lower() else: self.red_team_choice = red_team.lower() self.blue_team_choice = blue_team.lower() self.players: List[Player] = [] self.board: dict = {} self.api_keys = api_keys if api_keys else {} self.setup_game() def setup_game(self): """Initialize a new game with players and board""" # Prepare shared pools for names and avatars available_names = NAMES.copy() available_avatars = AVATAR_PATHS.copy() random.shuffle(available_names) random.shuffle(available_avatars) self.players = self.create_players(available_names, available_avatars) self.board = self.generate_board() def _generate_team_players(self, team_color, team_choice, available_names, available_avatars): players = [] roles = ["boss", "captain", "player", "player"] if team_choice in TEAM_MODEL_PRESETS: setup = TEAM_MODEL_PRESETS[team_choice] model_names = [setup["boss"], setup["captain"]] + setup["players"] else: ROLE_POOLS = { "boss": [preset["boss"] for preset in TEAM_MODEL_PRESETS.values()], "captain": [preset["captain"] for preset in TEAM_MODEL_PRESETS.values()], "player": [ model for preset in TEAM_MODEL_PRESETS.values() for model in preset["players"] ] } model_names = [random.choice(ROLE_POOLS[role]) for role in roles] for i in range(4): name = available_names.pop() if available_names else f"{team_color.title()}_{i}" avatar = available_avatars.pop() if available_avatars else "assets/avatars/default.png" model_name = model_names[i] model = create_model(model_name, self.api_keys) p = Player(name, model_name, model, avatar) p.team = team_color p.role = roles[i] players.append(p) return players def create_players(self, available_names, available_avatars) -> List[Player]: """Create 8 players (4 per team) according to selected team presets""" red_players = self._generate_team_players("red", self.red_team_choice, available_names, available_avatars) blue_players = self._generate_team_players("blue", self.blue_team_choice, available_names, available_avatars) return red_players + blue_players def generate_board(self) -> dict: """ Generate a new game board with 25 random words. Distribution: 9 starting team, 8 other team, 7 neutral, 1 killer """ # Select 25 random words selected_words = random.sample(CODENAMES_WORDS, 25) # Randomly choose starting team starting_team = random.choice(['red', 'blue']) # Assign word counts based on starting team if starting_team == 'red': red_count, blue_count = 9, 8 else: red_count, blue_count = 8, 9 neutral_count = 7 # Create a list of (word, color) tuples word_color_pairs = [] idx = 0 # Add red words for i in range(red_count): word_color_pairs.append((selected_words[idx], 'red')) idx += 1 # Add blue words for i in range(blue_count): word_color_pairs.append((selected_words[idx], 'blue')) idx += 1 # Add neutral words for i in range(neutral_count): word_color_pairs.append((selected_words[idx], 'neutral')) idx += 1 # Add killer word word_color_pairs.append((selected_words[idx], 'killer')) # Shuffle to randomize positions on board random.shuffle(word_color_pairs) # Store in board dictionary board = { 'word_color_pairs': word_color_pairs, 'starting_team': starting_team, 'red': [w for w, c in word_color_pairs if c == 'red'], 'blue': [w for w, c in word_color_pairs if c == 'blue'], 'neutral': [w for w, c in word_color_pairs if c == 'neutral'], 'killer': [w for w, c in word_color_pairs if c == 'killer'][0] } return board