Add CLAUDE.md and Slovak game-rules doc
CLAUDE.md documents the engine/web architecture and dev commands for future Claude Code sessions. PRAVIDLA.md captures the full Bridzik rules (extracted from the engine) in Slovak. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## What this is
|
||||||
|
|
||||||
|
A web implementation of **Bridžik**, a Slovak 4-player trick-taking/bidding card game played with a 32-card Slovak/German-suited deck. The codebase is in mid-migration from a legacy server-rendered HTTP frontend to a realtime Socket.IO frontend; both still live in `api/`. Code, comments, and exception messages are mostly in **Slovak** — keep new strings consistent with that.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Run the app (starts on 0.0.0.0:5000)
|
||||||
|
python -m app # or: python app.py / python start.py — all just import `api`
|
||||||
|
|
||||||
|
# Run via Docker (app on :5000, debugpy on :5678)
|
||||||
|
docker-compose up --build
|
||||||
|
|
||||||
|
# Run the full test suite (pure-engine unittest)
|
||||||
|
python -m unittest tests -v
|
||||||
|
|
||||||
|
# Run a single test case / method
|
||||||
|
python -m unittest tests.StashCase
|
||||||
|
python -m unittest tests.StashCase.test_get_winner
|
||||||
|
```
|
||||||
|
|
||||||
|
There is no linter or build step configured.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Game engine — `bridzik.py` (the important part)
|
||||||
|
|
||||||
|
Pure Python, **no Flask dependency**. All game rules live here and are exercised directly by `tests.py`. The state is a strict nested hierarchy, each level enforcing turn order and completion before delegating down:
|
||||||
|
|
||||||
|
- **`Bridzik`** — a whole game = exactly **4 `Series`**.
|
||||||
|
- **`Series`** — exactly **8 `Round`s**; the starting player rotates per series/round.
|
||||||
|
- **`Round`** — a bidding (`guess`/"tip") phase then a play phase of `8 - round_number` **`Stash`es**. Each round deals fewer cards as `round_number` grows.
|
||||||
|
- **`Stash`** (a "kopka" = one trick) — 4 cards, one per player; `get_winner()` resolves it.
|
||||||
|
|
||||||
|
Key rules encoded in the engine:
|
||||||
|
- **`Card_colors.HEARTS` (červeň) is the permanent trump** — any heart beats any non-heart in `Stash.get_winner()`, and follow-suit logic in `Round.play_card` forces playing a heart when you can't follow the led suit.
|
||||||
|
- **`Card_values` are ordered** C7 < C8 < C9 < C10 < LOWER < UPPER < KING < ACE via custom comparison dunders.
|
||||||
|
- **Scoring**: a player who exactly matches their guess scores `10 + guess`, else 0 (`Round.get_points_summary`).
|
||||||
|
- The total of the 4 guesses may **not** equal the number of tricks (the last bidder is constrained) — see `Round.add_player_guess`.
|
||||||
|
|
||||||
|
Serialization: `Card.JSONEncoder` flattens a `Card` to `{color, value}` name strings. The double `json.loads(json.dumps(...))` pattern used throughout the API exists to strip escaped slashes after custom encoding.
|
||||||
|
|
||||||
|
### Web layer — `api/`
|
||||||
|
|
||||||
|
Two frontends coexist; **`api/__init__.py` is the active one**:
|
||||||
|
|
||||||
|
- **`api/__init__.py` — Socket.IO realtime server (current).** Defines `app`, `socketio`, and all `@socketio.on(...)` handlers (`create_game`, `register_player`, `start_game`, `play_card`, etc.). Supports **multiple concurrent games** via the module-global `games` dict keyed by game id (`gid`), with `Game`/`Player` wrapper classes and Socket.IO rooms. **The server is started as an import side-effect** — `socketio.run(...)` runs at the bottom of this module, which is why `app.py` and `start.py` are one-line `from api import app`.
|
||||||
|
- Known WIP/fixme spots: `create_game` hardcodes `gid = 'a'`; `play_card` references `get_player_cards` without calling it correctly. Expect rough edges here.
|
||||||
|
|
||||||
|
- **`api/routes.py` + `api/templates/` + `api/forms.py` — legacy server-rendered HTTP frontend (dormant/broken).** It imports `bridzikInstance` from `api`, but that single shared instance is **no longer defined** in `api/__init__.py` (commented out), so these routes will not run as-is. Treat this as reference for the old single-game flow, not as live code, unless you are deliberately reviving it.
|
||||||
|
|
||||||
|
- **`api/utils.py`** — `sort_card_list` (orders a hand by suit then value) and `get_points_sums` (totals standings across all series/rounds). Used by the legacy routes.
|
||||||
|
|
||||||
|
### Config & infra
|
||||||
|
|
||||||
|
- `config.py` holds a `Config` class with a dev `SECRET_KEY`; note the active `api/__init__.py` sets its own `SECRET_KEY` inline rather than loading this.
|
||||||
|
- `Dockerfile` targets Python 3.9, runs `python -m app`, and bundles `debugpy` for remote debugging on port 5678.
|
||||||
|
- `requirements.txt` pins `Flask-SocketIO` + `eventlet` (the chosen `async_mode`); the trailing `socket-cli` is marked for removal.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- New game-rule logic belongs in `bridzik.py` and should come with a `unittest` case in `tests.py` — keep the engine independent of Flask/Socket.IO.
|
||||||
|
- Raise `BridzikException` (Slovak message) for rule violations; the API layer catches it and re-emits a generic Slovak error to the client.
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
# Pravidlá hry Bridžik
|
||||||
|
|
||||||
|
Tento dokument popisuje pravidlá hry tak, ako sú implementované v hernom jadre
|
||||||
|
(`bridzik.py`). Slúži ako referencia pre hráčov aj vývojárov.
|
||||||
|
|
||||||
|
## Karty
|
||||||
|
|
||||||
|
Hrá sa s **32-kartovým balíčkom** sedmových (slovenských/nemeckých) kariet.
|
||||||
|
|
||||||
|
### Farby (4)
|
||||||
|
|
||||||
|
| Názov v kóde | Slovenský názov |
|
||||||
|
| ------------ | --------------- |
|
||||||
|
| `HEARTS` | červeň |
|
||||||
|
| `LEAVES` | zeleň |
|
||||||
|
| `ACORNS` | žaluď |
|
||||||
|
| `BELLS` | guľa |
|
||||||
|
|
||||||
|
**Červeň je vždy tromf (adut).** Červeň prebíja každú inú farbu.
|
||||||
|
|
||||||
|
### Hodnoty (8) — od najnižšej po najvyššiu
|
||||||
|
|
||||||
|
`sedmička (7) < osmička (8) < deviatka (9) < desiatka (10) < dolník < horník < kráľ < eso`
|
||||||
|
|
||||||
|
V kóde: `C7 < C8 < C9 < C10 < LOWER < UPPER < KING < ACE`.
|
||||||
|
|
||||||
|
## Štruktúra hry
|
||||||
|
|
||||||
|
Hru hrajú **4 hráči** (očíslovaní 0, 1, 2, 3). Celá hra má pevnú štruktúru:
|
||||||
|
|
||||||
|
- **Hra** = 4 **série** (séria 0 až 3).
|
||||||
|
- **Séria** = 8 **kôl** (kolo 0 až 7).
|
||||||
|
- **Kolo** = `8 − číslo_kola` **kopiek** (zdvihov).
|
||||||
|
|
||||||
|
V každom kole dostane každý hráč `8 − číslo_kola` kariet, takže počet kariet
|
||||||
|
postupne klesá:
|
||||||
|
|
||||||
|
| Číslo kola | Kariet na hráča | Počet kopiek v kole |
|
||||||
|
| ---------: | --------------: | ------------------: |
|
||||||
|
| 0 | 8 | 8 |
|
||||||
|
| 1 | 7 | 7 |
|
||||||
|
| 2 | 6 | 6 |
|
||||||
|
| 3 | 5 | 5 |
|
||||||
|
| 4 | 4 | 4 |
|
||||||
|
| 5 | 3 | 3 |
|
||||||
|
| 6 | 2 | 2 |
|
||||||
|
| 7 | 1 | 1 |
|
||||||
|
|
||||||
|
Celá hra teda obsahuje 4 × 8 = 32 kôl.
|
||||||
|
|
||||||
|
## Rozdávanie
|
||||||
|
|
||||||
|
Na začiatku každého kola sa balíček zamieša. Z vrchu sa odloží `4 × číslo_kola`
|
||||||
|
kariet a zvyšok sa rozdá: každý zo 4 hráčov dostane `8 − číslo_kola` kariet.
|
||||||
|
|
||||||
|
## Kto začína
|
||||||
|
|
||||||
|
- **Sériu** otvára hráč s rovnakým číslom, ako je číslo série (séria 0 → hráč 0,
|
||||||
|
séria 1 → hráč 1, …).
|
||||||
|
- **Kolo** otvára hráč `(prvý_hráč_série + číslo_kola) mod 4`, čiže začínajúci
|
||||||
|
hráč sa medzi kolami posúva.
|
||||||
|
|
||||||
|
## Priebeh kola
|
||||||
|
|
||||||
|
Každé kolo má dve fázy: **tipovanie** a následne **hranie kariet**.
|
||||||
|
|
||||||
|
### 1. Tipovanie (bridžik)
|
||||||
|
|
||||||
|
Hráči postupne (počnúc začínajúcim hráčom kola, v smere poradia) zadávajú **tip** —
|
||||||
|
koľko kopiek (zdvihov) v tomto kole získajú.
|
||||||
|
|
||||||
|
- Tip musí byť v rozsahu `0` až `počet kopiek v kole` (`8 − číslo_kola`).
|
||||||
|
- **Pravidlo bridžika:** posledný (štvrtý) tipujúci hráč nesmie zadať taký tip,
|
||||||
|
pri ktorom by sa **súčet všetkých štyroch tipov rovnal počtu kopiek** v kole.
|
||||||
|
Inými slovami, súčet tipov sa nikdy nesmie presne rovnať počtu zdvihov — vždy
|
||||||
|
musí niekto „prebrať" alebo „nedobrať".
|
||||||
|
- Každý hráč zadáva tip iba raz a iba keď je na rade.
|
||||||
|
|
||||||
|
### 2. Hranie kariet
|
||||||
|
|
||||||
|
Po dokončení tipovania sa hrá `8 − číslo_kola` kopiek (zdvihov).
|
||||||
|
|
||||||
|
- **Prvú kopku** otvára hráč s **najvyšším tipom**. Pri zhode tipov začína ten,
|
||||||
|
kto je skôr v poradí (počítané od začínajúceho hráča kola).
|
||||||
|
- **Každú ďalšiu kopku** otvára **víťaz predchádzajúcej kopky**.
|
||||||
|
|
||||||
|
#### Povinnosť priznať farbu
|
||||||
|
|
||||||
|
Keď je na stole vynesená (prvá) karta kopky, ďalší hráči musia dodržať:
|
||||||
|
|
||||||
|
1. Ak má hráč farbu vynesenej karty → **musí priznať farbu** (zahrať kartu tej
|
||||||
|
istej farby).
|
||||||
|
2. Ak farbu vynesenej karty nemá, ale má **červeň** → **musí zahrať červeň**
|
||||||
|
(tromf).
|
||||||
|
3. Ak nemá ani vynesenú farbu, ani červeň → môže zahrať **ľubovoľnú** kartu.
|
||||||
|
|
||||||
|
Hráč môže zahrať len kartu, ktorú má v ruke, a iba keď je na rade.
|
||||||
|
|
||||||
|
#### Vyhodnotenie kopky
|
||||||
|
|
||||||
|
Po zahraní všetkých 4 kariet sa určí víťaz kopky:
|
||||||
|
|
||||||
|
- **Červeň prebíja** každú inú farbu. Ak v kopke padla aspoň jedna červeň,
|
||||||
|
vyhráva **najvyššia červeň**.
|
||||||
|
- Ak nepadla žiadna červeň, vyhráva **najvyššia karta vynesenej farby**.
|
||||||
|
- Karty iných farieb (ktoré nie sú ani vynesená farba, ani červeň) kopku
|
||||||
|
vyhrať nemôžu.
|
||||||
|
|
||||||
|
Víťaz kopky vynáša do nasledujúcej kopky.
|
||||||
|
|
||||||
|
## Bodovanie
|
||||||
|
|
||||||
|
Body sa počítajú po každom dokončenom kole:
|
||||||
|
|
||||||
|
- Ak sa hráčov **tip presne zhoduje** s počtom kopiek, ktoré v kole získal,
|
||||||
|
dostane **`10 + tip`** bodov.
|
||||||
|
- Ak sa tip nezhoduje (získal viac alebo menej kopiek), dostane **0 bodov**.
|
||||||
|
|
||||||
|
Príklad: hráč tipoval 3 a získal presne 3 kopky → 13 bodov. Ak by získal 2 alebo
|
||||||
|
4 kopky → 0 bodov.
|
||||||
|
|
||||||
|
Celkové skóre hráča je súčet bodov zo všetkých kôl všetkých sérií. Vyhráva hráč
|
||||||
|
s najvyšším celkovým súčtom po dohraní všetkých 4 sérií.
|
||||||
|
|
||||||
|
## Ukončenie
|
||||||
|
|
||||||
|
- **Kolo** je ukončené, keď sú odohrané všetky kopky.
|
||||||
|
- **Séria** je ukončená po 8 kolách.
|
||||||
|
- **Hra** je ukončená po 4 sériách.
|
||||||
Reference in New Issue
Block a user