Commit Graph

25 Commits

Author SHA1 Message Date
tiennm99 1d80d334e0 refactor(lobby): drop 'New' prefix from Room type and store functions
The 'New' prefix was a phase-06 naming compromise to avoid colliding
with a legacy Room type. That legacy type is gone now, so the prefix
is misleading — in Go 'NewX' conventionally reads as a constructor,
not a type.

- NewRoom type → Room
- JoinNewRoom → JoinRoom
- GetNewRoom → GetRoom
- LeaveNewRoom → LeaveRoom
- WatchNewRoom → WatchRoom
- UnwatchNewRoom → UnwatchRoom
- deleteNewRoom → deleteRoom

Also remove dead code uncovered by the pass:
- Delete lobby/events.go entirely — RoomEvent + BroadcastEvent wrapped
  a no-op placeholder, never called.
- Delete BroadcastToNewRoom no-op from lobby/store.go — kept only for
  the dead BroadcastEvent wrapper.
- Delete TestBroadcastToRoom_SkipsExcludedIDs — theater test that never
  actually called BroadcastToNewRoom, just built a manual exclude map.

go vet + go test ./... green.
2026-04-11 16:31:36 +07:00
tiennm99 4c068849c4 refactor(server): rename database package to lobby, drop ratel legacy files
Rename
- server/database/ → server/lobby/ (17 import sites + qualified references)
- Package was named "database" but there is no database — it's in-memory
  hashmaps for players/rooms/spectators. "lobby" accurately names its role:
  the multiplayer game lobby state (who is in what room, joining/leaving,
  spectating).

Ratel-online legacy cleanup
- Delete server/README.md — 100% Chinese, entirely about ratel card games
  (斗地主/跑得快/德州扑克/麻将/骗子酒馆/Uno). Zero relevance to gomoku.
- Delete server/build.sh + server/build.ps1 — multi-platform ratel-server
  build scripts with mixed Chinese comments, superseded by Makefile +
  Dockerfile.
- Delete server/docs/ — Chinese Docker deployment guide + quickstart,
  superseded by root docs/deployment-guide.md and root README.md.
- Delete server/demo.gif — ratel card-game demo screenshot.

Comment fixes: update "database" references in consts/const.go and
game/board.go package docs to point at "lobby" instead.

go vet + go test ./... green.
2026-04-11 16:08:46 +07:00
tiennm99 d45b1275af refactor: typed proto enums, dead code cleanup, room-join broadcast fix
Protocol type safety
- Add Piece, GameResult, RoomType, RoomStatus proto3 enums; replace
  unsafe string fields in GameMoveSuccessResponse, GameOverResponse,
  RoomCreateSuccessResponse, RoomSummary, WatchGameSuccessResponse.
- Go compiler now rejects typos like "PVP" or "BLACK". protobufjs
  toJSON() serializes enums as UPPERCASE names, so existing client
  comparisons keep working.
- Fixes turn-change bug where lowercase "black"/"white" server strings
  never matched client 'BLACK'/'WHITE' checks, freezing currentTurn
  and blocking the non-starting player's clicks.
- Regenerate Go + JS stubs.

Room-join bug fix
- home.go handleJoinRoom now broadcasts RoomJoinSuccessResponse to all
  players in the room (owner + joiner), not just the joiner. Owner
  can see the player count flip to 2/2 and the Start Game button
  enables. Remove superseded broadcastJoined + GameReadyResponse path.
- client menu-scene _onRoomJoinSuccess: read correct proto camelCase
  field names (roomOwner, roomClientCount, clientNickname).

Dead code removal
- Delete GameReadyRequest/Response proto messages entirely; leaveRoom
  notifies via ClientExitResponse.
- Delete server/network/{network,wss}.go empty stubs.
- Delete server/pkg/consts/ unused re-export package.
- Slim server/consts/const.go from 117 LOC to 24: drop legacy TCP
  constants, duplicated RoomType/RoomStatus enums, Error/NewErr types,
  StateJoin/StateCreate=0 type-unsafe aliases, unused GameTypes maps.
- database/player.go: remove unused IP, Mode, Type, Amount, legacy
  private state field.
- Fix gopls findings: unused forPlayer, gameOverOnce, runAIMove player,
  handleGameReset player params.

go vet + go test ./... green, npm run build green.
2026-04-11 16:03:21 +07:00
tiennm99 b2be88597c feat(docker): multi-stage Dockerfiles and compose for server + nginx client
- server/Dockerfile: golang:1.23-alpine build → distroless/static-debian12:nonroot (3.5 MB)
- client/Dockerfile: node:22-alpine Vite build → nginx:1.27-alpine runtime
- client/nginx.conf: SPA fallback, aggressive asset caching, gzip
- docker-compose.yml: two services — server :1999, client :8080
- server/.dockerignore / client/.dockerignore: trim build contexts
- server/Makefile: add docker-build/run/stop/logs/smoke targets
- client/vite.config.js: raise chunkSizeWarningLimit to 2000 (Phaser bundle)
- remove server/docker-compose.yaml (superseded by root compose file)
2026-04-11 15:28:15 +07:00
tiennm99 4fad10ae41 test(state): unit tests for spectator watching flow, snapshot, and auto-eject
9 test cases in watching_test.go:
- TestWatching_ExitReturnsHome
- TestWatching_ClientExitReturnsErrClientExit
- TestWatching_MoveAttemptRejected
- TestWatching_ClosedCmdChReturnsErrClientExit
- TestSnapshot_SendsOwnerStartingAndHistory
- TestHomeWatchGame_RouteToWatching
- TestHomeWatchGame_RoomNotFound
- TestDeleteRoom_EjectsSpectators
- TestRoomSummary_IncludesSpectators
2026-04-11 15:08:21 +07:00
tiennm99 34b0f8f2ce feat(state): watching state with room snapshot replay and spectator-cannot-act
- Add StateWatching to consts/const.go (iota value 8)
- Register watchingState in state.go runner init()
- Add sendRoomSnapshot helper in game_shared.go: sends WatchGameSuccessResponse,
  GameStartingResponse, and one GameMoveSuccessResponse per MoveHistory entry
  using room.Snapshot() to avoid holding lock during Send calls
- Update home.go: handle WatchGameRequest → WatchNewRoom + sendRoomSnapshot →
  StateWatching; RoomPlayFailNotFoundResponse on missing room
- New watching.go: WatchGameExitRequest → UnwatchNewRoom + ShowOptions → StateHome;
  ClientExitRequest → UnwatchNewRoom → ErrClientExit; GameMoveRequest →
  SpectatorCannotActResponse + stay; closed CmdCh → UnwatchNewRoom → ErrClientExit
- Update store.go LeaveNewRoom: when last player leaves, collect and eject spectators
  (clear Spectators map under lock, then send ClientExitResponse + push synthetic
  WatchGameExitRequest to each spectator CmdCh after releasing lock)
2026-04-11 15:08:15 +07:00
tiennm99 d6c781082a chore(deps): go mod tidy after retiring pkg shims 2026-04-11 14:48:44 +07:00
tiennm99 ca933abeed test(state): unit tests for runner, PVP/PVE game flow, waiting, and gameover
27 tests covering: welcome/setNickname/home transitions, runner exit on
ErrClientExit, waiting owner/joiner role split with StartCh signal,
PVP move validation (turn order, bounds, occupancy, win detection with
GameOverCh cross-goroutine sync), PVE human+AI alternation and AI-first
when human is White, gameover reset/rematch for both PVP and PVE.
2026-04-11 14:28:58 +07:00
tiennm99 530b96d161 refactor: retire legacy database shim, TCP handler, and server/pkg shims
Remove database/legacy.go (legacy hashmap store, Room/Gomoku types).
Remove state/create.go and state/join.go (collapsed into home.go).
Remove state/game/gomoku.go (replaced by game_pvp.go + game_shared.go).
Remove server/pkg/{model,network,protocol,async,json,strings} packages
that are no longer imported after the state machine rewrite.
Stub out network/network.go (legacy TCP handler retired).
Rewrite database/player.go to remove legacy conn/data fields.
2026-04-11 14:28:32 +07:00
tiennm99 43ac04ac79 feat(state): rewrite state machine using cmdCh and typed protobuf requests
Replace legacy AskForString/AskForPacket state machine with channel-based
runner. Each state reads *protocol.Request from player.CmdCh. Adds PVP
waiting (owner/joiner role split with StartCh signal), gamePvp (GameOverCh
for cross-goroutine game-end sync), gamePve (AI alternates with human,
AI-first when human is White), and gameover (reset/rematch support).
2026-04-11 14:28:19 +07:00
tiennm99 5ceb7ef924 test(server): unit tests for dispatch and ws network layer
- codec_test.go: roundtrip encode/decode for Request and Response variants,
  malformed input, empty frame
- handlers_stateless_test.go: nickname validation table (9 cases),
  heartbeat no-op, get_rooms response, set_client_info version store,
  dispatch routing (stateless inline vs stateful CmdCh push),
  CmdCh overflow drop without panic
2026-04-11 13:56:29 +07:00
tiennm99 9e14f3a9b3 feat(server): new ws network layer and protobuf dispatch on :1999/gomoku
- Add server/network/{server,codec,reader,writer,dispatch,handlers_stateless}.go
- Single /gomoku WS endpoint; binary protobuf frames only (no JSON/base64)
- Per-connection reader + writer goroutines; write mutex serialises WS writes
- Dispatch type-switch: stateless (heartbeat, set_nickname, get_rooms,
  set_client_info, client_exit) inline; stateful requests → player.CmdCh
- Add Player.SendCh, CmdCh, LastHeartbeat, ClientVersion, Send() to database.Player
- Rewire main.go: NewServer(":1999").Serve() + database.StartCleanup()
- Empty wss.go (old shim superseded by server.go)
2026-04-11 13:56:22 +07:00
tiennm99 39bbcd98bc test(database): unit tests for store and room operations
19 tests covering: unique ID assignment, PVP/PVE room creation, color
randomization, invalid difficulty rejection, join/leave/watch/unwatch,
empty-room cleanup, snapshot independence, ApplyMove turn advancement,
move history recording, win detection, Reset clearing, and IsOwner.
2026-04-11 13:31:04 +07:00
tiennm99 acf08669dd feat(database): new domain model for PVP/PVE/spectator with thread-safe store
- Split monolithic database.go/model.go/gomoku.go into focused files:
  player.go, room.go, store.go, errors.go, events.go, cleanup.go
- NewRoom embeds game.Board directly; carries blackPlayerId, whitePlayerId,
  currentTurn, moveHistory, spectators, owner, type, difficulty from caro domain
- Store singleton with sync.RWMutex: RegisterPlayer, CreatePvpRoom, CreatePveRoom,
  JoinNewRoom, LeaveNewRoom, WatchNewRoom, UnwatchNewRoom, BroadcastToNewRoom
- PVE rooms randomly assign human to Black or White; AI takes opposite side
- legacy.go shim keeps server/state/*.go and state/game/gomoku.go compiling
  without modification until phase-06 rewrites them
- consts/const.go: add RoomTypePvp/Pve, Status*, RoomStatus*, Difficulty* enums
2026-04-11 13:30:58 +07:00
tiennm99 43b349e09e chore: remove .gitkeep placeholders now that phase-02 and phase-03 populated the directories 2026-04-11 12:42:58 +07:00
tiennm99 c40120d6db feat(server): add protoc-gen-go toolchain and generated proto code
Adds tools.go to pin protoc-gen-go, updates go.mod/go.sum with
google.golang.org/protobuf, generates request.pb.go and response.pb.go,
and adds a make proto target to server/Makefile for regen.
2026-04-11 12:40:53 +07:00
tiennm99 a8b7ab37e4 feat: add gomoku AI with easy/medium/hard difficulty and tests
Port GomokuAI.java to Go with three difficulty levels:
- Easy: uniform random (seeded RNG for determinism)
- Medium: immediate win/block heuristic from caro
- Hard: true minimax depth-3 with alpha-beta pruning

evaluatePosition uses caro threat-pattern weights (open-four=100000,
closed-four=10000, open-three=1000, etc.) as leaf evaluator.
candidateMoves limits branching to radius-2 Chebyshev neighbours.
Benchmark: ~71µs/move on 30-stone mid-game board (budget: <1s).
2026-04-11 12:30:59 +07:00
tiennm99 b20262b85a feat: add gomoku board and helper logic with tests
Port Board.java and GomokuHelper.java to idiomatic Go under server/game/.
Board is a value type ([15][15]Piece) enabling zero-allocation Clone().
Helper provides ValidMoves, FormatBoard, WinnerMessage as pure functions.
Covers all 4 win directions, draw, OOB, occupied-cell, and reset cases.
2026-04-11 12:30:50 +07:00
tiennm99 1ce619ba4c chore: add skeleton directories for future phases
common/proto/, server/game/, server/protocol/, client/src/{config,scenes,
services,objects,ui,generated} — all .gitkeep placeholders.
2026-04-11 12:07:25 +07:00
tiennm99 b089e64955 refactor: delete api/, core/, old client/, web/, server/bot/, server/network/tcp.go
Removed legacy Java API, Go shared core lib, Go CLI client, vanilla-JS web
client, QQ bot integration, and TCP listener. Server is now WS-only.
2026-04-11 12:07:18 +07:00
tiennm99 1b9eec5f7d refactor: rename Go module and copy core pkgs into server/pkg
- Module: github.com/ratel-online/server → github.com/tiennm99/gomoku/server
- Copied core/{log,util/async,util/json,util/strings,model,network,protocol,consts}
  into server/pkg/* (temporary shims until phase-05 replaces protocol/network)
- Rewrote all ratel-online import paths across server/**/*.go
- Trimmed main.go: single -p flag, WS-only on :1999, no TCP/bot/static
- Trimmed network/wss.go: endpoint /gomoku, no static file serving
- Updated Makefile: removed TCP/bot references, port 1999
2026-04-11 12:04:03 +07:00
tiennm99 5ccd4e7ce2 feat: add documentation, code comments, and update Docker config
Rewrite README with usage guide, deployment instructions, and protocol
docs. Update CLAUDE.md to reflect gomoku-only architecture. Add English
doc comments to all key server Go files, replacing Chinese comments.

Create docs/system-architecture.md (state machine, protocol, database
schema) and docs/deployment-guide.md (local dev, Docker, production
nginx, resource requirements).

Update Dockerfile to Go 1.22 with repo-root build context to include
web client. Update docker-compose to match.
2026-04-09 23:35:46 +07:00
tiennm99 cdcc3e0623 refactor: remove legacy card game code, keep only gomoku
Remove 3,612 lines of card game implementations (Dou Dizhu, Texas
Hold'em, Mahjong, Uno, Liar's Bar, Run Fast), their database models,
rule engine, skill system, and render package.

Simplify Room struct by removing card-game-specific fields, clean up
consts to only gomoku game type, and remove unused dependencies
(mahjong, uno, cast, color).
2026-04-09 23:23:58 +07:00
tiennm99 2635151ce2 feat: add gomoku game type and web client with canvas board engine
Add server-side gomoku (five-in-a-row) as game type 9 with 15x15 board,
2-player rooms, move validation, win detection in 4 directions, and
draw detection. Includes channel-based turn sync with mutex-protected
board access.

Add vanilla JS web client served as static files from the Go server:
WebSocket connection with base64 packet encoding, state machine
navigation, Canvas-based board renderer with gradient stones, hover
ghost, last-move highlight, and game-over overlay.
2026-04-09 22:25:24 +07:00
tiennm99 6e3670aec8 feat: add ratel-online server, core, client, and api sources
Import source files from ratel-online organization repos into monorepo
structure for gomoku game development. Update README with project
structure and credits for original authors.
2026-04-09 17:09:41 +07:00