Bot-Man-Toe/pyclient/transition.py

111 lines
3.3 KiB
Python

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