Files
Wizard/docs/02-game-rules.md
2026-09-27 11:26:10 +02:00

4.8 KiB
Raw Permalink Blame History

2. Game rules as implemented

This chapter lists every rule the code enforces and where. The original rules are in wizard_instructions/; where this implementation deliberately differs from them, it is marked (house rule).

All rule code lives in the game engine: stateless helpers in wizard_server/game_logic/wizard_game/rules.py, flow in game.py.

Cards

60 cards (cards.py):

Cards Count Notes
Number cards 1–13 in red, yellow, green, blue 52 the only cards with a suit
Wizards 4 always highest
Jesters 4 always lowest

Every card has a fixed id 0–59, used in JSON and in the AI encoding:

Ids Cards
0–12 red 1–13
13–25 yellow 1–13
26–38 green 1–13
39–51 blue 1–13
52–55 wizards
56–59 jesters

Formula for number cards: id = suit_index * 13 + (rank - 1) with suit order red, yellow, green, blue.

Players and rounds

  • 3 to 6 players (rules.MIN_PLAYERS, rules.MAX_PLAYERS).
  • Number of rounds = 60 // players (rules.total_rounds): 3 → 20, 4 → 15, 5 → 12, 6 → 10.
  • In round n every player gets n cards, so round n has n tricks.

Dealing, dealer and starting player

WizardGame._deal:

  1. A fresh 60-card stack is shuffled every round.
  2. Cards are dealt one at a time from the top of the stack, starting with the player left of the dealer.
  3. The next card of the stack is turned up as the trump card. It is taken off the stack: it is in nobody's hand and can never be played.
  4. In the last round all 60 cards are dealt, so there is no trump card.

The first dealer is random (or first_dealer= in tests). The dealer moves one seat to the left every round. The player left of the dealer (the starter) bids first and leads the first trick.

Trump

rules.trump_suit(trump_card):

Trump card Trump suit
number card its suit
wizard no trump (house rule — the original rules let the dealer choose)
jester no trump
none (last round) no trump

Bidding

WizardGame._allowed_bids and _bid:

  • Players bid in turn, starting with the starter; the dealer bids last.
  • A bid is any number from 0 to the number of cards in hand.
  • The sum of all bids may never equal the number of cards in hand (house rule — in the original rules this is the optional "notequal" variant; here it is always on). Only the last bidder is restricted: the one value that would make the sum equal the round number is removed from their legal bids. Example: round 5, the others bid 1, 2 and 0 → the last player may bid anything except 2.
  • Option hidden bids ("hiddentip", GameOptions.hidden_bids): while bidding is in progress, each player only sees their own bid; everyone can see who has already bid (Observation.has_bid). All bids are revealed as soon as the last bid is placed (WizardGame.observation). Note: because of the sum rule, the last bidder can deduce the sum of the hidden bids from the forbidden value.

Playing a trick

The starter leads the first trick; afterwards the winner of the previous trick leads.

Which suit must be followed — rules.lead_suit(trick)

Look at the cards of the trick in playing order:

  • Jesters are skipped.
  • If the first non-jester card is a wizard, there is no suit to follow for the whole trick.
  • If the first non-jester card is a number card, its suit must be followed.
  • If only jesters were played so far, there is no suit yet (the next number card will set it).

Which cards may be played — rules.legal_cards(hand, trick)

  • Wizards and jesters may always be played.
  • If there is a lead suit and the player holds at least one number card of that suit, they must play a card of that suit (or a wizard/jester).
  • Otherwise any card may be played.

Who wins the trick — rules.trick_winner(trick, trump)

In this order:

  1. The first wizard played wins.
  2. Otherwise the highest trump wins.
  3. Otherwise the highest card of the lead suit wins.
  4. If only jesters were played, the first jester wins.

Scoring

rules.round_score(bid, tricks) at the end of each round:

Result Points
tricks == bid 20 + 10 × tricks
tricks ≠ bid −10 × |tricks − bid|

Examples: bid 0, took 0 → +20. Bid 3, took 3 → +50. Bid 2, took 0 → −20.

End of the game

After the last round (WizardGame._complete_round) the phase becomes finished. All players with the highest total score win (ties are possible, WizardGame.winners).

Rule variants from the original that are not implemented

  • dmmixed and wiztournament (tournament card distributions).
  • The dealer choosing trump when a wizard is turned up (replaced by the house rule "wizard = no trump").