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.
This commit is contained in:
+56
-7
@@ -16,9 +16,10 @@ and
|
||||
scientifico, the four-player, fixed-partnership variant of the classic
|
||||
Italian card game: pure rules plus the platform adapter.
|
||||
- **`tavolo-briscola`** (`packages/tavolo-briscola/`) — briscola, the
|
||||
Italian trick-taking game, in its classic two-player (`briscola`) and
|
||||
four-player partnership (`briscola_a_quattro`) variants: pure rules
|
||||
plus the platform adapter.
|
||||
Italian trick-taking game, in its classic two-player (`briscola`),
|
||||
four-player partnership (`briscola_a_quattro`) and five-player
|
||||
called-partner (`briscola_chiamata`) variants: pure rules plus the
|
||||
platform adapter.
|
||||
- **`tavolo-app`** (`packages/tavolo-app/`) — the
|
||||
composition root wiring the platform to the games, with the
|
||||
environment-driven settings and the SPA shell.
|
||||
@@ -236,7 +237,9 @@ aggregate with `max`, not `sum`.
|
||||
as reported by the engine (`result` JSON — for scopone: both teams'
|
||||
final scores, winner, target score, hands played and the per-hand
|
||||
audit; for briscola: the final scores, winner, target score, deals
|
||||
played and the per-deal audit).
|
||||
played and the per-deal audit; for briscola chiamata: the calling side's
|
||||
points against the defenders', the declared target, the called card and
|
||||
whether the caller played alone).
|
||||
- `match_player` — one row per participant: the OIDC `sub`, display name,
|
||||
seat, game-defined team label (nullable), whether they won, the points
|
||||
they scored, the Elo change the match produced (`elo_delta`) and
|
||||
@@ -275,7 +278,7 @@ All endpoints except `/api/health`, `/api/docs`, `/api/openapi.json`,
|
||||
| Method | Path | Description |
|
||||
|---|---|---|
|
||||
| `GET` | `/api/game-types` | The games the platform can host (for the creation dropdown), each with its `options_schema` |
|
||||
| `POST` | `/api/games` | Create a lobby game. Optional body `{"game_type": "scopone_scientifico", "options": {"target_score": 11, "napola": true, "asso_pigliatutto": false}}`; briscola games use `{"game_type": "briscola"}` or `{"game_type": "briscola_a_quattro"}` with an optional `{"target_score": 61}`. Returns the lobby (`{id, join_code, players, seats_open, ...}`) |
|
||||
| `POST` | `/api/games` | Create a lobby game. Optional body `{"game_type": "scopone_scientifico", "options": {"target_score": 11, "napola": true, "asso_pigliatutto": false}}`; briscola games use `{"game_type": "briscola"}` or `{"game_type": "briscola_a_quattro"}` with an optional `{"target_score": 61}`, and briscola chiamata uses `{"game_type": "briscola_chiamata"}` with no options. Returns the lobby (`{id, join_code, players, seats_open, ...}`) |
|
||||
| `POST` | `/api/games/join` | Join with `{"code": "ABC123"}`. The last player triggers the start and gets the game view back |
|
||||
| `GET` | `/api/games/preview?code=ABC123` | Pre-join summary of the lobby behind a code: game name/description, seated players, open seats and the engine-echoed options. `404` when the code is unknown |
|
||||
| `GET` | `/api/games/{id}` | Game snapshot. Seated players get the personalized view (own hand plus the join code); anyone else gets the read-only spectator view: table, scores, captured counts and scope, no hands and no join code |
|
||||
@@ -341,6 +344,24 @@ For briscola (`briscola`, `briscola_a_quattro`) the game actions are
|
||||
every player has acknowledged, or automatically after
|
||||
`HAND_ACK_TIMEOUT_SECONDS`.
|
||||
|
||||
For briscola chiamata the game actions are the calling auction plus play:
|
||||
|
||||
```json
|
||||
{"action": "bid", "rank": 3}
|
||||
{"action": "bid", "points": 64}
|
||||
{"action": "pass"}
|
||||
{"action": "call", "card": "03D"}
|
||||
{"action": "play", "card": "04C"}
|
||||
```
|
||||
|
||||
- `bid` with a `rank` calls a lower rank than the standing bid
|
||||
(`A > 3 > K > H > J > 7 > 6 > 5 > 4 > 2`); with `points` it raises the
|
||||
target once the standing bid is the two.
|
||||
- `pass` leaves the auction; the last player standing must bid.
|
||||
- `call` names any card of the won rank; naming one of your own cards
|
||||
means playing alone.
|
||||
- `play` follows briscola: any card in hand is legal.
|
||||
|
||||
After every accepted move the new state is broadcast to every connected
|
||||
client, spectators included.
|
||||
|
||||
@@ -353,7 +374,10 @@ is required), so a disconnected or idle player cannot stall the match. The
|
||||
timeout is `TURN_TIMEOUT_SECONDS` (default 30); the auto-played move is
|
||||
broadcast like any other. Deadlines fire from the shared `tavolo:deadlines`
|
||||
queue (see above), not from timers tied to client connections, so the
|
||||
match keeps progressing even with every player disconnected.
|
||||
match keeps progressing even with every player disconnected. Briscola
|
||||
chiamata uses the same timeout for its auction bids (auto-bid or
|
||||
auto-pass) and for the called-card choice (a random suit of the won
|
||||
rank).
|
||||
|
||||
### Hand-end summary
|
||||
|
||||
@@ -416,6 +440,30 @@ player must dismiss. A play attempted in this phase is rejected with an
|
||||
four players in two fixed partnerships (seats 0/2 vs 1/3, partners
|
||||
opposite).
|
||||
|
||||
### Briscola chiamata
|
||||
|
||||
- 40-card Italian deck, eight cards each for five players: the whole deck
|
||||
is dealt, so there is no stock and no face-up card.
|
||||
- The calling auction starts with the player after the dealer: each
|
||||
player either passes (leaving the auction) or bids a lower rank than
|
||||
the standing bid (*A > 3 > K > H > J > 7 > 6 > 5 > 4 > 2*); once the
|
||||
standing bid is the two, the auction continues on points (62, 64, …).
|
||||
The last player standing must bid, so every deal gets a caller.
|
||||
- The winner names any card of the won rank. If the winner holds it, the
|
||||
caller plays 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; the partner's identity stays hidden until the
|
||||
called card is played.
|
||||
- Play and trick resolution follow briscola; eight tricks exhaust every
|
||||
hand. The calling side must reach the declared target (61 unless
|
||||
raised); 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 caller
|
||||
and partner (or the lone caller) against the other players map onto
|
||||
the platform's two-team result, Elo and history.
|
||||
- Auction bids, the called-card choice and the plays all have their own
|
||||
`TURN_TIMEOUT_SECONDS` deadlines (an absent player is auto-bid,
|
||||
auto-called or auto-played for).
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
@@ -493,8 +541,9 @@ packages/tavolo-briscola/ # briscola game (own pyproject + tests)
|
||||
src/tavolo/briscola/
|
||||
├── state.py # BriscolaState / PlayerState / Card / Trick, JSON (de)serialization
|
||||
├── engine.py # pure briscola rules (2- and 4-player)
|
||||
├── chiamata.py # pure briscola chiamata rules (5-player, auction, secret partner)
|
||||
├── errors.py # briscola-specific rule violations
|
||||
└── plugin.py # BriscolaEngine + BriscolaQuattroEngine adapters
|
||||
└── plugin.py # BriscolaEngine + BriscolaQuattroEngine + BriscolaChiamataEngine
|
||||
packages/tavolo-app/ # deployable app: composition root (own pyproject)
|
||||
src/tavolo/
|
||||
├── app.py # session/OIDC/Tortoise/OpenAPI/Platform/DeadlineScheduler mixins
|
||||
|
||||
Reference in New Issue
Block a user