A polished desktop UI (PySide6) for the supervised chess CNN in this repo.
Play against the trained ChessNet model, play pass-and-play with a
friend on one board, watch the model's policy live, review games, export
them to PGN, and learn with interactive lessons. The old tkinter GUI
(chess_gui.py) still works too.
Build the image:
docker build -t chessnet:0.7 .The GUI needs access to a display server. On Linux with X11, run:
xhost +local:docker
docker run --rm -it \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v "$(pwd)/checkpoints:/app/checkpoints:ro" \
chessnet:0.7The trained checkpoint is intentionally not included in the image. Mount
checkpoints/ as shown above so checkpoints/chess_model_best.pth
is available at runtime.
Requires Python 3.10+.
pip install -r requirements.txt
python main_menu.py # recommended entry point
python chess_app.py # dark theme (play window only)
python chess_app.py --light # light themeYou need a trained checkpoint at checkpoints/chess_model_best.pth
(86 MB). If it is missing, the app tells you exactly what to run:
python prepare_data.py # data/games.csv -> data/chess_data.npz
python train.py # masked training -> checkpoints/chess_model_best.pth-
Two-player pass & play: share the board with a friend — control flips to the side to move after every move. The model can still coach both sides.
-
Hint: ask ChessNet for its best move in any position (Ctrl+H), with the policy confidence shown in the insights panel.
-
PGN export: save the current game to a
.pgnfile (Ctrl+S or the PGN button) — open it in any chess tool. -
Puzzle of the Day: each calendar day maps to one of the 33 lessons (deterministic). Open it from the main menu card or with Ctrl+P.
-
Interactive Lessons: a learning mode with 33 structured chess puzzles. Each lesson gives you a position, a task, hints, and live ChessNet coaching. If you make a wrong move, the model can explain why the move is not the teaching idea and suggest better candidate moves. You can also press Show me to watch the correct move animated on the board.
-
Lesson levels & progress:
- Filter by Beginner / Intermediate / Advanced
- Random lesson button (prefers unsolved)
- Progress saved to
~/.chessnet_lesson_progress.json
-
Lesson coaching tools:
- Ask AI — asks ChessNet for its top candidate moves.
- Hint — shows the lesson hint.
- Show me — plays the correct answer move animated on the board.
- Reset — restarts the current lesson.
- Progress tracking — solved lessons are marked in the lesson list.
-
Board: SVG pieces (cburnett set), drag & drop or click-to-move, legal-move dots, capture rings, last-move + check highlights, smooth animated moves (with capture fades and castling), promotion picker.
-
Model insights: after every AI reply, the panel shows the model's top-5 candidate moves with animated softmax probability bars — you can literally watch the network's policy.
-
Move list: numbered SAN moves; click any move (or use ←/→, Esc for live) to review earlier positions.
-
Player cards: avatars, captured pieces, material advantage, turn indicator, "thinking" state.
-
Play options: choose White / Black / Random or two players; Low / Medium / High AI effort; undo (full move pair); board flip; animation toggle.
-
Themes: dark (default) and light, toggle live.
-
Sounds: move / capture / check / game-end, synthesized at startup (no asset files). Toggle with the ♪ button.
-
Stability improvements: AI inference runs on a worker thread, so the UI never freezes. Worker-thread lifetime is properly managed to avoid leaks when restarting games or closing windows.
-
AI Difficulty Slider: Smooth five-step difficulty slider (Easy / Casual / Medium / Hard / Expert) replacing the old combo box. The slider controls how strongly ChessNet plays — sampling, safeguards, and move selection all adapt smoothly.
-
AI Styles: Choose from five distinct playing styles:
- Balanced — solid, principled play
- Aggressive — prefers attacks, sacrifices, and complications
- Defensive — solid, prophylactic, safety-first
- Tactical — seeks tactics, sacrifices, and sharp play
- Positional — long-term strategy, prophylaxis, structure
-
AI Mood Indicator: The UI shows a compact mood indicator based on the current difficulty and playing style, with intensity ranging from Calm to Intense.
-
AI Mood History: During a game, recent AI mood states are shown as a short timeline, making difficulty/style changes easy to follow.
-
Adaptive Difficulty: optional mode that adjusts AI strength dynamically based on your play — ramps up when you're winning, eases off when you're struggling.
-
Animated Evaluation Bar: live position evaluation bar that smoothly animates between scores, showing White/Black advantage in real-time during play.
-
Live AI Thinking Telemetry: evaluation updates and thinking status are shown while the AI is working.
-
AI Session Summary: after a completed AI game, the result card shows the selected difficulty percentage/tier, playing style, mood, AI move count, and average AI thinking time for that game.
-
Move Quality Feedback & Game Analysis: after the game, get a detailed post-game analysis with:
- Accuracy score (percentage of moves matching or near ChessNet's top choices)
- Best moves / Inaccuracies / Mistakes / Blunders counts
- Per-move quality labels: Excellent, Good, Inaccuracy, Mistake, Blunder
- Per-move comparison: your move vs. ChessNet's best move
- Coach summary with actionable feedback
-
Persistent Player Statistics: accuracy tracking and game-by-game history saved across sessions.
Trained on ~20k Lichess games (1.08M positions, players rated 1200+), predicting the human move from the position, with legal-move masking during training and a strict game-level validation split (870 games the model never saw):
| Metric | Score |
|---|---|
| Top-1 accuracy | 40.9% |
| Top-5 accuracy | 76.6% |
In other words: 3 out of 4 human moves are among the model's five best guesses. (A pre-upgrade baseline — 4k games, no masking, leaky split — reached 32.4% top-1.)
ChessNet is a compact supervised CNN that maps a board position to a
distribution over moves. It does not search; it predicts which move a
human is likely to play.
Each position is encoded as a 15-plane tensor (board_to_tensor in
chess_utils.py). Boards are always encoded from White's perspective
(Black-to-move positions are mirrored):
| Planes | Content |
|---|---|
| 0–5 | White pieces (P, N, B, R, Q, K) |
| 6–11 | Black pieces (P, N, B, R, Q, K) |
| 12 | White kingside castling rights (full plane) |
| 13 | White queenside castling rights (full plane) |
| 14 | En passant target square (if any) |
Input 15×8×8
│
├─ Conv2d 15→64, k=3, pad=1 + BatchNorm + ReLU
├─ Conv2d 64→128, k=3, pad=1 + BatchNorm + ReLU
├─ Conv2d 128→128,k=3, pad=1 + BatchNorm + ReLU
├─ Conv2d 128→256,k=3, pad=1 + BatchNorm + ReLU
├─ Conv2d 256→256,k=3, pad=1 + BatchNorm + ReLU
│
├─ Flatten → 256×8×8 = 16,384
├─ Linear 16,384 → 1,024 + ReLU
├─ Dropout 0.3
└─ Linear 1,024 → 4,096 (move logits)
- 4,096 logits = every from-square × to-square pair (
64 × 64). - At train and play time, illegal moves are masked (logits set to −1e9) so softmax only runs over legal moves.
- Promotion is handled in decoding (pawn to last rank → queen by default).
| Total parameters | ~22.1M (22,093,696) |
| Convolutional stack | ~1.1M |
| Fully connected head | ~21.0M |
| Checkpoint | checkpoints/chess_model_best.pth (~86 MB) |
Masked cross-entropy on the human move played in the game, with a game-level validation split (no position leakage across train/val). Metrics: masked top-1 and top-5 accuracy.
python prepare_data.py # all games.csv -> chess_data.npz (positions,
# legal-move lists, game ids)
python train.py # masked training -> chess_model_best.pthprepare_data.py replays every game with python-chess, encoding each
position as a 15-plane tensor and recording the full legal-move list.
train.py trains with masked cross-entropy (illegal moves get −1e9
logits), evaluates masked top-1/top-5 on a strict game-level validation
split (5% of games the model never saw), early-stops on validation
top-1 with an LR plateau scheduler, and saves the best checkpoint —
not the last one.
The lesson content, move encoding and daily puzzle are covered by a torch-free test suite (lesson positions were regression-prone — several shipped positions were mathematically unsolvable before v0.6):
pip install chess numpy pytest
pytestA GitHub Actions workflow (.github/workflows/ci.yml) runs the suite
on every push and pull request.
python chess_app.py --screenshot out.png --plies 16 [--light]Renders the window after scripted model-vs-model plies and exits.
- Replaced the difficulty ComboBox with a smooth five-step AI difficulty slider.
- Added AI styles: Balanced, Aggressive, Defensive, Tactical, and Positional.
- Added an AI mood indicator combining difficulty intensity and playing style.
- Added per-game AI mood history showing recent mood transitions.
- Added adaptive difficulty mode.
- Added animated position evaluation and live AI thinking telemetry.
- Added move-quality feedback and a game analysis view.
- Added persistent player statistics and accuracy tracking.
- Added an end-of-game AI session summary with difficulty, style, mood, move count, and average thinking time.
- Added a production-ready
Dockerfilefor the ChessNet desktop app. - Documented Linux/X11 Docker usage and read-only checkpoint mounting.
- The image uses Python 3.11 and installs the system libraries required by PySide6.
Fixed
- Seven lesson positions were mathematically broken and shipped
unsolvable or misleading: Discovered Check and Double Check
(the bishop could never check the king on e8), Queen Checkmate
(no mate-in-1 existed), Pin and Skewer (the "answer" was a
plain capture, not a pin/skewer), plus the Fork position (white
started in check with the knight pinned) and Trading Pieces
(the knights did not attack each other). All 33 lessons are now
covered by regression tests (
tests/). - The Hint button in lessons visually revealed the answer on the board — it now shows only the text hint.
- Closing the play/lessons window left the hidden main menu running with no way back (zombie app). Both windows now return to the menu, from the close button, the X button, or the new ☰ Menu button.
- Background AI threads are now waited on window close — closing mid-inference no longer risks a "QThread destroyed while running" crash.
- The move-coaching evaluation ran a model forward pass on the UI thread on every human move (UI freeze). It now runs on a worker.
- The sound engine existed but was never created — the ♪ button toggled nothing. Sounds are now actually wired: move, capture, check and game-end.
train.pymultiplied logits by the 0/1 legal mask instead of masking with −1e9, ran a second unmasked forward pass per batch, never used its early-stopping/scheduler definitions, saved the last instead of the best model, and crashed on CPU-only machines (hardcodedcuda). Fully rewritten.prepare_data.pyexecuted at import time and used cwd-relative paths; both pipeline scripts now use script-relative paths and amain()guard.- A missing checkpoint now produces a clear, actionable error message.
- The play board no longer allows interaction after the game ended.
- Undo now works after game over (to take back a mate).
Added
- Two-player pass & play mode in the new-game dialog.
- Hint button in the play window (Ctrl+H).
- PGN export (Ctrl+S).
- Animation toggle button.
- Settings persistence (theme, sound, animations, AI effort) in
~/.chessnet_settings.json. - Torch-free test suite (
tests/, 160+ tests) and a GitHub Actions CI workflow. - Progress saving now happens on lesson close as well.
- Added Puzzle of the Day on the main menu (daily lesson from date).
- Added lesson difficulty levels with filter and Random button.
- Lesson progress persists across sessions.
- Expanded the interactive lesson set from 13 to 33 lessons.
- Added new lessons covering captures, pins, skewers, discovered and double checks, queenside castling, centre control, development, trading, defence, opposition, rook lifts, outposts, back-rank threats, pawn breaks, active king, and more mating patterns.
- Added a full Interactive Lessons mode.
- Added live ChessNet coaching for wrong lesson moves.
- Added Ask AI, Hint, Show me, and Reset lesson controls.
- Added lesson progress tracking and solved-lesson checkmarks.
- Added lesson keyboard shortcuts.
- Fixed lesson board interaction for positions that python-chess marks as game over because of insufficient material.
- Improved board click handling so pieces remain clickable in lesson puzzles.
- Improved lesson state handling so the board does not stay locked after wrong moves, AI hints, or answer animations.
- Sound toggle crash fixed — sound button no longer crashes when toggled rapidly.
- AI worker thread lifetime properly managed — no thread leaks on game restart.
- Promotion drag-cancel fixed — dragging promotion piece off-board no longer crashes.
This project was developed with assistance from multiple AI systems during different stages of coding, debugging, documentation, and feature development:
- ChatGPT 5.6 Luna
- Claude Sonnet 5
- Qwen 3.7 Plus
- GLM 5.2
- Grok 4.5
These AI systems were used as development assistants; the project code and final integration were reviewed and maintained by the project contributors.
- Piece art: cburnett
(CC BY-SA 3.0), embedded in
ui/pieces.pyandui/assets/. - Chess rules: python-chess.
- @sepehrtaji-dev — original author
- @MarziehNaseri2022 — fixes, tests, two-player mode, PGN export, settings
