4.8 KiB
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:
- A fresh 60-card stack is shuffled every round.
- Cards are dealt one at a time from the top of the stack, starting with the player left of the dealer.
- 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.
- 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:
- The first wizard played wins.
- Otherwise the highest trump wins.
- Otherwise the highest card of the lead suit wins.
- 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
dmmixedandwiztournament(tournament card distributions).- The dealer choosing trump when a wizard is turned up (replaced by the house rule "wizard = no trump").