CI / Build and push docker image (push) Successful in 5m35s
Five-player briscola with a descending calling auction and a secret partner. Starting with the player after the dealer, each player bids a lower rank (A > 3 > K > H > J > 7 > 6 > 5 > 4 > 2) or passes; once the standing bid is the two the auction continues on points (62, 64, ...). The last player standing must bid, and the winner names any card of the won rank: its holder is the secret partner, or the caller plays alone when it is one of their own cards, and its suit becomes the trump. The calling side must reach 61 (or the raised target); a 60-60 deal with the plain target is a patta and is replayed. A match is a single deal, so the caller and partner (or the lone caller) against the other players map onto the platform's two-team result, Elo and match history. The rules live in tavolo.briscola.chiamata with the BriscolaChiamataEngine adapter registered alongside the other briscola variants; the partner's role and the side totals stay hidden until the called card is played. The web client gets a five-seat table, the auction panel with legal bids and point raises, the call picker, the reveal bands and a chiamata-aware final summary.
99 lines
4.9 KiB
Markdown
99 lines
4.9 KiB
Markdown
# tavolo-briscola
|
||
|
||
Briscola — the Italian trick-taking game — as a
|
||
[`tavolo-platform`](../tavolo-platform/README.md) game implementation.
|
||
Three variants share one rules core:
|
||
|
||
- `briscola` — the classic two-player game;
|
||
- `briscola_a_quattro` — four-player fixed-partnership briscola;
|
||
- `briscola_chiamata` — five-player briscola with a calling auction and a
|
||
secret partner.
|
||
|
||
## Contents
|
||
|
||
- `state.py` — `BriscolaState` (pure game data: phases, players, hands,
|
||
stock, face-up briscola, tricks, scores, deadlines), `PlayerState`,
|
||
`Card`, `TrickCard`, `Trick`, with JSON (de)serialization. No session
|
||
envelope, no transport, no I/O.
|
||
- `engine.py` — the pure rules engine for two- and four-player briscola:
|
||
deck, deals, trick resolution (trump first, then the led suit; strength
|
||
ace > three > king > horse > jack > 7 > 6 > 5 > 4 > 2), the draw order
|
||
(trick winner first, the face-up briscola last), card points (ace 11,
|
||
three 10, king 4, horse 3, jack 2), patta re-deals and the
|
||
target-score match end, deal-end acknowledgements and auto-play.
|
||
Deterministic and I/O-free apart from logging, so the whole rule set is
|
||
unit-testable.
|
||
- `chiamata.py` — the pure rules engine for five-player briscola
|
||
chiamata: `ChiamataState`/`ChiamataPlayer`/`Auction` (JSON
|
||
round-trip), the 8-card deal with no stock, the descending calling
|
||
auction with point raises, the winner's call (including calling one's
|
||
own card, which means playing alone), the called-card reveal, single-
|
||
deal scoring with the 60–60 patta and the auto-actions for timeouts.
|
||
- `errors.py` — briscola-specific errors (`CardNotInHand`); every other
|
||
failure mode is a shared `tavolo.platform.errors` subclass.
|
||
- `plugin.py` — `BriscolaEngine`, `BriscolaQuattroEngine` and
|
||
`BriscolaChiamataEngine` (`GameEngine`): the platform-facing adapters.
|
||
The first two validate the `target_score` creation option (61–120,
|
||
default 61) and extract the `MatchResult` (teams, winner, per-player
|
||
scores and the match summary persisted as the match's JSON `result`).
|
||
Briscola chiamata takes no creation options.
|
||
|
||
Timeouts are constructor arguments (`turn_timeout_seconds`,
|
||
`hand_ack_timeout_seconds`), wired from the environment by the
|
||
application composition root. Briscola chiamata uses the turn timeout
|
||
for its auction bids, the called-card choice and the plays; it never
|
||
enters the between-deals acknowledgement phase (a single deal ends the
|
||
match), so the hand-ack timeout is accepted but unused.
|
||
|
||
## Rules
|
||
|
||
### Briscola (two-player and four-player)
|
||
|
||
- Three cards per player; the next card is turned face up: its suit is
|
||
the trump (briscola) for the deal and it is the last card drawn.
|
||
- The winner of a trick is the highest trump, or the highest card of the
|
||
led suit when no trump was played. The winner takes the trick and leads
|
||
the next one.
|
||
- After each trick everyone draws back up to three cards, starting with
|
||
the trick winner.
|
||
- Card points total 120 per deal; a 60–60 deal is a *patta*, its points
|
||
are discarded and the deal is replayed. The first team to the target
|
||
score wins; a tie at or above the target is broken by another deal.
|
||
- Between deals of an unfinished match every player acknowledges the
|
||
summary (or the hand-end timeout deals on), exactly like scopone.
|
||
|
||
### Briscola chiamata (five-player)
|
||
|
||
- The whole 40-card deck is dealt out, eight cards each: there is no
|
||
stock and no face-up card.
|
||
- Starting with the player after the dealer, each player either passes
|
||
(leaving the auction for good) or bids a **lower** rank than the
|
||
standing bid on the ladder *A > 3 > K > H > J > 7 > 6 > 5 > 4 > 2*;
|
||
the first bidder may bid any rank. Once the standing bid is the two,
|
||
the auction continues on points instead (62, 64, …): the calling side
|
||
then has to reach the raised target. The last player standing must
|
||
bid, so a deal always gets a caller.
|
||
- The auction winner names any card of the winning rank. If the winner
|
||
holds it, they **play alone** against the other four; otherwise its
|
||
holder is the **secret partner** and the two form the calling side.
|
||
The called card's suit is the trump for the deal. The partner's
|
||
identity is hidden until the called card is played.
|
||
- Play follows briscola: the player after the dealer leads, the highest
|
||
trump (or highest led-suit card) takes the trick and leads the next
|
||
one; eight tricks exhaust every hand.
|
||
- The calling side (caller plus partner, or the lone caller) must reach
|
||
the declared target — 61 unless the auction raised it. With the plain
|
||
target a 60–60 deal is a patta and is replayed with the next dealer.
|
||
A match is a single deal, so the two sides map onto the platform's
|
||
two-team result (Elo rating, match history).
|
||
|
||
## Development (from `server/`)
|
||
|
||
```sh
|
||
.venv/bin/python -m unittest discover -s packages/tavolo-briscola/tests
|
||
.venv/bin/python -m mypy -p tavolo.briscola
|
||
```
|
||
|
||
`test_engine.py`/`test_plugin.py` cover the two classic variants;
|
||
`test_chiamata.py`/`test_chiamata_plugin.py` cover briscola chiamata.
|