Bot-Man-Toe/pyclient/replay.py

94 lines
3.2 KiB
Python

"""
This module helps describe & evaluate previously played games.
"""
from __future__ import annotations
from .games import Game
from .transition import Transition
from dataclasses import dataclass
from typing import Any, Generator
@dataclass(frozen=True)
class GameReplay:
"""
Game replay detailing the events of what happened in a previously
played game.
"""
game_name : str
start : Game
turns : list[Turn]
def gen_transitions(self) -> Generator[Transition, None, None]:
"""
Generate transitions from the game's summary.
:return: Transitions that describe consequences throughout the game.
:rtype: Generator[Transition, None, None]
"""
prev_state : Game = self.start
seen_participants : dict[int, tuple[Game, dict[str, Any]]] = {}
for turn in self.turns:
# If a player has made a move before, show the current state as
# the result of their previous turn's action.
state, action = seen_participants.get(turn.player, ( None, {} ))
if state is not None:
yield Transition(
full_state_after=prev_state,
full_state_before=state,
move=action,
player=turn.player,
)
# Save the player's current action for the future.
# We'll see how this action worked out!
seen_participants[turn.player] = ( prev_state, turn.action )
prev_state = turn.state
else:
# Record to all players that the game has finished.
for player, ( state, action ) in seen_participants.items():
yield Transition(
full_state_after=prev_state,
full_state_before=state,
move=action,
player=player,
)
def to_transitions(self, player : int | None = None) -> list[Transition]:
"""
Convert the GameSummary into a list of transitions that can be
fed to a system that can reflect on past moves.
:param player: Filter to only show transitions of a given player.
:type player: int | None
:return: A list of transitions extracted from a game.
:rtype: list[Transition]
"""
if player is None:
return list(self.gen_transitions())
else:
return [ t for t in self.gen_transitions() if t.player == player ]
@dataclass(frozen=True)
class Turn:
"""
A turn is a snapshot of a moment where a user was prompted to take an
action. A turn consists of three values:
1. The player (number) that was prompted for an action
2. The action that that player has decided to take
3. The game's state after the action was prompted and before the next
prompted move.
Note that turns might not correlate with in-game turns. A user might
take multiple actions in a Risk game (recruit, attack, move) and each
action is registered as an independent move.
"""
player : int
action : dict[str, Any]
state : Game