first prototype
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""The view of the game a single player is allowed to see.
|
||||
|
||||
An ``Observation`` contains everything a player knows at a point in time and
|
||||
nothing more (no opponent hands, hidden bids stay hidden). It is used
|
||||
|
||||
- by the server to send the game state to a web client, and
|
||||
- as the input of AI players, both in training and in production.
|
||||
|
||||
``to_dict`` / ``from_dict`` provide a lossless JSON representation.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from .actions import Action, action_from_dict
|
||||
from .cards import Card, Suit, card_by_id
|
||||
from .state import GameOptions, Phase, PlayedCard, RoundResult, TrickResult
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Observation:
|
||||
player: int
|
||||
num_players: int
|
||||
options: GameOptions
|
||||
phase: Phase
|
||||
round_number: int
|
||||
total_rounds: int
|
||||
dealer: int
|
||||
current_player: int | None
|
||||
hand: tuple[Card, ...]
|
||||
hand_sizes: tuple[int, ...]
|
||||
trump_card: Card | None
|
||||
trump_suit: Suit | None
|
||||
# ``None`` for players who have not bid yet, or whose bid is still hidden.
|
||||
bids: tuple[int | None, ...]
|
||||
has_bid: tuple[bool, ...]
|
||||
tricks_won: tuple[int, ...]
|
||||
scores: tuple[int, ...]
|
||||
trick_number: int
|
||||
trick_leader: int
|
||||
current_trick: tuple[PlayedCard, ...]
|
||||
lead_suit: Suit | None
|
||||
# All cards played in the current round, including the current trick.
|
||||
played_cards: tuple[Card, ...]
|
||||
last_trick: TrickResult | None
|
||||
round_history: tuple[RoundResult, ...]
|
||||
# Empty unless it is this player's turn.
|
||||
legal_actions: tuple[Action, ...]
|
||||
winners: tuple[int, ...]
|
||||
|
||||
@property
|
||||
def is_my_turn(self) -> bool:
|
||||
return self.current_player == self.player
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"player": self.player,
|
||||
"num_players": self.num_players,
|
||||
"options": self.options.to_dict(),
|
||||
"phase": self.phase.value,
|
||||
"round_number": self.round_number,
|
||||
"total_rounds": self.total_rounds,
|
||||
"dealer": self.dealer,
|
||||
"current_player": self.current_player,
|
||||
"hand": [card.to_dict() for card in self.hand],
|
||||
"hand_sizes": list(self.hand_sizes),
|
||||
"trump_card": self.trump_card.to_dict() if self.trump_card else None,
|
||||
"trump_suit": self.trump_suit.value if self.trump_suit else None,
|
||||
"bids": list(self.bids),
|
||||
"has_bid": list(self.has_bid),
|
||||
"tricks_won": list(self.tricks_won),
|
||||
"scores": list(self.scores),
|
||||
"trick_number": self.trick_number,
|
||||
"trick_leader": self.trick_leader,
|
||||
"current_trick": [played.to_dict() for played in self.current_trick],
|
||||
"lead_suit": self.lead_suit.value if self.lead_suit else None,
|
||||
"played_cards": [card.to_dict() for card in self.played_cards],
|
||||
"last_trick": self.last_trick.to_dict() if self.last_trick else None,
|
||||
"round_history": [result.to_dict() for result in self.round_history],
|
||||
"legal_actions": [action.to_dict() for action in self.legal_actions],
|
||||
"winners": list(self.winners),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> Observation:
|
||||
def card(value: dict | None) -> Card | None:
|
||||
return card_by_id(value["id"]) if value else None
|
||||
|
||||
def suit(value: str | None) -> Suit | None:
|
||||
return Suit(value) if value else None
|
||||
|
||||
return cls(
|
||||
player=data["player"],
|
||||
num_players=data["num_players"],
|
||||
options=GameOptions.from_dict(data["options"]),
|
||||
phase=Phase(data["phase"]),
|
||||
round_number=data["round_number"],
|
||||
total_rounds=data["total_rounds"],
|
||||
dealer=data["dealer"],
|
||||
current_player=data["current_player"],
|
||||
hand=tuple(card_by_id(c["id"]) for c in data["hand"]),
|
||||
hand_sizes=tuple(data["hand_sizes"]),
|
||||
trump_card=card(data["trump_card"]),
|
||||
trump_suit=suit(data["trump_suit"]),
|
||||
bids=tuple(data["bids"]),
|
||||
has_bid=tuple(data["has_bid"]),
|
||||
tricks_won=tuple(data["tricks_won"]),
|
||||
scores=tuple(data["scores"]),
|
||||
trick_number=data["trick_number"],
|
||||
trick_leader=data["trick_leader"],
|
||||
current_trick=tuple(PlayedCard.from_dict(p) for p in data["current_trick"]),
|
||||
lead_suit=suit(data["lead_suit"]),
|
||||
played_cards=tuple(card_by_id(c["id"]) for c in data["played_cards"]),
|
||||
last_trick=TrickResult.from_dict(data["last_trick"]) if data["last_trick"] else None,
|
||||
round_history=tuple(RoundResult.from_dict(r) for r in data["round_history"]),
|
||||
legal_actions=tuple(action_from_dict(a) for a in data["legal_actions"]),
|
||||
winners=tuple(data["winners"]),
|
||||
)
|
||||
Reference in New Issue
Block a user