Add scopa: classic two-player and scopa a quattro

New tavolo-scopa package with a pure rules engine and the platform
adapters for two-player scopa and four-player fixed-partnership scopa a
quattro: three cards each and four on the table, capture by rank or sum,
sweep for scope and score carte/denara/settebello/primiera.

The optional asso pigliatutto creation option turns either variant into
scopa d'assi (an ace sweeps the whole table and scores no scopa), reusing
scopone's rule semantics.

Wire both engines into the app and the Docker install, add the scopa
table view to the SPA (duo and four-seat layouts, deck count,
captured/scope stats, hand-summary and final screens, player names in the
two-player summary), and cover the rules, the platform contract, the
REST/WebSocket flows, match persistence and Elo.
This commit is contained in:
2026-10-09 14:45:20 +08:00
parent 9eea293471
commit 68200bbe62
27 changed files with 3401 additions and 116 deletions
+42
View File
@@ -0,0 +1,42 @@
# tavolo-scopa
Scopa — the classic Italian fishing game — in its two-player form and in
the four-player fixed-partnership variant (*scopa a quattro*), as
[`tavolo-platform`](../tavolo-platform/README.md) game implementations.
The optional *asso pigliatutto* creation option turns either variant into
**scopa d'assi**.
## Contents
- `state.py` — `ScopaState` (pure game data: phases, players, hands,
table, the deck persisting between rounds, scores, deadlines),
`PlayerState`, `Card`, `Move`, with JSON (de)serialization. No session
envelope, no transport, no I/O.
- `engine.py` — the pure rules engine: deck, legal captures, plays,
auto-play, round re-dealing, hand scoring (carte, denara, settebello,
primiera, scope), the optional asso pigliatutto capture, hand-end
acknowledgements. Deterministic and I/O-free apart from logging, so the
whole rule set is unit-testable.
- `errors.py` — scopa-specific errors (`CardNotInHand`); every other
failure mode is a shared `tavolo.platform.errors` subclass.
- `plugin.py` — `ScopaEngine` (two players) and `ScopaQuattroEngine`
(four players in fixed partnerships): the platform-facing adapters.
They translate create/join/websocket actions/deadlines into
rules-engine calls and back, validate the
`target_score`/`asso_pigliatutto` creation options, and extract the
`MatchResult` (teams, winner, per-player scores and the match summary
persisted as the match's JSON `result`).
Timeouts are constructor arguments (`turn_timeout_seconds`,
`hand_ack_timeout_seconds`), wired from the environment by the
application composition root.
## Development (from `server/`)
```sh
.venv/bin/python -m unittest discover -s packages/tavolo-scopa/tests
.venv/bin/python -m mypy -p tavolo.scopa
```
`test_engine.py` covers the pure rules; `test_plugin.py` covers the
platform contract (actions, deadlines, serialization, results).