Skip to content

Play With Bot Mode

Play With Bot mode allows users to play a full offline game of Dice Chess against a local bot. The bot can run two distinct heuristics:

  • Greedy Bot: Prioritizes capturing material or delivering mate.
  • Random Bot: Chooses random valid sequences of moves based on the rolled dice values.

The game flows according to the core Dice Chess domain rules: a player rolls 3 dice at the start of a turn, then has up to 3 micro-moves to consume those dice before transitioning control to the opponent.


To ensure maintainability, the module is divided into a high-cohesion, composed architecture under src/lib/playWithBot/. A slim orchestrator store coordinates user events and delegates core duties to dedicated reactive sub-systems.

graph TD
    Store["PlayWithBotStore (Orchestrator)"] -->|Composes| History["PlayWithBotHistory"]
    Store -->|Composes| Dice["PlayWithBotDice"]
    Store -->|Delegates to| Bot["PlayWithBotBot (AI Service)"]

The primary entry point and orchestrator for the game mode.

  • State ($state): gameStatus (idle, rolling, playing, bot_thinking, victory, defeat), playerColor, botAlgorithm, activeColor, and pendingPromotion.
  • Duties: Coordinates page/view entry, manages timed transitions, plays sound effects, saves local game summaries to IndexedDB via saveLocalGame, and exposes backward-compatible delegating properties to the UI.

2. PlayWithBotHistory (History & Navigation)

Section titled “2. PlayWithBotHistory (History & Navigation)”

Tracks game progress, moves, and supports interactive move navigation.

  • State ($state): historyMap (associates move index to position states), currentMoveIndex, maxMoveIndex, turnHistory, and currentTurnRecord.
  • Derived ($derived):
    • historyBlocks: Organizes individual micro-moves into clear, turn-by-turn visual groupings.
    • canGoToStart / canGoToEnd: State checks for disabling/enabling navigation buttons in the UI.
  • Duties: Logs valid moves, registers new positions, and allows step-by-step navigation through the played game.

Maintains the state of the active turn’s dice pool.

  • State ($state): currentDice (array of DieState objects containing value, allowed, and used flags) and isAnimatingRoll.
  • Derived ($derived): availableDiceValues (computes values of dice that are allowed and have not yet been used in the active turn).
  • Duties: Generates random dice pools, triggers rolling animations, and encapsulates usage mutations through markUsed and revertUse methods.

Isolates greedy and random algorithm move selection.

  • State: Stateless.
  • Duties: Interfaces asynchronously with the @rabestro/dicechess-engine via selectBestMove(fen, diceValues, algorithm). It formats inputs as standard DFEN strings and retrieves optimized move series.
  • Injectability: Features test-injections setBotDiceChessInstance and resetBotDiceChessInstance to seamlessly support mocked engine instances in test environments.

The module utilizes Svelte 5 Runes to maintain perfect reactive synchronization between UI components and decoupled store states:

  • $state: Keeps fields like currentDice, historyMap, and currentMoveIndex deeply reactive.
  • $derived / $derived.by: Automatically recomputes the UI board’s legalMovesDests and historyBlocks as soon as the active dice pool or move position changes.
  • $state.snapshot: Used in history state recording (dices: $state.snapshot(this.currentDice)) to capture frozen values of reactive proxies, preventing reactive leakage into historic blocks.

By separating history, dice, and bot AI into discrete modules, we are able to perform robust, isolated testing:

  • playWithBotHistory.test.ts: Verifies starting position initialization, turn history logging, and correct visual historyBlocks grouping.
  • playWithBotDice.test.ts: Exercises dice generation bounds (e.g., uppercase piece codes for White, lowercase for Black), animation states, and encapsulation flags.
  • playWithBotBot.test.ts: Simulates Greedy/Random heuristic recommendations and handles engine errors gracefully.
  • playWithBotStore.bot.test.ts: Tests bot integrations, turn transitions, victory/defeat statuses, and timeout delays.

All unit tests are run via Vitest in frontend PWA, maintaining a 100% green execution rate.


To match the @rabestro/dicechess-engine 1.2.0 capabilities, several high-fidelity gameplay features are integrated into the store:

Draws can be negotiated between the human player and the AI bot:

  • Player-Initiated Draws: The player can offer a draw during their turn when gameStatus is 'playing'. The bot evaluates the position asynchronously using the engine’s shouldBotAcceptDraw function to decide the outcome.
  • Bot-Initiated Draws: Before rolling dice on its turn, the bot evaluates the board state. If the engine’s shouldBotOfferDraw function returns true, the bot pauses its turn and shows a dedicated overlay modal for the player to accept or decline.
  • State Management: Tracked via playerCanOfferDraw, botCanOfferDraw, and activeDrawOffer ('player' | 'bot' | null).
  • The player can resign at any time during active play. Resigning instantly concludes the game with a 'defeat' status for the player.
  • The bot is strictly configured to never resign.
  • Timer Pausing: To prevent time exploits, the active game timer is paused (this.stopTimer()) when a draw offer is pending. It resumes (this.startTimer()) if the player declines the bot’s draw offer.
  • Race Condition Prevention: The async 1.2-second bot thinking delay in offerDraw() is protected by validating that this.startTime (the unique game session identifier) hasn’t changed. If the player resets or starts a new game during the delay, the draw offer is discarded without mutating the new session state.
  • When starting a game with a configured bet amount (bet > 0), the player’s balance is verified and debited.
  • Upon game conclusion, payouts are resolved:
    • Victory: The player receives double their bet (2 * bet).
    • Draw: The player is refunded their original bet (bet).
    • Defeat: The player forfeits the wagered bet.

  • frontend-pwa/src/lib/playWithBot/playWithBotStore.svelte.ts — The primary coordinating store.
  • frontend-pwa/src/lib/playWithBot/playWithBotHistory.svelte.ts — Game navigation and turn record-keeping.
  • frontend-pwa/src/lib/playWithBot/playWithBotDice.svelte.ts — Dice pool, states, and roll generators.
  • frontend-pwa/src/lib/playWithBot/playWithBotBot.ts — AI bot move calculations.
  • frontend-pwa/src/lib/playWithBot/index.ts — Consolidated module exports.