""" The transition module allows agents to reflect on the choices they (and others) have made during recent games. Agents are generally intended to be stateless, so this allows them to later understand how well certain moves turned out. """ from __future__ import annotations from .games import FinishState, Game from dataclasses import dataclass from typing import Any, Generator @dataclass(frozen=True) class Transition: """ A transition is a simplified view on a user's single move. The transition contains the game state, the move they made, and what the game ended up looking like the next time they were prompted for a move. If the game ends, the `state_after` field contains the final state. """ full_state_after : Game full_state_before : Game move : dict[str, Any] player : int @property def end_result(self) -> FinishState | None: """ Return the result of this move if it caused the game to end, or None if the game still continues after this. :return: The player's result in the game with this move. :rtype: FinishState | None """ w = self.full_state_after.winner() if w is None: return None return w[self.player] @property def game_has_ended(self) -> bool: """ Shorthand property for whether this was the player's last move. Tip: Use the methods `move_caused_draw`, `move_caused_loss` and `move_caused_win` to determine the outcome. """ return self.full_state_after.winner() is not None @property def move_caused_draw(self) -> bool: """ Shorthand property for whether this move caused the player to draw. :rtype: bool """ return self.end_result == FinishState.draw @property def move_caused_loss(self) -> bool: """ Shorthand property for whether this move caused the player to lose. :rtype: bool """ return self.end_result == FinishState.loss @property def move_caused_win(self) -> bool: """ Shorthand property for whether this move caused the player to win. :rtype: bool """ return self.end_result == FinishState.win @property def state_after(self) -> dict[str, Any]: """ The initial state that the agent was shown after they were asked for a move. Keep in mind that this state does not necessarily contain ALL information, as players are often partially kept in the dark about a game's state. :rtype: dict[str, Any] """ return self.full_state_after.as_seen_by(self.player) @property def state_before(self) -> dict[str, Any]: """ The initial state that the agent was shown when they were asked for a move. Keep in mind that this state does not necessarily contain ALL information, as players are often partially kept in the dark about a game's state. :rtype: dict[str, Any] """ return self.full_state_before.as_seen_by(self.player)