Bot-Man-Toe/pyclient/client.py

81 lines
2.6 KiB
Python

"""
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)),
)