This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A Rust/Yew WebAssembly application that solves the numbers round from the British game show "Countdown". Users input 6 numbers and a target (1-999), and the solver finds solutions using basic arithmetic operations (+, -, *, /).
# Run all unit tests
cargo test
# Run a single test by name
cargo test test_name
# Check formatting (CI enforces this)
cargo fmt --check
# Fix formatting
cargo fmt
# Build WASM (requires trunk and wasm32 target)
trunk build --release
# Local development server
trunk serveNote: Tailwind CSS is automatically compiled via Trunk pre-build hook — npm run build runs before each trunk build or trunk serve. The source CSS is styles/main.css; styles/output.css is generated and committed.
# Install dependencies (first time)
cd tests/e2e && uv sync
uv run playwright install chromium --with-deps
# Run all E2E tests (requires a running server on port 8080)
cd tests/e2e && uv run pytest tests/
# Run a single E2E test file
cd tests/e2e && uv run pytest tests/test_solver.pyStart the server for E2E tests with: python3 -m http.server 8080 --directory ./dist
rustup target add wasm32-unknown-unknown
cargo install trunk wasm-bindgen-cli
npm installThe app has two screens managed by App (src/app.rs) via a single use_state:
-
GameProvider(src/components/game_provider.rs) — shown when no game is active. Presents buttons to start a game (Random, Custom Split, Manual Entry). Only Random Game is currently wired up; it callsGame::default()and emits the game upward. -
GameBoard(src/components/game_board.rs) — shown once a game is active. Displays the target and 6 board tiles, a Solve button, and a Reset button. Solving is synchronous and updates aSolutionStateenum (NotAttempted→Solving→Solved(solution)/NotFound). The solution is rendered as a step-by-step list with the resulting board tiles shown after each operation, the newly produced number highlighted in green.
Board (src/game/board.rs)
- Exactly 6 numbers, stored sorted ascending as
Vec<u32> - Valid numbers: 1–10 (each up to twice), 25/50/75/100 (each once)
BoardBuildervalidates rules on construction;BoardAdjusteris used by the solver to produce child board states (remove two operands, add result) without re-validating rules.
Game (src/game/game.rs)
- Wraps a
Board+ target (u16, valid range 1–999) - Implements
Problem;is_solved()returns true if the target is already on the board
solver/solver.rs defines the core traits and types:
Problemtrait:is_solved() -> boolSolver<P, S>trait:solve() -> Option<Solution<P, S>>Solution<P, S>: holds the originalProblemand aVec<Instruction<S>>Instruction<S>: holds a boardstate: Sandoperation: Option<Operation>. The first instruction always hasoperation = None(initial board state); subsequent instructions each carry theOperationthat produced that state.Operation:{ left, operator, right, result }— always expressed as larger op smaller for subtraction/division
IterativeDeepeningSolver (src/solver/iterative_deepening.rs)
- Iterative deepening DFS over board states, depth limit 1–6 (max 6 operations)
generate_children(board)returnsVec<(Board, Operation)>— all valid single-operation successors- Uses a
HashSet<Board>for the explored set and aVec<StateTraversal>frontier;StateTraversalforms a linked list back to the root for path reconstruction - Subtraction skips equal operands (result would be 0); division only applies when the result is a whole number
styles/main.css is the Tailwind source. styles/output.css is compiled and committed — update CSS classes in .rs files and let the Trunk pre-build hook regenerate it, or run npm run build manually.
Runs on push to main: cargo fmt --check → cargo test → trunk build --release → E2E tests against the built dist → deploy to Azure Static Web Apps via Bicep deployment stack.