Source code for yasuki_core.engine.rules.projection

from dataclasses import dataclass

from yasuki_core.engine.players import PlayerId
from yasuki_core.engine.redaction import redact, ViewSnapshot
from yasuki_core.engine.rules.state import GameState, Phase
from yasuki_core.engine.rules.decisions import DecisionRequest


[docs] @dataclass(frozen=True, slots=True) class GameView: """A per-seat projection of a :class:`GameState` — everything one seat is entitled to see. The table is redacted for the viewer (the opponent's hand, face-down cards, and deck contents appear as backs); the turn-level rules fields are public to both seats; and a pending decision reaches only the seat that must answer it. Attributes ---------- viewer : PlayerId The seat this view is built for. table : ViewSnapshot The viewer's redacted view of the board. turn : int The current turn number. active : PlayerId The seat whose turn it is. phase : Phase The current phase. first_player : PlayerId The seat that took the first turn. gold : dict mapping PlayerId to int Every seat's gold pool — public to both seats. favor_holder : PlayerId or None The seat holding the Imperial Favor, or None. pending : DecisionRequest or None The decision the viewer must answer, or None when nothing is awaited from this viewer — including when the engine is instead waiting on the other seat. """ viewer: PlayerId table: ViewSnapshot turn: int active: PlayerId phase: Phase first_player: PlayerId gold: dict[PlayerId, int] favor_holder: PlayerId | None pending: DecisionRequest | None
[docs] def project(game: GameState, viewer: PlayerId) -> GameView: """Project ``game`` into the view ``viewer`` is entitled to: the board redacted for the viewer, the public rules fields, and the pending decision only if this viewer is the one to answer it.""" pending = game.pending if game.pending is not None and game.pending.seat is viewer else None return GameView( viewer=viewer, table=redact(game.table, viewer), turn=game.turn, active=game.active, phase=game.phase, first_player=game.first_player, gold=dict(game.gold), favor_holder=game.favor_holder, pending=pending, )