MID-AUTUMN-Festival version topology-gomoku https://moon-gomoku.qqs.tw
  • TypeScript 81.9%
  • CSS 13.6%
  • Python 3.9%
  • Dockerfile 0.3%
  • HTML 0.2%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-13 10:15:06 +08:00
design feat: add Mid-Autumn music playlist with Git LFS 2026-09-10 00:29:23 +08:00
docs test(ai): record festival strength and upstream move parity 2026-09-13 09:31:07 +08:00
e2e feat(ai): bring Mid-Autumn edition to upstream search and worker parity 2026-09-13 09:27:42 +08:00
public Add screenshot 2026-09-13 10:15:06 +08:00
scripts test(ai): record festival strength and upstream move parity 2026-09-13 09:31:07 +08:00
server feat(ai): bring Mid-Autumn edition to upstream search and worker parity 2026-09-13 09:27:42 +08:00
shared feat(ai): bring Mid-Autumn edition to upstream search and worker parity 2026-09-13 09:27:42 +08:00
src feat(ai): bring Mid-Autumn edition to upstream search and worker parity 2026-09-13 09:27:42 +08:00
.dockerignore feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
.env.example feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
.gitattributes feat: add Mid-Autumn music playlist with Git LFS 2026-09-10 00:29:23 +08:00
.gitignore feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
compose.yaml feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
Dockerfile feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
index.html feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
package-lock.json feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
package.json test(ai): record festival strength and upstream move parity 2026-09-13 09:31:07 +08:00
playwright.config.ts feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
README.md Add screenshot 2026-09-13 10:15:06 +08:00
tsconfig.json Initial commit: topology-gomoku-mid-autumn-festival 2026-09-09 18:03:32 +08:00
tsconfig.server.json feat(ai): bring Mid-Autumn edition to upstream search and worker parity 2026-09-13 09:27:42 +08:00
vite.config.ts feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00
vitest.config.ts feat: add localized online multiplayer to Mid-Autumn edition 2026-09-10 23:59:23 +08:00

Moonlit Gomoku · 月满弈境 · 月滿弈境

The Mid-Autumn edition of Topology Gomoku, with moonlit gardens, jade boards, carved mooncake and rabbit stones, and synchronized 2D and interactive 3D views. Play locally, against the computer, through a private invitation, or in the public online lobby. The interface supports English, Simplified Chinese and Traditional Chinese.

Moonlit Gomoku

Run locally

Use Node.js 24 or newer, npm, and Git LFS:

git lfs pull
npm ci
npm run build
npm start

Open http://127.0.0.1:2568. The root redirects to the preferred locale. Local sessions use non-Secure cookies; production requires HTTPS and sets Secure cookies. By default the server expects the exact origin http://127.0.0.1:2568. Set PUBLIC_ORIGIN when using another hostname or port.

For development with Vite hot reload, use two terminals after the initial build:

PUBLIC_ORIGIN=http://localhost:5175 npm run dev:server
npm run dev

Open http://localhost:5175. Vite proxies API, lobby and room connections to port 2568. SQLite is stored under data/, which is ignored by Git.

Languages and HTML source

The stable locale URLs are /en/, /zh-Hans/, and /zh-Hant/. Lobby URLs add lobby; invitations add room/<match-id>. Switching the language preserves the current match, board view and music. The server supplies the correct <html lang>, page title, description and Open Graph metadata in the original HTML response, including for lobby and invitation URLs. This also works in View Source and with JavaScript disabled. Vite builds a localized HTML entry for each language.

An explicit locale URL takes precedence. At /, a saved locale cookie wins over Accept-Language. Chinese browser locales honor explicit Hans/Hant script tags before their region; TW/HK/MO default to Traditional, CN/SG to Simplified. Other languages fall back to English. Translations include rule descriptions, topology names, notifications, music titles and accessible board labels.

Online play

  1. Open the online lobby and choose a display name, surface and board size.
  2. Create a public table, or a private table and copy its invitation link.
  3. The second player joins; the server assigns Black and White and starts play.
  4. Undo requires the other player's agreement. Both players must request a rematch; colors swap in the next round. Resignation ends the round immediately.

Only public tables are listed in the live lobby. Private match IDs contain 128 bits of randomness and act as invitation capabilities: anyone with the link can claim an available seat. Once seated, each player must present their original HttpOnly guest-session cookie. Display names never authorize a seat. A guest may have one unfinished match at a time. “Your recent games” allows returning to saved matches, including private ones.

The server validates membership, session expiry, turn order, board bounds, occupancy, match phase and command revision. Accepted commands have durable IDs, so retries cannot place a second stone. Cross-origin mutation and socket requests are rejected; invitations work because both browsers connect to the game's own origin. Raw Colyseus create/join endpoints cannot bypass the application's guards.

Moves pause for up to 90 seconds after a player disconnects. AI then takes over that seat using the shared topology rules. The returning player immediately resumes control from the current position; stale AI calculations are discarded. Undo and rematches still require both human players to be connected.

When both players are absent, play pauses and AI stops. Paused games remain recoverable for 30 days, matching guest-session retention, then close as abandoned draws. An empty waiting table closes after two minutes away (or 30 minutes total). “Close table” confirms closure with the server before returning to the lobby.

Browser reloads and outage recovery reclaim seats with the HttpOnly guest cookie, without reusing stale Colyseus reconnection tokens. Retries use capped backoff and durable command IDs. Clearing cookies loses access to the previous guest identity.

Database cleanup runs at startup and every hour. Expired sessions and finished or closed games older than 30 days are deleted together with their command receipts, events and player associations. A paused game becomes an abandoned draw after 30 days without players, then remains in history for another 30 days.

The public lobby has 8 games per page and recent games 5 per page, with independent navigation and live updates. Filtering runs on the server before pagination, so every matching game remains reachable. History is scoped to the current guest. The API accepts page, pageSize (up to 50), and topology.

Rules

Black moves first. Connect five or more distinct intersections horizontally, vertically, or diagonally to win. Overlines count; there are no forbidden moves.

Surface Left / right edges Top / bottom edges
Plane Stop Stop
Cylinder Same-direction connection Stop
Torus Same-direction connection Same-direction connection
Möbius strip Reversed connection Stop
Klein bottle Reversed connection Same-direction connection
Projective plane Reversed connection Reversed connection
Sphere Top connects to left Right connects to bottom

Crossing a seam transforms both position and direction. Loops count each intersection once. On the sphere and projective plane, a diagonal that crosses two edges at exactly the same corner stops there. Visual self-intersections of the Klein bottle and Roman surface do not introduce additional connections.

Local games retain the existing topology-gomoku:mid-autumn:v1: storage keys, separately by topology, board size and mode. Upgrading preserves existing saves. Against the computer you play Black; undo retracts a full round. Demonstrations remain separate from the current game. Online games share the exact same pure rules.

Structure

shared/          Pure topology/rules engine, protocol types and locale metadata
server/          Colyseus rooms, HTTP/SSE routes, SQLite persistence and validation
src/i18n/        Three translation catalogs and language switching
src/online/      Lobby, online controls and recoverable client connections
src/game/        Local game controller, AI, audio; shared rules re-exports
src/components/  Shared 2D/3D game UI
src/scene/       Three.js scene, picking, camera and resource lifecycle
scripts/         Build, Docker image script and Blender asset creation
public/          Models, coordinates, textures and eight original music tracks

AI uses the same topology-aware multi-step search as the upgraded original edition, including forcing tactics, cached paths and incremental evaluation. Local play runs in a reusable browser worker; undo, restart and switching games cancel obsolete work. Servers use up to two workers, with a 16-job admission cap, per-dispatch watchdogs and cancellation when a player returns. Results still require matching round, revision and seat control before they can be saved. See AI design and verification for budgets and acceptance tests.

Room updates use one small, atomic Colyseus snapshot per change so the board, turn and outcome cannot be rendered from different revisions. Rendering and music remain client-local. The shared engine imports neither React nor browser APIs. Three.js and the online client are loaded on demand.

Verify

npm run typecheck
npm test
npm run verify:ai
npm run build
npx playwright install chromium
npm run test:e2e

Tests cover all seven topology rules and all three board sizes, AI behavior, localization coverage and HTML source, concurrent seat claims and moves, idempotent retries, invalid/session-expired requests, rate limits, undo/rematch consent, disconnection/reconnection, atomic persistence rollback, actual server restart recovery, and real two-browser workflows. Browser tests also exercise mixed languages, refresh recovery, public/private visibility and mobile layout. Coverage also includes AI takeover/return races, paused games, topology-specific AI wins, migration of existing databases, pagination past the old list limits, and repeated reconnections without accumulating reserved seats. Screenshots and traces are written under /tmp, outside the repository.

Deploy

./scripts/build-image.sh

Builds Linux amd64 and loads git.qqs.tw/bobmaster/moon-gomoku:latest. Add --push to publish after registry login. compose.yaml includes no Nginx service; it uses the host's Nginx and a persistent database volume. See deployment instructions for the origin setting, Nginx proxy, updates, rate limits, retention and backups. Compose binds 127.0.0.1:2568 to container port 2567 and uses its own moon-gomoku-data volume. The original edition can continue on port 2567. The moon_gomoku_session and moon_gomoku_locale cookies are independent of the original edition’s cookies; deploy each edition on its own hostname.

Festival design and music

The existing festival artwork, models, lighting, stone textures, favicon and music are preserved. Every surface retains its festival name in all three languages: Moon terrace (月台 / 月臺), Osmanthus walk (桂廊), Reunion (团圆 / 團圓), Turning moon (旋月), Osmanthus wine (桂酿 / 桂釀), Moon reflection (映月), and Wangshu (望舒). The carved black mooncake and white jade-rabbit stones use identical rules.

The eight original M4A tracks remain unchanged: Moonlit Reunion, Moonlight Through Osmanthus, Jade Rabbit’s Moonwalk, and Seven Worlds, One Moon, each with V1 and V2. The playlist shuffles without repeating a track at the boundary between rounds. Initial volume is 30%; blocked autoplay resumes after an interaction. Manual pause persists across moves, language changes and navigation. Stone sounds have a separate mute button.

All media use Git LFS. Run git lfs pull before building; the build rejects unresolved LFS pointers. public/art/ contains optimized festival artwork and stone renders, public/models/ contains the seven GLB surfaces and carved stones, and public/audio/ contains the eight tracks. Source art and the native Blender project are in design/; the image prompts, visual specification and fidelity ledger are retained there.

To regenerate models and stone images with Blender:

npm run assets

The asset script uses /Applications/Blender.app/Contents/MacOS/Blender; change that command on other systems. The WebGL view loads on demand and offers a 2D fallback. Three.js is a separate bundle; its existing size advisory does not prevent the build.

The supplied Topology Gomoku video was used as a rules reference. It was not copied into this edition, and the original repository is maintained independently.