Files
marvinandClaude Opus 5.5 21a2b044d9 Trump card: draw from the stack, no trump for wizards and jesters
- Deal the hands from the shuffled stack and draw the trump card from it,
  so the trump card is in nobody's hand and cannot be played
- A wizard or jester as trump card means no trump suit (previously a
  wizard let the dealer choose); remove the trump selection phase, the
  ChooseTrump action, the trump picker UI and the AI trump actions
- Completed tricks carry their round's trump card, so the table keeps
  showing the matching trump card while the last trick of a round is
  displayed
- Card corners are no longer rotated, so 6 and 9 cannot be confused
- Trump label explains why there is no trump (wizard, jester, last round)
- Tests: trump card never dealt, special cards give no trump, tricks keep
  their trump card

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 10:28:53 +02:00

63 lines
1.7 KiB
Python

"""Actions a player can take and their (de)serialization.
Actions are serialized as small JSON objects which are shared by the web
frontend, the game server and the AI player:
- ``{"type": "bid", "value": 2}``
- ``{"type": "play", "card": 17}``
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from .cards import Card, card_by_id
@dataclass(frozen=True, slots=True)
class Bid:
value: int
def to_dict(self) -> dict:
return {"type": "bid", "value": self.value}
@dataclass(frozen=True, slots=True)
class PlayCard:
card: Card
def to_dict(self) -> dict:
return {"type": "play", "card": self.card.id}
Action = Bid | PlayCard
def action_to_dict(action: Action) -> dict:
return action.to_dict()
def action_from_dict(data: dict[str, Any]) -> Action:
"""Parse an action from its JSON representation.
Raises ``ValueError`` if the data is malformed.
"""
if not isinstance(data, dict):
raise ValueError("Action must be an object")
kind = data.get("type")
try:
if kind == "bid":
value = data["value"]
if not isinstance(value, int) or isinstance(value, bool):
raise ValueError("Bid value must be an integer")
return Bid(value)
if kind == "play":
card_id = data["card"]
if not isinstance(card_id, int) or isinstance(card_id, bool):
raise ValueError("Card must be an integer id")
return PlayCard(card_by_id(card_id))
except KeyError as exc:
raise ValueError(f"Missing field {exc} in action") from exc
raise ValueError(f"Unknown action type: {kind!r}")