Files
bridzik/CLAUDE.md
T
tim 821c7e81ce 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>
2026-06-13 23:40:42 +02:00

4.5 KiB

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

# 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 Rounds; the starting player rotates per series/round.
  • Round — a bidding (guess/"tip") phase then a play phase of 8 - round_number Stashes. 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-effectsocketio.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.pysort_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.