first prototype
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
"""Value types describing game state, options, results and events."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from .cards import Card, Suit, card_by_id
|
||||
|
||||
|
||||
class Phase(str, Enum):
|
||||
TRUMP_SELECTION = "trump_selection"
|
||||
BIDDING = "bidding"
|
||||
PLAYING = "playing"
|
||||
FINISHED = "finished"
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class GameOptions:
|
||||
# "notequal": the sum of all bids must not equal the number of tricks
|
||||
# of the round. The last bidder has to adjust their bid.
|
||||
not_equal: bool = False
|
||||
# "hiddentip": bids are revealed only once every player has bid.
|
||||
hidden_bids: bool = False
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"not_equal": self.not_equal, "hidden_bids": self.hidden_bids}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> GameOptions:
|
||||
return cls(
|
||||
not_equal=bool(data.get("not_equal", False)),
|
||||
hidden_bids=bool(data.get("hidden_bids", False)),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class PlayedCard:
|
||||
player: int
|
||||
card: Card
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"player": self.player, "card": self.card.to_dict()}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> PlayedCard:
|
||||
return cls(player=data["player"], card=card_by_id(data["card"]["id"]))
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class TrickResult:
|
||||
round_number: int
|
||||
trick_number: int
|
||||
cards: tuple[PlayedCard, ...]
|
||||
winner: int
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"round_number": self.round_number,
|
||||
"trick_number": self.trick_number,
|
||||
"cards": [played.to_dict() for played in self.cards],
|
||||
"winner": self.winner,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> TrickResult:
|
||||
return cls(
|
||||
round_number=data["round_number"],
|
||||
trick_number=data["trick_number"],
|
||||
cards=tuple(PlayedCard.from_dict(c) for c in data["cards"]),
|
||||
winner=data["winner"],
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RoundResult:
|
||||
round_number: int
|
||||
bids: tuple[int, ...]
|
||||
tricks: tuple[int, ...]
|
||||
score_changes: tuple[int, ...]
|
||||
scores: tuple[int, ...]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"round_number": self.round_number,
|
||||
"bids": list(self.bids),
|
||||
"tricks": list(self.tricks),
|
||||
"score_changes": list(self.score_changes),
|
||||
"scores": list(self.scores),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> RoundResult:
|
||||
return cls(
|
||||
round_number=data["round_number"],
|
||||
bids=tuple(data["bids"]),
|
||||
tricks=tuple(data["tricks"]),
|
||||
score_changes=tuple(data["score_changes"]),
|
||||
scores=tuple(data["scores"]),
|
||||
)
|
||||
|
||||
|
||||
# --- Events -----------------------------------------------------------------
|
||||
# ``WizardGame.apply`` returns the events caused by an action. They are handy
|
||||
# for clients that want to animate what happened (e.g. pause after a trick).
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RoundStarted:
|
||||
round_number: int
|
||||
dealer: int
|
||||
trump_card: Card | None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"type": "round_started",
|
||||
"round_number": self.round_number,
|
||||
"dealer": self.dealer,
|
||||
"trump_card": self.trump_card.to_dict() if self.trump_card else None,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class TrickCompleted:
|
||||
trick: TrickResult
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"type": "trick_completed", "trick": self.trick.to_dict()}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RoundCompleted:
|
||||
result: RoundResult
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"type": "round_completed", "result": self.result.to_dict()}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class GameFinished:
|
||||
scores: tuple[int, ...]
|
||||
winners: tuple[int, ...]
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"type": "game_finished", "scores": list(self.scores), "winners": list(self.winners)}
|
||||
|
||||
|
||||
Event = RoundStarted | TrickCompleted | RoundCompleted | GameFinished
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class RoundState:
|
||||
"""Mutable per-round state, owned by ``WizardGame``."""
|
||||
|
||||
round_number: int
|
||||
dealer: int
|
||||
hands: list[list[Card]]
|
||||
trump_card: Card | None
|
||||
trump_suit: Suit | None
|
||||
bids: list[int | None]
|
||||
tricks_won: list[int]
|
||||
current_trick: list[PlayedCard] = field(default_factory=list)
|
||||
trick_leader: int = 0
|
||||
trick_number: int = 1
|
||||
played_cards: list[Card] = field(default_factory=list)
|
||||
Reference in New Issue
Block a user