""" 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. """ 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