mcts-web is a React playground for experimenting with Monte Carlo Tree Search across several turn-based board games. It lets you play moves manually, hand control to the AI, auto-play full games, inspect move history, and view the current search tree while tuning MCTS settings.
Current games:
- Connect Four
- Dobutsu Shogi
- Tic-Tac-Toe
- Ultimate Tic-Tac-Toe
- Filler
- Onitama
- Othello
- React 18 + TypeScript
- Vite for local development and builds
- Tailwind CSS for styling
multimctsfor the core search engine- Vitest + Testing Library for tests
Use Node 20 to match CI.
npm install
npm run devOpen the local Vite URL and choose a game from the selector. The app starts on TicTacToe.
npm run dev # start the local dev server
npm run benchmark # benchmark deterministic MCTS search scenarios
npm run benchmark:complexity -- --samples 100 --max-plies 160 # generate profile data
npm run benchmark:compare -- origin/main HEAD # compare two refs
npm run benchmark:strength -- origin/main HEAD # play head-to-head matches between two refs
npm run lint # run ESLint
npm run test # run tests once
npm run build # type-check and build for production
npm run preview # preview the production buildIf you prefer make, the repo also provides make setup, make lint, make test, and make build.
The session view exposes the same controls for every game:
r: resetz/x: undo / redoh: toggle historyn: request one AI movep: toggle auto-playa: toggle auto-reply
The right panel shows the current search tree and the active MCTS settings. Search trees are reused across repeated searches and advanced when the chosen move already exists in the explored tree.
Below the search tree, the Profile panel shows pre-generated per-game profiling data. Its expanded/collapsed state is persisted locally.
The repo includes a small CLI harness for measuring raw MCTS search speed on deterministic positions outside the browser. That makes branch-to-branch comparisons much less noisy than timing the UI by hand.
npm run benchmark -- --iterations 5000 --samples 25
npm run benchmark -- --game Onitama --iterations 10000
npm run benchmark:complexity -- --samples 100 --max-plies 160
npm run benchmark:compare -- origin/main HEAD --iterations 5000 --samples 25
npm run benchmark:strength -- origin/main HEAD --iterations 3000The throughput compare command creates temporary worktrees for both refs, injects the benchmark harness, and prints a rounds-per-second delta. The strength compare command uses the same deterministic scenarios to play equal-budget head-to-head games while swapping who moves first.
The complexity profiler samples full games with deterministic random playouts and writes chart-ready JSON to public/generated/profile.json. It reports branching by ply and ply bucket, game-length distributions, truncation counts, cumulative tree-width summaries, and runtime cost distributions such as median and p90 getLegalMoves, makeMove, and random playout timing.
These commands measure search speed and move quality, not React render performance; use the browser profiler separately if the slowdown feels UI-specific.
docs/ durable project docs and deferred plans
src/
components/ shared UI such as the session view, tree viewer, and controls
games/ per-game rules, boards, tests, and the game registry
hooks/ app/session orchestration and MCTS integration
test/ shared test helpers
utils/ small cross-cutting utilities
src/App.tsx is intentionally small and acts as the app shell. src/components/GameSessionView.tsx owns the common session UI. src/hooks/useGameSession.ts manages history, replay, auto-play, and AI flow. src/games/gameRegistry.ts is the only place where games are wired into the shell.
Prefer the typed game API. A migrated game should live in src/games/<Game>/ and usually contain:
state.tsfor rules and move/state transitionsBoard.tsxfor React UI and local interaction stateindex.tsfor the exported typed game definitionstate.test.tsfor rules coverage
Game boards should work with typed moves locally and only encode to strings at the registry boundary.
Before committing, run:
npm run lint
npm run test
npm run buildRules changes should include state-focused tests. UI or shell changes should include at least one behavioral test when flow changes.
Lightweight reminders live in TODO.md. Durable plans live under docs/plans/. Start with docs/README.md, then see docs/plans/tak.md for an example. Repository-specific working conventions live in AGENTS.md.