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:
Tim
2026-06-13 23:40:42 +02:00
parent d47eb03bce
commit 821c7e81ce
2 changed files with 196 additions and 0 deletions
+67
View File
@@ -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
View File
@@ -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``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.