|
|
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) |
|
|
""" |
|
|
|
|
|
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""" |
|
|
|
|
|
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 |
|
|
""" |
|
|
|
|
|
selected_words = random.sample(CODENAMES_WORDS, 25) |
|
|
|
|
|
|
|
|
starting_team = random.choice(['red', 'blue']) |
|
|
|
|
|
|
|
|
if starting_team == 'red': |
|
|
red_count, blue_count = 9, 8 |
|
|
else: |
|
|
red_count, blue_count = 8, 9 |
|
|
|
|
|
neutral_count = 7 |
|
|
|
|
|
word_color_pairs = [] |
|
|
idx = 0 |
|
|
|
|
|
|
|
|
for i in range(red_count): |
|
|
word_color_pairs.append((selected_words[idx], 'red')) |
|
|
idx += 1 |
|
|
|
|
|
|
|
|
for i in range(blue_count): |
|
|
word_color_pairs.append((selected_words[idx], 'blue')) |
|
|
idx += 1 |
|
|
|
|
|
|
|
|
for i in range(neutral_count): |
|
|
word_color_pairs.append((selected_words[idx], 'neutral')) |
|
|
idx += 1 |
|
|
|
|
|
|
|
|
word_color_pairs.append((selected_words[idx], 'killer')) |
|
|
|
|
|
|
|
|
random.shuffle(word_color_pairs) |
|
|
|
|
|
|
|
|
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 |
|
|
|