Skip to content

About

Games to train AI

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

363 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GamesForAI

A game library that serves as a training and evaluation environment for AI systems. It has Rust game engines behind one standardized API (REST, WebSocket and MCP), built-in opponents such as Stockfish, persistent match history, and a React + Phaser frontend for playing games, watching live matches and viewing replays.

See the Product Requirements Document.

Run locally

With Rust, Node.js 22 and pnpm 10.6.5 installed, run:

make serve

This installs the locked browser dependencies, builds the app, and serves both it and the API at http://127.0.0.1:8080/. The interactive API reference is at /docs/. Stop and rerun the command after changing the browser source. Use PORT=9090 or DB_PATH=./development.sqlite to override the local defaults.

For browser development with hot reload, run make serve-api in one terminal and make dev in another; open the URL printed by Vite (normally port 5173). For API-only use without Node.js:

cargo run -p gfa-cli --locked -- serve --sqlite ./gfa.sqlite --port 8080

API-only mode redirects / to /docs/. To serve a previously built frontend, add --web-dir web/apps/site/dist. Local mode binds to loopback and treats the local caller as the match owner. See make help and the contributor guide for other workflows.

For PostgreSQL, enable the backend and put the connection URL in an environment variable so credentials do not appear in the command arguments:

# Set GFA_DATABASE_URL through your shell or secret manager first.
cargo run -p gfa-cli --features postgres --locked -- serve --postgres-env GFA_DATABASE_URL

Use a dedicated database; startup applies embedded migrations. For remote PostgreSQL, require server certificate verification with sslmode=verify-full. SQLite is the default. The storage flags are mutually exclusive. Both backends persist moves and idempotency receipts atomically and recover replays after a graceful shutdown and restart.

Opponents and analysis

GET /v1/games/{game_id}/opponents lists installed players. Random is available for every game. Deterministic, sequential games with perfect information also have MCTS; two-player games have alpha-beta minimax. Search levels are resource budgets until calibration results are published; the API reports null ratings.

POST /v1/analysis accepts game_id, from (a match/seat/optional turn, or a standalone position/state), opponent (id, optional level and limits), and an independent seed. It returns legal recommendations, evaluation, principal variation, node count, depth and whether the budget was exhausted. Match analysis requires assists.allow_analysis: true. A standalone copy of an active position cannot bypass that policy. Searches run in four bounded workers and receive only the authorized observation and legal actions.

Sudoku also advertises the reference opponent. Analysis returns its next placement and supporting candidate eliminations. Search-backed steps are marked advice.is_guess: true; an incorrect entered digit produces an explicit solution_check erasure recommendation. Ordinary state responses do not include these recommendations or the solution grid.

Play against a built-in opponent

Create an interactive match with one assignment per player:

{"game_id":"tictactoe","seats":[{"type":"self"},{"type":"opponent","opponent":{"id":"minimax","level":3},"seed":19}]}

An omitted list keeps both seats external. A bot in the starting seat plays before creation returns; use ?seat=1 when joining the second seat. An action request returns opponent_actions and the final observation after those replies. The caller's move, automatic replies, and idempotency receipt commit together, so worker failure or a conflicting write leaves the attempted batch unapplied.

Planning seeds are materialized independently from game randomness. Replay reapplies recorded actions without rerunning opponents. Forks may replace seats; omitted assignments retain the parent's configuration. All-opponent matches return their initial state immediately and run in the background. The server scans persisted matches at startup and between batches, so a restart resumes pending turns. Live streams receive each committed update. Four concurrent scheduler tasks and four search workers bound resource use. Interactive reply chains longer than eight moves continue through this runner.

GET /v1/matches/{id}/events?since=&limit=&seat= pages through consecutive event sequences from one recorded revision. Omit since for the beginning; use next for the following page. Limits are 1–100. The service projects each event to the authorized player or spectator: private actions, reasoning, chance events, match seeds, and internal fork permissions are omitted when unauthorized. Own reasoning is available immediately; other reasoning in perfect-information games becomes available after completion.

Full replay bundles include the game/version, normalized config, event revision, projected events (including reasoning and controls), and reconstructed per-turn observations. Authorized in-process omniscient exports also include the initial engine state and RNG seed, so custom starts and forked histories can be rebuilt exactly. The ordinary REST views omit those private inputs. Full responses have a 16 MiB budget; larger histories remain available through paginated events.

Game briefings provide compact rules and full schemas/examples. Full previews mark large numeric arrays in omitted_fields; fetch the normal state/legal-action routes for complete tensors and masks. This keeps model prompts readable without changing the live state contract.

Chess

Chess is enabled by default and uses the same create, move, simulate, fork, analysis and replay routes. Submit UCI moves such as e2e4, e1g1 or a7a8n, or the structured/index representation from legal_actions. White is seat 0. GET /v1/games/chess/info explains draw claims and every encoding.

Use start: {"position":"<six-field FEN>"} for a custom board. A bare FEN begins new repetition history; complete played-state JSON keeps the original position and actions. Replay and forks retain that history. The engine accepts standard chess only. Generic random/search opponents are available; Stockfish integration is tracked separately.

To enable a local Stockfish installation on Linux:

cargo run -p gfa-cli -- serve --stockfish /usr/games/stockfish

Install Stockfish, bubblewrap and util-linux, and allow bubblewrap to create user namespaces under the host's security policy. Startup verifies a sandboxed search before opening the database. The application never disables host sandbox policy. Hosts may configure the pool, CPU/address-space limits, threads and hash size through StockfishConfig. Engine paths and resource policy cannot be supplied by match participants.

Chess then advertises stockfish in its opponent catalog. Select it for an opponent seat or POST /v1/analysis with, for example, {"id":"stockfish","level":3}, or {"id":"stockfish","uci":{"elo":1500,"multipv":3}} as the opponent. Explicit level, skill and Elo strength choices are mutually exclusive. Installed engine capability bounds are authoritative. Skill presets use levels 1–10 but remain uncalibrated, with null ratings, until a measured calibration is published. Stockfish's weaker settings may randomize play; a planning seed does not promise deterministic engine strength-limited decisions. Idempotent action retries reuse the persisted result. Analysis exposes typed centipawn/mate scores and bounded, rules-validated variations in advice.details.

About

Games to train AI

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages