""" This module hosts the PyClient class. You can use this class to simulate games among mulltiple agents. """ from __future__ import annotations from agents import Agent from .games import Game from .replay import GameReplay, Turn from dataclasses import dataclass from typing import Any, Generator @dataclass(frozen=True) class PyClient: """ Host games among multiple agents. """ debug : bool def gen_game(self, players : list[Agent], start : Game) -> Generator[Turn, None, None]: """ Generate a game by polling the players. :param players: All players that wish to participate. :type players: list[Agent] :param start: The start state of the game. :type start: Game :return: A generator that yields turns. :rtype: Generator[Turn, None, None] """ current_state = start while current_state.winner() is None: player = current_state.player_to_move() if len(players) < player: # Player not found! Make a default move. current_state = current_state.move_default() yield Turn(action={}, player=player, state=current_state) else: agent = players[player - 1] on_move = agent.get_action( game=current_state.game_name(), action=current_state.action_name(), ) # Calculate move if on_move is None: payload = {} else: try: payload = on_move(current_state.as_seen_by(player=player)) except Exception: payload = {} current_state = current_state.move(payload=payload) yield Turn(action=payload, player=player, state=current_state) def play_game(self, players : list[Agent], start : Game) -> GameReplay: """ Generate a game by polling the players. Collect all moves in a summary. :param players: All players that wish to participate. :type players: list[Agent] :param start: The start state of the game. :type start: Game :return: Summary describing how the game went. :rtype: GameReplay """ return GameReplay( game_name=start.game_name(), start=start, turns=list(self.gen_game(players=players, start=start)), )