"""Instance of the game, with players and a market""" import asyncio from typing import List import random from model import Card, CardRole, CardParser, Player, Team, Serializable, Effect from model.card_loader import load_cards, create_card_effects, create_card class Game(Serializable): """Instance of the game, with players and a market""" object_type = "game" loaded_cards: List[CardParser] = load_cards() cards: List[Card] effects: List[Effect] market_stack: List[Card] market: List[Card] gem_stack: List[Card] players: List[Player] teams: List[Team] started: bool default_health = 50 current_turn: Team def __init__(self) -> None: super().__init__() self.market_stack: List[Card] = [] self.market: List[Card | None] = [None for _ in range(5)] self.gem_stack: List[Card] = [] self.players: List[Player] = [] self.cards: List[Card] = [] self.effects: List[Effect] = [] self.teams: List[Team] = [] self.started = False self.current_turn = None async def init_game(self): await self.init_cards() await self.distribute_market_cards() async def instanciate_card(self, card_parser: CardParser) -> Card: card, all_effects = create_card(card_parser) for e in all_effects: self.effects.append(e) await self.notify_controller("create", e.serialize()) self.cards.append(card) await self.notify_controller("create", card.serialize()) return card async def init_cards(self): """Creates market cards and fire gem cards from previously loaded cards""" market_only = [c for c in self.loaded_cards if c.role == CardRole.MARKET] for c in market_only: for _ in range(c.init_amount): self.market_stack.append(await self.instanciate_card(c)) random.shuffle(self.market_stack) fire_gems = [c for c in self.loaded_cards if c.role == CardRole.FIRE_GEM] for c in fire_gems: for _ in range(c.init_amount): self.gem_stack.append(await self.instanciate_card(c)) async def create_base_deck(self, base_deck_name: str = "base") -> List[Card]: """Creates the starting base deck for a player. Use base_deck_name to choose extensions characters""" base_deck_loaded = [ c for c in self.loaded_cards if c.role == CardRole.PERSONAL and c.faction == base_deck_name ] base_deck = [] for c in base_deck_loaded: for _ in range(c.init_amount): base_deck.append(await self.instanciate_card(c)) random.shuffle(base_deck) return base_deck async def create_player(self, username: str, team: Team | None = None) -> Player: if team is None: team = await self.create_team() player = Player(self, username, team) self.players.append(player) player.stack_pile = await self.create_base_deck("base") await self.notify_controller("create", player.turn.serialize()) await self.notify_controller("create", player.serialize_guest()) await self.notify_controller("update", self.serialize_guest()) return player async def create_team(self) -> Team: team = Team(health=self.default_health) self.teams.append(team) await self.notify_controller("create", team.serialize_guest()) return team def get_player(self, username: str) -> Player | None: players = [p for p in self.players if p.username == username] if players and len(players) > 0: return players[0] return None async def distribute_market_cards(self): """Tries to fill holes in the market with cards from the market stack""" try: while None in self.market: self.market[self.market.index(None)] = self.market_stack.pop() except IndexError: print("no more cards in market_stack!") finally: await self.notify_controller("update", self.serialize_guest()) def serialize_guest(self) -> dict: data = super().serialize_guest() | { "cards": [card.uuid for card in self.cards], "market_stack": [None for card in self.market_stack], "market": [None if card is None else card.uuid for card in self.market], "gem_stack": [card.uuid for card in self.gem_stack], "players": [player.uuid for player in self.players], "teams": [team.uuid for team in self.teams], "started": self.started, "default_health": self.default_health, "current_turn": ( None if self.current_turn is None else self.current_turn.uuid ), "effects": [effect.uuid for effect in self.effects], } return {k: data[k] for k in data.keys() - ["loaded_cards"]} async def start_game(self): self.started = True self.current_turn = random.choice(self.teams) await self.notify_controller("update", self.serialize_guest()) draws = [] for p in [p for p in self.players if p.team == self.current_turn]: draws.append(p.draw(3)) for p in [p for p in self.players if p.team != self.current_turn]: draws.append(p.draw(5)) await asyncio.gather(*draws) await self.notify_controller("update", self.serialize_guest()) notifications = [] await asyncio.gather(*notifications) print( "start game with " + str(len(self.players)) + " players : " + ", ".join([p.username for p in self.players]) ) async def end_turn(self): team_index = self.teams.index(self.current_turn) self.current_turn = self.teams[(team_index + 1) % len(self.teams)] for p in self.players: await p.start_turn() await self.notify_controller("update", self.serialize_guest()) def search_card_in_pile(self, card_id: str, pile: List[Card]): return next( (m for m in [f for f in pile if f is not None] if str(m.uuid) == card_id), None, )