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>
This commit is contained in:
2026-09-27 10:28:53 +02:00
co-authored by Claude Opus 5.5
parent fde8e2fb2e
commit 21a2b044d9
16 changed files with 135 additions and 190 deletions
@@ -10,7 +10,6 @@ from .cards import Card, Suit, card_by_id
class Phase(str, Enum):
TRUMP_SELECTION = "trump_selection"
BIDDING = "bidding"
PLAYING = "playing"
FINISHED = "finished"
@@ -51,6 +50,8 @@ class TrickResult:
trick_number: int
cards: tuple[PlayedCard, ...]
winner: int
# The trump card of the round the trick was played in.
trump_card: Card | None = None
def to_dict(self) -> dict:
return {
@@ -58,6 +59,7 @@ class TrickResult:
"trick_number": self.trick_number,
"cards": [played.to_dict() for played in self.cards],
"winner": self.winner,
"trump_card": self.trump_card.to_dict() if self.trump_card else None,
}
@classmethod
@@ -67,6 +69,7 @@ class TrickResult:
trick_number=data["trick_number"],
cards=tuple(PlayedCard.from_dict(c) for c in data["cards"]),
winner=data["winner"],
trump_card=card_by_id(data["trump_card"]["id"]) if data.get("trump_card") else None,
)