tiennm99 d5ad56023c chore: remove stale subagent reports
Both reports belonged to shipped work:
- docs-manager-260410-1344: docs sweep, superseded by docs/ updates in cbad690
- researcher-260410-2132: pre-2026 version audit, superseded by the pinned
  deps in server/build.gradle.kts and client/package.json
2026-04-11 10:01:29 +07:00
2018-10-16 20:00:52 +08:00

Caro (Gomoku)

A multiplayer Gomoku (Five-in-a-Row) game with client-server architecture. Play in the browser against other players or an AI.

Built on Netty (server) and Phaser 3 (client).

Features

  • 15x15 board with standard Gomoku rules
  • Player vs Player (PVP) — create or join rooms, play against others online
  • Player vs AI (PVE) — three difficulty levels (Easy, Medium, Hard)
  • Spectator mode — watch ongoing games in real-time
  • Phaser web client — professional 2D game UI with canvas board, stone animations, sound effects
  • Typed protobuf over WebSocket — single binary wire protocol on port 1999

Prerequisites

  • Java 25 — for building the server (Gradle wrapper is included; no separate Gradle install needed)
  • Node.js 22+ — for the client (development only)
  • Docker + Docker Compose — optional, for containerized deployment

Quick Start (Docker Compose)

git clone https://github.com/tiennm99/caro.git
cd caro
docker compose up -d

Then open http://localhost:8080/ in your browser. The server listens on port 1999 (WebSocket); the client is served at 8080.

Quick Start (Local)

1. Build and run the server

./server/gradlew -p server clean build
java -jar server/build/libs/caro-server-0.0.1.jar -p 1999

On Windows use server\gradlew.bat instead of ./server/gradlew.

The server starts one listener:

  • WebSocket on port 1999 (typed protobuf binary frames at /ratel)

2. Run the client (Vite dev server)

npm --prefix client install
npm --prefix client run dev

Open http://localhost:5173 in your browser. Features:

  • Wood-textured board with gradient stones
  • Stone placement animations and hover preview
  • Move history panel and turn indicator
  • Sound effects (Web Audio API)
  • Lobby with room management

To play multiplayer, open two browser tabs.

Game Rules

  • Two players take turns placing black and white pieces on a 15x15 board
  • Black moves first
  • The first player to form an unbroken line of 5 pieces (horizontally, vertically, or diagonally) wins
  • The game ends in a draw if all 225 positions are filled

Project Structure

caro/
  server/     Standalone Netty server (Java 25, Gradle, com.miti99.caro.{common,server})
  client/     Phaser 3 web client (Vite + vanilla JS)
  docs/       Project documentation

Server Architecture

Client (browser)
  |
  +-- WS :1999 /ratel  -->  WebsocketTransferHandler
                              |
                              v
                            RequestConverter  (wire Request -> sealed ClientRequest record)
                              |
                              v
                            RequestDispatcher (pattern-match switch on record)
                              |
                              v
                            <Verb>Handler     (typed business logic, emits typed Response)

Protobuf schemas live at server/src/main/proto/{request,response}.proto. The com.google.protobuf Gradle plugin generates Java classes into server/build/generated/sources/proto/main/java/com/miti99/caro/protocol/. No reflection, no string-keyed lookups.

Client Architecture

client/src/
  main.js                    Phaser game boot
  config/
    game-config.js           Phaser config (800x800, Scale.FIT)
    protocol-constants.js    ClientEventCode (event bus keys) only
  generated/
    protocol.js              pbjs static-module output (Request/Response)
    protocol.d.ts            pbts TypeScript typings for protocol.js
  scenes/
    boot-scene.js            Connect to server
    menu-scene.js            DOM overlay menus
    game-scene.js            Board rendering + game interaction
  services/
    event-bus.js             Pub/sub event decoupling
    connection-service.js    WebSocket with heartbeat + reconnect
    game-state-service.js    Client-side state container
  objects/
    board.js                 15x15 grid with wood texture
    stone.js                 Gradient stones with drop animation
  ui/
    menu-ui.js               Nickname, lobby, room list, waiting room
    game-ui.js               HUD, move history, game over, toasts

Server Options

-p, -port    WebSocket port (default: 1999)

Client Scripts

npm --prefix client run dev      # Start Vite dev server (port 5173)
npm --prefix client run build    # Production build to client/dist/
npm --prefix client run preview  # Preview production build
npm --prefix client run proto:gen # Regenerate client/src/generated/protocol.{js,d.ts}

Protocol

Communication uses typed protobuf binary frames over WebSocket.

Every client-to-server message is an instance of the Request oneof wrapper (server/src/main/proto/request.proto); every server-to-client message is an instance of the Response oneof wrapper (server/src/main/proto/response.proto). The oneof case IS the event type — there are no string codes on the wire.

WebSocket endpoint: ws://host:1999/ratel

Example (send a move at row 7, col 7):

connectionService.sendGameMove(7, 7); // builds Request { game_move: { row: 7, col: 7 } }

Credits

This project is based on Ratel by ainilili, originally a Chinese Landlords (Dou Di Zhu) card game. It has been converted to Gomoku (Five-in-a-Row) with a new web client.

  • Original project: ainilili/ratel — Netty-based multiplayer game framework
  • Networking: Netty — asynchronous event-driven network framework
  • Web game engine: Phaser 3 — HTML5 game framework
  • Client build tool: Vite — next-generation client tooling
  • Server build tool: Gradle with Shadow plugin for fat jars

License

Licensed under the Apache License 2.0.

S
Description
A caro server, based on [ratel](https://github.com/ainilili/ratel)
Readme Apache-2.0 6.4 MiB
Languages
JavaScript 84.1%
Java 14.6%
HTML 1.1%
Dockerfile 0.2%