Practice Mode
Overview
Section titled “Overview”Practice mode lets users solve saved TrainingPuzzle entries from their own collection.
Unlike trainer playback validation, Practice mode validates answers by comparing the final board state (normalized FEN) rather than the exact sequence of micro-moves.
Practice mode has two usage variants:
- Authenticated practice session (
PracticeView+practiceStore) with spaced-repetition attempt tracking. - Shared puzzle screen (
SharedPuzzleView) for a single public puzzle link without navigation menus.
- User starts a session from
PracticeView. - Frontend requests the next puzzle from
GET /api/v1/training-puzzles/next. ActivePuzzlerenders:- interactive board
- puzzle dice
- live timer
- User manipulates the board and clicks Check Answer.
- Frontend extracts the piece placement part of the current FEN and compares it to the puzzle’s
normalized_final_fenpiece placement part. - Frontend sends attempt result to
POST /api/v1/training-puzzles/{id}/attemptswith elapsed time. - User moves to the next puzzle.
Session State Model
Section titled “Session State Model”practiceStore drives one explicit state machine:
idle— lobby view, waiting for user action.playing— one active puzzle loaded and interactive.finished— reserved for future session summary mode.
Primary transitions:
startSession()→idle -> playingfetchNextPuzzle()keepsplayingand swapscurrentPuzzleendSession()resets toidle
Frontend Architecture
Section titled “Frontend Architecture”src/views/PracticeView.svelte- Handles lobby/start flow and renders the active puzzle session UI.
src/components/ActivePuzzle.svelte- Puzzle interaction container (board, timer, reset, check, feedback, next).
src/lib/practiceStore.svelte.ts- Session state + API orchestration (
startSession,fetchNextPuzzle,submitAttempt,endSession).
- Session state + API orchestration (
src/components/ChessgroundBoard.svelte- Reused in prop-driven mode for puzzle board state and reset signals.
src/components/DiceBox.svelte- Reused with dice overrides for puzzle dice display.
src/components/TopNavigationBar.svelte- Practice actions: share puzzle, open source game, notes, deactivate.
Validation Logic
Section titled “Validation Logic”Validation uses exact equality on the piece placement FEN field only (the first field).
getFenBoardPart(current_fen) === getFenBoardPart(solution_fen)
Active color, castling rights, en-passant targets, and move counters are ignored during validation.
This keeps validation aligned with puzzle outcome semantics in Dice Chess, where multiple micro-move paths can still produce the same correct final position.
Attempt Logging and Puzzle Lifecycle
Section titled “Attempt Logging and Puzzle Lifecycle”- Correct/incorrect result is sent to
POST /api/v1/training-puzzles/{id}/attempts. - Backend updates denormalized counters (
success_count,failure_count,last_attempted_at). - Deactivate action sets
is_active=falseand immediately requests the next available puzzle.
Sharing from Practice
Section titled “Sharing from Practice”When the user presses Share in practice mode, the app creates a puzzle link, not a game-position link:
- Share URL:
/api/share/puzzle/{puzzle_id} - OG image:
/api/v1/training-puzzles/{puzzle_id}/preview.png - Redirect target:
/?puzzle={puzzle_id}
The shared target is an isolated “Guess the Move” screen without global app navigation.
Timer Semantics
Section titled “Timer Semantics”- Timer starts when a puzzle is loaded and visible.
- Timer updates continuously in the UI (
MM:SS). - Resetting the board position (
Resetbutton) does not reset the timer (the user is still thinking). - Timer stops at answer check.
- Exact elapsed milliseconds are sent as
time_spent_msfor spaced-repetition statistics.
Key Files
Section titled “Key Files”frontend-pwa/src/views/PracticeView.sveltefrontend-pwa/src/components/ActivePuzzle.sveltefrontend-pwa/src/lib/practiceStore.svelte.tsfrontend-pwa/src/utils/fenUtils.tsfrontend-pwa/src/lib/api/client.tsfrontend-pwa/src/views/SharedPuzzleView.svelte