尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A complete implementation of the Catan board game in TypeScript, with a procedurally drawn 3D board, bots at three difficulty levels and local-network multiplayer with an authoritative server.
No install needed: play against bots or hot-seat on the same device. Local-network multiplayer needs the server from this repo (npm run lan).
| Layer | Technology |
|---|---|
| Language | TypeScript 5 (strict), ES2022 |
| Build & dev server | Vite 5 |
| Rendering | Canvas 2D with a custom 3D projection, SVG |
| Audio | Web Audio API (oscillators and filtered noise) |
| Networking | WebSocket (ws) on the same HTTP port that serves the game |
| Testing | Vitest, jsdom, node-canvas, fuzzing with tsx |
| Deployment | GitHub Actions → GitHub Pages (tests gate every deploy) |
src/engine/ never touches the DOM, never calls Math.random and never reads the clock. Its interface is a reducer:
const state = createGame(players, { seed }); // deterministic match
const moves = getLegalActions(state, playerId); // everything they can do
const result = applyAction(state, moves[0]); // (state, action) -> state
Randomness lives inside the state (a seeded mulberry32 generator), so a whole match can be rebuilt from the seed plus the action list. That shape made bots and networking almost free: a bot is just a function that picks among legal actions, and the server re-validates every move with the same validate() the client uses — no duplicated logic. → src/engine/
Clients only propose moves. Before sending state to each player, the server strips what that player isn't allowed to see: other players' hands, other players' development cards, the deck order, and the RNG state, which would let anyone compute every future dice roll. Redacted fields are left empty rather than faked, and public counts travel separately. A test guards against any new secret field leaking. → src/net/redact.ts, server/room.ts
Instead of computing corners as floats and deciding with an epsilon whether two of them match, the board uses a doubled integer grid (X = 2q + r, Y = 3r): neighboring hexes produce literally the same pair for a shared corner, so vertex identity is plain integer equality. Harbors aren't hand-placed: the code walks the island's perimeter along single-hex edges and spaces them evenly, and the same code serves both board sizes. → src/engine/hex.ts, src/engine/board.ts
243 tests across 12 files. The most valuable ones aren't unit tests:
Requires Node.js 18+.
npm install
npm run dev # local match at http://localhost:5173
npm run lan # build and start the server for local-network play
npm test # 243 tests
npm run fuzz 500 # 500 bot matches checking invariants
npm run build # production build in dist/
Network scope: designed for a trusted network. Traffic is unencrypted and the only access control is the room code; don't expose it to the internet as-is.
src/
engine/ rules engine: pure TypeScript, no DOM, no external randomness
ai/ bot contract, random and heuristic bots, self-play loop
net/ protocol, state redaction and WebSocket client with reconnection
ui/ 3D scene, procedural art, sound and match controller
server/ HTTP + WebSocket on one port; rooms and the authoritative match
tools/ headless board-to-PNG rendering, fuzzer and bot tournaments
tests/ rules, board, bots, UI and networking
The full design document, covering every rules and UI decision, is in docs/DISENO.md.
Non-commercial personal project. Not affiliated with or endorsed by Catan GmbH; "Catan" is a trademark of its respective owners.