diff --git a/AGENTS.md b/AGENTS.md index 4ac959d..033a853 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,8 @@ Online Mancala (the Turkish *Mangala* rules) with a web app, an Android/iOS app Specs that exist: `keycloak-auth` (login, guests, tokens), `game-history` (saved games, live games, replay), `game-clock` (5 minutes per player, ending games on time), `web-redesign` (the web app's look: themes, board, -pages) and `quarkus-backend` (the backend's move from Node to Java and Quarkus). +pages), `quarkus-backend` (the backend's move from Node to Java and Quarkus) and `game-bot` (playing against a bot +at four levels). ## Running locally @@ -44,13 +45,15 @@ unless `useLocalServer` is set in `apps/mobile/src/const/config.ts`. |---|---|---| | Engine | `cd packages/mancala.js && npx jest` | After changing the rules, change the Java port too and record the parity games again (`apps/backend/README.md`) | | Core | `cd packages/core && npx jest` | | -| Backend | `cd apps/backend && ./mvnw test` | Needs a JDK 25 and Docker: Postgres and Valkey run with Quarkus Dev Services | +| Backend | `cd apps/backend && ./mvnw test` | Needs a JDK 25 and Docker: Postgres and Valkey run with Quarkus Dev Services. The bot's calibration tournament is tagged `calibration` and skipped; see `apps/backend/README.md` | | Keycloak extension | `cd apps/keycloak/extension && mvn test` | Needs Docker; starts Keycloak with the real realm file | | Web app | `cd apps/frontend && yarn build` | There is no `tsconfig.json`, so nothing type-checks it; use a temporary one when needed (with `"types": ["styled-jsx", "react", "react-dom"]`). 1 type error (`react-dom/client`) is known | | Mobile | `cd apps/mobile && npx tsc --noEmit -p .` and `npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output /tmp/x.bundle` | 11 type errors are known and older than recent work | There is no automated end-to-end suite. Changes to the game flow were checked by driving Chrome with -`playwright-core` (installed outside the repo, `executablePath: /usr/bin/google-chrome`) against the local stack. +`playwright-core` (installed outside the repo, e.g. `npm install playwright-core@1.48.2` in a scratch folder; +`executablePath: /usr/bin/google-chrome`) against the local stack. A live game is `GET /game/:id` on the backend, +which helps to check what the server holds. ## How we work @@ -92,6 +95,10 @@ There is no automated end-to-end suite. Changes to the game flow were checked by left with `GameClocks.getClockTimes`, never store a ticking value. `GAME_CLOCK_MS=40000` makes games short for manual tests. - `Rtmt.listenOnClientConnectionChange` adds a listener (several are allowed). +- The bot plays as `bot:` (`BotLevel.isBotId`) in many games at once: `GameStore` does not map it to a game, + nothing is sent to it, it is always online and `PublicIds` keeps its id. The bot's search must never run on the + game loop; `BotPlayer` runs it on its own pool and plays the move back on the loop. +- `-Dgroups=...` runs only the tests with that tag; run the untagged tests separately too. - Unit tests build the logic with fakes (`FakeRtmt`, in-memory stores, `ManualScheduler` instead of timers and direct executors); only storage, HTTP and WebSocket tests are `@QuarkusTest`s. `FakeTokenVerifier` replaces Keycloak in all `@QuarkusTest`s. diff --git a/TODO.md b/TODO.md index 7b73634..7ab5374 100644 --- a/TODO.md +++ b/TODO.md @@ -54,6 +54,17 @@ See `docs/specs/game-clock`. - [ ] Clocks in the home page's live game previews and in the ongoing-game banner - [ ] Try the mobile clocks on a device; only the type check and the bundle were run +## Game bot + +See `docs/specs/game-bot`. + +- [ ] Play against the bot without a connection (a bot in the TypeScript engine on the device) +- [ ] Keep bot games apart once there are statistics or ratings +- [ ] Hints or move analysis for players, with the same search +- [ ] Rebuild `MancalaGame` on `Position`, or use `Position` to check moves before running them (see Security) +- [ ] Tune the levels from real games (`games.bot` holds each game's level, strength and seed) +- [ ] Try the bot on a mobile device; only the type check and the bundle were run + ## Web redesign See `docs/specs/web-redesign`. diff --git a/apps/backend/README.md b/apps/backend/README.md index fb5c3ef..ac0a548 100644 --- a/apps/backend/README.md +++ b/apps/backend/README.md @@ -21,7 +21,8 @@ The Docker image is built from the repo root: `docker build -f apps/backend/Dock | Package | What | |---|---| -| `engine` | The game rules, a port of `packages/mancala.js` | +| `engine` | The game rules, a port of `packages/mancala.js`; `Position`, a compact board for searching moves | +| `bot` | The bot: levels, strength, the search and `BotPlayer`, which plays its turns in live games | | `model` | The JSON sent to clients and stored, and the shared `ObjectMapper` | | `loop` | `GameLoop`, the single thread that owns all live game state | | `auth` | Keycloak token verification | @@ -93,6 +94,24 @@ backend is down is not charged. The design is in `docs/specs/game-clock`. |---|---|---| | `GAME_CLOCK_MS` | `300000` | Time each player has for a game; a short value such as `40000` helps when testing by hand | +## Bot + +Players can play against a bot at four levels (`new_bot_game` with `{ level }`); the lobby offers it after 10 seconds +without an opponent. Each level is a range of strengths, and the bot draws one per game, so games at the same level +differ. It plays as `bot:` through the same game logic as players, with the clock, saving and spectators, and +waits for the previous move's animation and a thinking time before moving. Its moves are worked out with alpha-beta +search on `Position` on a thread pool of their own, never on the game loop. The design is in `docs/specs/game-bot`. + +| Variable | Default | Purpose | +|---|---|---| +| `BOT_SEARCH_THREADS` | half the processors | Threads working out the bot's moves | + +After changing the search or the strength table, check that every level still beats the one below: + +```sh +./mvnw test -Dtest=BotTournamentTest -Dgroups=calibration -DexcludedGroups=none +``` + | Route | Auth | Response | |---|---|---| | `GET /game/:id` | – | A live game, or `{ status: "finished", record }` | diff --git a/docs/specs/game-bot/design.md b/docs/specs/game-bot/design.md index 7d25bae..82f9c69 100644 --- a/docs/specs/game-bot/design.md +++ b/docs/specs/game-bot/design.md @@ -231,3 +231,9 @@ Games being worked on are kept in a set by identity, so a game restored with the "Play with bot" on the home page; the bot moves after the animation; the game ends and shows in recent games and the replay as "Bot · "; "Play again" starts a new bot game; a backend restart during the bot's turn; a second browser watches a bot game from the live previews. + +Checked end to end in Chrome on 2026-10-16 with the default clock: the home menu and the lobby offer (shown after +10.3 s) start games at the chosen level; "Bot · Easy" / "Bot · Hard" on the game page, in recent games and in a +second browser's live previews; an Easy game played to the end (the bot waited 1.45–4 s per move, longer after long +animations); "Play again" starts a new game at the same level; the backend stopped right after a Master game started +and the bot made its first move after the restart. diff --git a/docs/specs/game-bot/requirements.md b/docs/specs/game-bot/requirements.md index f3dfb95..20d2cf3 100644 --- a/docs/specs/game-bot/requirements.md +++ b/docs/specs/game-bot/requirements.md @@ -1,6 +1,6 @@ # Game bot: requirements -Status: spec, not implemented yet. Branch `feature/game-bot` (based on `develop`). +Status: implemented on branch `feature/game-bot` (based on `develop`). Scope: backend, `packages/core`, web app and mobile app. ## Goals diff --git a/docs/specs/game-bot/tasks.md b/docs/specs/game-bot/tasks.md index 3459e5f..5ef03f9 100644 --- a/docs/specs/game-bot/tasks.md +++ b/docs/specs/game-bot/tasks.md @@ -17,5 +17,5 @@ Work through the tasks in order; each ends with its tests passing and a commit. - [x] 7. **Web app**: `BotLevelPicker`, the home page button, the lobby offer and `?bot=`, "Play again" after a bot game, bot names everywhere players are shown. - [x] 8. **Mobile app**: lobby offer and `botLevel`, home screen button, bot names; type check and bundle. -- [ ] 9. **End to end and docs**: the Chrome tests from `design.md`; `README.md`, `apps/backend/README.md`, +- [x] 9. **End to end and docs**: the Chrome tests from `design.md`; `README.md`, `apps/backend/README.md`, `AGENTS.md` (the specs list, bot ids, the calibration test) and `TODO.md` (the out of scope items).