From 0d71b39f609ebfb72da644d5e2735197d30ea650 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 9 Apr 2026 17:10:17 +0700 Subject: [PATCH] plan: caro simplification - remove landlords code, implement gomoku flow 5-phase plan to strip card game remnants, clean enums/entities, rewrite server/client event handlers for Gomoku, and verify build. --- .../phase-01-delete-dead-files.md | 80 +++++++++ .../phase-02-clean-shared-code.md | 92 ++++++++++ .../phase-03-rewrite-server-events.md | 164 ++++++++++++++++++ .../phase-04-rewrite-client-events.md | 144 +++++++++++++++ .../phase-05-integration-verify.md | 116 +++++++++++++ plans/260409-1701-caro-simplification/plan.md | 46 +++++ 6 files changed, 642 insertions(+) create mode 100644 plans/260409-1701-caro-simplification/phase-01-delete-dead-files.md create mode 100644 plans/260409-1701-caro-simplification/phase-02-clean-shared-code.md create mode 100644 plans/260409-1701-caro-simplification/phase-03-rewrite-server-events.md create mode 100644 plans/260409-1701-caro-simplification/phase-04-rewrite-client-events.md create mode 100644 plans/260409-1701-caro-simplification/phase-05-integration-verify.md create mode 100644 plans/260409-1701-caro-simplification/plan.md diff --git a/plans/260409-1701-caro-simplification/phase-01-delete-dead-files.md b/plans/260409-1701-caro-simplification/phase-01-delete-dead-files.md new file mode 100644 index 0000000..90891fe --- /dev/null +++ b/plans/260409-1701-caro-simplification/phase-01-delete-dead-files.md @@ -0,0 +1,80 @@ +## Phase 1: Delete Dead Files + +### Context Links +- [Plan overview](./plan.md) + +### Overview +- **Priority:** P1 (do first -- unblocks everything) +- **Status:** Pending +- **Effort:** 30m + +Pure deletion phase. No logic changes. Every file listed is either landlords-specific code or obsolete documentation. + +### Files to Delete + +**Common module -- Poker domain:** +- `landlords-common/src/main/java/org/nico/ratel/landlords/entity/Poker.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/entity/PokerSell.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerLevel.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerType.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/helper/PokerHelper.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/utils/LastCardsUtils.java` + +**Common module -- Old robot system:** +- `landlords-common/src/main/java/org/nico/ratel/landlords/robot/AbstractRobotDecisionMakers.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/robot/EasyRobotDecisionMakers.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/robot/MediumRobotDecisionMakers.java` +- `landlords-common/src/main/java/org/nico/ratel/landlords/robot/RobotDecisionMakers.java` + +**Common module -- Tests:** +- `landlords-common/src/test/java/org/nico/ratel/landlords/helper/tests/PokerHelperTest.java` +- `landlords-common/src/test/java/org/nico/ratel/landlords/robot/tests/MediumRobotDecisionMakersTests.java` + +**Common module -- Chinese i18n:** +- `landlords-common/src/main/resources/messages_zh_CN.properties` + +**Server module -- Landlord event handlers (6 files):** +- `landlords-server/.../event/ServerEventListener_CODE_GAME_LANDLORD_ELECT.java` +- `landlords-server/.../event/ServerEventListener_CODE_GAME_POKER_PLAY.java` +- `landlords-server/.../event/ServerEventListener_CODE_GAME_POKER_PLAY_PASS.java` +- `landlords-server/.../event/ServerEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java` +- `landlords-server/.../robot/RobotEventListener_CODE_GAME_LANDLORD_ELECT.java` +- `landlords-server/.../robot/RobotEventListener_CODE_GAME_POKER_PLAY.java` + +**Client module -- Landlord event handlers (12 files):** +- `landlords-client/.../event/ClientEventListener_CODE_GAME_LANDLORD_CONFIRM.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_LANDLORD_CYCLE.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_LANDLORD_ELECT.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_CANT_PASS.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_INVALID.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_LESS.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_MISMATCH.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_ORDER_ERROR.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_PASS.java` +- `landlords-client/.../event/ClientEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java` +- `landlords-client/.../event/ClientEventListener_CODE_SHOW_POKERS.java` + +**Root-level files:** +- `GOMOKU_CONVERSION_SUMMARY.md` +- `PROTOCO_CN.md` +- `UPDATE.md` +- `serverlist.json` +- `docker/` (entire directory) + +### Total: ~35 files/dirs deleted + +### Implementation Steps +1. Delete all files listed above via `git rm` +2. Run `mvn compile` -- expect failures (imports of deleted classes). Those are fixed in Phase 2. +3. Commit: `refactor: delete all landlords card game code and obsolete docs` + +### Risk Assessment +- **Risk:** Accidentally delete a file still referenced by kept code +- **Mitigation:** Phase 2 explicitly fixes all broken imports. Compile verification in Phase 5. +- **Likelihood:** Low (all files audited against grep results) + +### Success Criteria +- [ ] All listed files removed from repo +- [ ] No landlord/poker .java files remain +- [ ] Commit is clean and focused diff --git a/plans/260409-1701-caro-simplification/phase-02-clean-shared-code.md b/plans/260409-1701-caro-simplification/phase-02-clean-shared-code.md new file mode 100644 index 0000000..5c8999d --- /dev/null +++ b/plans/260409-1701-caro-simplification/phase-02-clean-shared-code.md @@ -0,0 +1,92 @@ +## Phase 2: Clean Shared Code (Common Module) + +### Context Links +- [Plan overview](./plan.md) +- [Phase 1](./phase-01-delete-dead-files.md) (must complete first) + +### Overview +- **Priority:** P1 +- **Status:** Pending +- **Effort:** 1h +- **Blocked by:** Phase 1 + +Remove all landlords references from shared entities, enums, helpers, and printers. After this phase, the common module compiles cleanly with only Gomoku domain code. + +### Key Insights +- `Room.java` is already mostly clean (gomoku fields present). But it still has `setCurrentSellClient()` called from server code, and leftover `scoreRate`/`baseScore`/`score` fields. +- `ClientSide.java` has no `pokers` field (already removed) but still has `score`, `scoreInc`, `type` (ClientType = LANDLORD/PEASANT), and linked-list `next`/`pre` fields used for 3-player turn order. +- `ClientEventCode.java` and `ServerEventCode.java` are already cleaned up -- only Gomoku codes remain. No changes needed. +- `ClientRole.java` has `PLAYER, ROBOT, BLACK_PLAYER, WHITE_PLAYER` -- needs simplification. +- `ClientStatus.java` has `CALL_LANDLORD` -- remove it. +- `ClientType.java` (LANDLORD/PEASANT) -- delete entire enum, not applicable to Gomoku. +- `SimplePrinter.java` has `printPokers()` method referencing deleted PokerHelper -- must remove. +- `ClientEventListener.java` (client base class) has `lastPokers`, `lastSellClientNickname`, `lastSellClientType` static fields -- must remove. + +### Files to Modify + +| File | Changes | +|------|---------| +| `entity/Room.java` | Remove `scoreRate`, `baseScore`, `currentSellClient`, `firstSellClient`, `landlordPokers`, `landlordId`, `lastSellClient` and all their getters/setters. Keep gomoku fields. | +| `entity/ClientSide.java` | Remove `score`, `scoreInc`, `type` (ClientType), `next`, `pre`, `round` fields + getters/setters. Gomoku doesn't need linked-list player chaining (use Room's clientSideMap). | +| `enums/ClientRole.java` | Remove `PLAYER` and `ROBOT`. Keep `BLACK_PLAYER`, `WHITE_PLAYER`. Add `SPECTATOR`. | +| `enums/ClientStatus.java` | Remove `CALL_LANDLORD`. Keep `TO_CHOOSE`, `NO_READY`, `READY`, `WAIT`, `PLAYING`. | +| `enums/ClientType.java` | **Delete entire file** -- no concept of landlord/peasant in Gomoku. | +| `print/SimplePrinter.java` | Remove `printPokers()` method and `import Poker/PokerHelper`. Remove `pokerDisplayFormat` field. | +| `helper/I18nHelper.java` | Verify no reference to `messages_zh_CN.properties` (already handles fallback to en_US). | + +### Files to Delete +- `landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientType.java` + +### Implementation Steps + +1. **Delete `ClientType.java`** + +2. **Clean `Room.java`:** + - Remove fields: `scoreRate`, `baseScore` (and `getScore()`, `initScoreRate()`, `increaseRate()` methods) + - Verify no `landlordPokers`, `currentSellClient`, `firstSellClient`, `lastSellClient`, `landlordId` fields exist (grep confirms Room.java already lacks these -- they exist only in deleted server files that call non-existent setters) + - Actually: grep shows `room.setCurrentSellClient()` called from server files, but Room.java has no such method. These are in files being deleted in Phase 1. **No Room.java changes needed for these.** + - Remove: `scoreRate`, `baseScore`, `getScore()`, `getBaseScore()`, `setBaseScore()`, `getScoreRate()`, `setScoreRate()`, `initScoreRate()`, `increaseRate()` -- these are unused in Gomoku + +3. **Clean `ClientSide.java`:** + - Remove `type` field (ClientType) + getter/setter + - Remove `score`, `scoreInc` fields + getter/setter/`addScore()` + - Remove `next`, `pre` fields + getter/setter (3-player circular list not needed for 2-player Gomoku; use Room.clientSideMap) + - Remove `round`, `resetRound()`, `addRound()`, `getRound()` + - Update `init()` to remove references to removed fields + +4. **Clean `ClientRole.java`:** + - Remove `PLAYER` and `ROBOT` + - Add `SPECTATOR` + - Result: `BLACK_PLAYER, WHITE_PLAYER, SPECTATOR` + +5. **Clean `ClientStatus.java`:** + - Remove `CALL_LANDLORD` + +6. **Clean `SimplePrinter.java`:** + - Remove `import org.nico.ratel.landlords.entity.Poker` + - Remove `import org.nico.ratel.landlords.helper.PokerHelper` + - Remove `pokerDisplayFormat` static field + - Remove `printPokers()` method + +7. **Clean `ClientEventListener.java` (client module base class):** + - Remove `import org.nico.ratel.landlords.entity.Poker` + - Remove static fields: `lastPokers`, `lastSellClientNickname`, `lastSellClientType` + - Remove `initLastSellInfo()` method + +8. Run `mvn compile -pl landlords-common` -- must pass + +### Risk Assessment +- **Risk:** Removing `next`/`pre` from ClientSide breaks server event handlers that use circular linked list for turn order +- **Mitigation:** Server handlers are rewritten in Phase 3 to use Room's `isPlayerTurn()` / `currentTurn` instead. Phase 3 must not use `client.getNext()`. +- **Likelihood:** Medium +- **Impact:** Compile error (caught immediately) + +### Security Considerations +None -- no auth/data changes. + +### Success Criteria +- [ ] `ClientType.java` deleted +- [ ] No `import.*Poker` in any kept file +- [ ] No `score`/`scoreRate`/`baseScore` in Room or ClientSide +- [ ] ClientRole has exactly: `BLACK_PLAYER, WHITE_PLAYER, SPECTATOR` +- [ ] `mvn compile -pl landlords-common` passes diff --git a/plans/260409-1701-caro-simplification/phase-03-rewrite-server-events.md b/plans/260409-1701-caro-simplification/phase-03-rewrite-server-events.md new file mode 100644 index 0000000..42f7854 --- /dev/null +++ b/plans/260409-1701-caro-simplification/phase-03-rewrite-server-events.md @@ -0,0 +1,164 @@ +## Phase 3: Rewrite Server Event Handlers + +### Context Links +- [Plan overview](./plan.md) +- [Phase 2](./phase-02-clean-shared-code.md) (must complete first) +- Key domain files: `Board.java`, `GomokuHelper.java`, `GomokuAI.java`, `Room.java` + +### Overview +- **Priority:** P1 +- **Status:** Pending +- **Effort:** 2h +- **Blocked by:** Phase 2 + +Rewrite the server-side event handlers to implement Gomoku game flow. Create the missing `ServerEventListener_CODE_GAME_MOVE.java`. Fix existing handlers that still contain landlords logic. + +### Data Flow: Gomoku Game Lifecycle + +``` +Client Server + |-- CODE_ROOM_CREATE ---------->| Create room, assign client as BLACK_PLAYER + |<-- CODE_ROOM_CREATE_SUCCESS --| + | | + |-- CODE_ROOM_JOIN ------------>| Join room, assign as WHITE_PLAYER + |<-- CODE_ROOM_JOIN_SUCCESS ----| (to both players) + | | Auto-start: call CODE_GAME_STARTING + |<-- CODE_GAME_STARTING --------| (to both players: board state, who is black/white) + | | + |-- CODE_GAME_MOVE ------------>| Validate move via GomokuHelper + |<-- CODE_GAME_MOVE_SUCCESS ----| (broadcast to both + spectators) + | or CODE_GAME_MOVE_INVALID | + | or CODE_GAME_MOVE_OCCUPIED | + | or CODE_GAME_MOVE_NOT_YOUR_TURN | + | | + |<-- CODE_GAME_OVER -----------| (when GomokuHelper detects win/draw) +``` + +### Files to Create + +**`ServerEventListener_CODE_GAME_MOVE.java`** -- the core missing handler + +``` +Package: org.nico.ratel.landlords.server.event +``` + +Logic: +1. Parse `data` as JSON: `{ "row": int, "col": int }` +2. Get room from `ServerContains.getRoom(clientSide.getRoomId())` +3. Null-check room -> push `CODE_ROOM_PLAY_FAIL_BY_INEXIST` +4. Check `room.isPlayerTurn(clientSide.getId())` -> if false, push `CODE_GAME_MOVE_NOT_YOUR_TURN` +5. Check `room.getGameBoard().isValidMove(row, col)`: + - Out of bounds -> `CODE_GAME_MOVE_OUT_OF_BOUNDS` + - Position occupied -> `CODE_GAME_MOVE_OCCUPIED` +6. Call `GomokuHelper.makeMove(room, row, col, clientSide.getId())` +7. Build result JSON: `{ row, col, piece, playerId, playerNickname, nextPlayerId }` +8. Broadcast `CODE_GAME_MOVE_SUCCESS` to all players + spectators +9. Check `GomokuHelper.isGameOver(room)`: + - If yes, determine winner, broadcast `CODE_GAME_OVER` with `{ result, winnerNickname, board }` + - For PVE: if next turn is AI, trigger AI move via `GomokuAI.getNextMove()` and recurse + +**`RobotEventListener_CODE_GAME_MOVE.java`** -- AI move handler for PVE + +``` +Package: org.nico.ratel.landlords.server.robot +``` + +Logic: +1. Get room, get AI piece color from room +2. Call `GomokuAI.getNextMove(board, difficulty)` +3. Delegate to `ServerEventListener_CODE_GAME_MOVE` with the AI's move data + +### Files to Rewrite + +**`ServerEventListener_CODE_GAME_STARTING.java`** -- Currently distributes poker cards. Rewrite for Gomoku: +1. Get room +2. Assign players: first player = BLACK, second = WHITE +3. Set `room.setBlackPlayerId(first.getId())`, `room.setWhitePlayerId(second.getId())` +4. Set player roles: `first.setRole(ClientRole.BLACK_PLAYER)`, `second.setRole(ClientRole.WHITE_PLAYER)` +5. Set `room.setStatus(RoomStatus.STARTING)` +6. Set `room.setCurrentTurn(PieceType.BLACK)` +7. Reset board: `room.getGameBoard().reset()` +8. Build result JSON: `{ roomId, blackPlayer: {id, nickname}, whitePlayer: {id, nickname}, boardSize: 15 }` +9. Push `CODE_GAME_STARTING` to both players + spectators +10. For PVE: if AI is BLACK, trigger AI first move + +**`ServerEventListener_CODE_GAME_READY.java`** -- Currently checks for 3 players and uses `ClientRole.PLAYER`. Rewrite: +1. Change player count check from 3 to 2 +2. Replace `ClientRole.PLAYER` references with check for non-null channel (human player) +3. Remove Chinese log messages (`"房间状态"`, `"玩家状态"`) +4. When all ready, call `CODE_GAME_STARTING` + +**`ServerEventListener_CODE_ROOM_CREATE.java`** -- Currently calls `room.setCurrentSellClient()`. Rewrite: +1. Remove `room.setCurrentSellClient()` call +2. Set first player as `ClientRole.BLACK_PLAYER` +3. Rest is fine + +**`ServerEventListener_CODE_ROOM_CREATE_PVE.java`** -- Currently creates 2 robots for 3-player game. Rewrite: +1. Create room with human player +2. Create 1 AI robot (not 2) -- Gomoku is 2-player +3. Assign human as BLACK, AI as WHITE (or configurable) +4. Replace `RobotDecisionMakers.contains()` with simple difficulty range check (1-3) +5. Remove `client.setNext()`/`client.setPre()` linked-list wiring +6. Auto-start game immediately + +**`ServerEventListener_CODE_ROOM_JOIN.java`** -- Currently allows up to 3 players. Rewrite: +1. Change full-room check from `size == 3` to `size == 2` +2. Remove `next`/`pre` linked-list wiring +3. When 2nd player joins, auto-start game (call `CODE_GAME_STARTING`) +4. Remove Chinese comments + +**`ServerEventListener_CODE_CLIENT_EXIT.java`** -- Currently uses `ClientRole.PLAYER`. Update: +1. Replace `ClientRole.PLAYER` with check against `BLACK_PLAYER`/`WHITE_PLAYER` +2. Remove Chinese comments + +**`RoomClearTask.java`** -- Heavy landlords logic (robot substitution, poker custody). Rewrite: +1. Keep timeout-based room cleanup (waitingStatusInterval, liveTime) +2. Remove all robot-substitution logic (lines 76-130) +3. Remove references to `currentSellClient`, `lastSellClient`, `landlordId`, `setPokers`, `setType` +4. On timeout: just close the room and notify players +5. Remove `RobotEventListener` import and call + +**`RobotEventListener.java`** (interface) -- Keep but will only resolve `CODE_GAME_MOVE`: +1. No structural change needed, reflection-based lookup still works + +### Files to Verify (minor touch-ups) + +- `ServerEventListener_CODE_GAME_WATCH.java` -- likely uses Chinese comments, remove them +- `ServerEventListener_CODE_GAME_WATCH_EXIT.java` -- same +- `ServerEventListener_CODE_CLIENT_OFFLINE.java` -- verify no poker references +- `ServerEventListener_CODE_CLIENT_INFO_SET.java` -- verify clean +- `ServerEventListener_CODE_CLIENT_NICKNAME_SET.java` -- verify clean +- `ServerEventListener_CODE_GET_ROOMS.java` -- verify clean + +### Architecture: PVE Move Flow + +``` +Human makes move -> ServerEventListener_CODE_GAME_MOVE + -> validate + apply move + -> check game over? + -> if not over && next turn is AI: + -> GomokuAI.getNextMove(board, difficulty) + -> apply AI move to board via GomokuHelper + -> broadcast AI move as CODE_GAME_MOVE_SUCCESS + -> check game over again +``` + +No separate robot event listener needed for moves -- handle AI inline in CODE_GAME_MOVE handler to avoid complexity. Delete RobotEventListener_CODE_GAME_MOVE if created, or simply don't create it. + +**Revised approach:** Handle AI response inline in `ServerEventListener_CODE_GAME_MOVE.java` rather than via separate RobotEventListener. Simpler, fewer files, same behavior. + +### Risk Assessment + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|------------| +| Breaking room join flow (2 vs 3 players) | Medium | High | Unit test: create room, join, verify auto-start | +| AI move infinite loop (AI triggers AI) | Low | High | Guard: only trigger AI if current turn belongs to AI player, and game not over | +| Race condition on concurrent moves | Low | Medium | Room operations already single-threaded per room via Netty event loop | + +### Success Criteria +- [ ] `ServerEventListener_CODE_GAME_MOVE.java` exists and handles move validation + win detection +- [ ] PVE mode creates 1 AI robot, not 2 +- [ ] Room join auto-starts at 2 players +- [ ] No references to Poker, PokerSell, PokerHelper, LastCardsUtils in any server file +- [ ] No Chinese text in any server file (except LICENSE) +- [ ] `mvn compile -pl landlords-server` passes diff --git a/plans/260409-1701-caro-simplification/phase-04-rewrite-client-events.md b/plans/260409-1701-caro-simplification/phase-04-rewrite-client-events.md new file mode 100644 index 0000000..fc37a15 --- /dev/null +++ b/plans/260409-1701-caro-simplification/phase-04-rewrite-client-events.md @@ -0,0 +1,144 @@ +## Phase 4: Rewrite Client Event Handlers + +### Context Links +- [Plan overview](./plan.md) +- [Phase 2](./phase-02-clean-shared-code.md) (must complete first) +- Can run **in parallel** with Phase 3 (no file overlap) + +### Overview +- **Priority:** P1 +- **Status:** Pending +- **Effort:** 1.5h +- **Blocked by:** Phase 2 + +Rewrite client-side event handlers to display Gomoku game state. The client is a CLI app -- it reads server events and prints board/prompts to the console, then sends user input back. + +### Files to Rewrite + +**`ClientEventListener_CODE_GAME_STARTING.java`** -- Currently prints poker cards. Rewrite: +1. Parse server data: `{ roomId, blackPlayer: {id, nickname}, whitePlayer: {id, nickname}, boardSize }` +2. Print: "Game starting! You are [BLACK/WHITE]" +3. Print initial empty board via `GomokuHelper.formatBoardForDisplay()` +4. If player is BLACK, prompt for first move +5. Remove all Poker imports and references + +**`ClientEventListener_CODE_GAME_OVER.java`** -- Currently shows poker scores. Rewrite: +1. Parse: `{ result, winnerNickname, board }` +2. Print final board state +3. Print result: "Black wins!" / "White wins!" / "Draw!" via `GomokuHelper.getWinnerMessage()` +4. Remove score display logic +5. Call `ClientEventListener_CODE_GAME_READY.gameReady(channel)` to offer rematch + +**`ClientEventListener_CODE_SHOW_OPTIONS_PVE.java`** -- Currently calls `initLastSellInfo()`. Update: +1. Remove `initLastSellInfo()` call (method deleted in Phase 2) +2. Keep difficulty selection (Easy/Medium/Hard maps to 1/2/3) +3. Rest is clean + +**`ClientEventListener_CODE_SHOW_OPTIONS_SETTING.java`** -- Check for poker display format references: +1. Remove any `pokerDisplayFormat` references +2. Keep language selection if present + +**New: `ClientEventListener_CODE_GAME_MOVE_SUCCESS.java`** -- Handle successful move broadcast: +1. Parse: `{ row, col, piece, playerNickname, nextPlayerId }` +2. Print: "[playerNickname] placed [BLACK/WHITE] at (row, col)" +3. Print updated board via `GomokuHelper.formatBoardForDisplay()` +4. If it's this player's turn next, prompt for move input +5. Read input as "row,col", send `CODE_GAME_MOVE` to server with `{ row, col }` + +**New: `ClientEventListener_CODE_GAME_MOVE_INVALID.java`** -- Handle invalid move: +1. Print "Invalid move. Please try again." +2. Re-prompt for move input + +**New: `ClientEventListener_CODE_GAME_MOVE_OCCUPIED.java`** -- Handle occupied position: +1. Print "Position already occupied. Please choose another." +2. Re-prompt for move input + +**New: `ClientEventListener_CODE_GAME_MOVE_OUT_OF_BOUNDS.java`** -- Handle out of bounds: +1. Print "Move out of bounds. Board is 15x15 (0-14)." +2. Re-prompt for move input + +**New: `ClientEventListener_CODE_GAME_MOVE_NOT_YOUR_TURN.java`** -- Handle wrong turn: +1. Print "It's not your turn. Please wait." + +**New: `ClientEventListener_CODE_SHOW_BOARD.java`** -- Handle board display request: +1. This is a client-only code; may need special handling +2. Or simply handle "board" command locally in the move input loop + +### Files Unchanged (already clean) +- `ClientEventListener_CODE_CLIENT_CONNECT.java` +- `ClientEventListener_CODE_CLIENT_EXIT.java` +- `ClientEventListener_CODE_CLIENT_KICK.java` +- `ClientEventListener_CODE_CLIENT_NICKNAME_SET.java` +- `ClientEventListener_CODE_ROOM_CREATE_SUCCESS.java` +- `ClientEventListener_CODE_ROOM_JOIN_SUCCESS.java` +- `ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_FULL.java` +- `ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_INEXIST.java` +- `ClientEventListener_CODE_ROOM_PLAY_FAIL_BY_INEXIST.java` +- `ClientEventListener_CODE_SHOW_OPTIONS.java` +- `ClientEventListener_CODE_SHOW_OPTIONS_PVP.java` +- `ClientEventListener_CODE_SHOW_ROOMS.java` +- `ClientEventListener_CODE_PVE_DIFFICULTY_NOT_SUPPORT.java` +- `ClientEventListener_CODE_GAME_READY.java` +- `ClientEventListener_CODE_GAME_WATCH.java` +- `ClientEventListener_CODE_GAME_WATCH_SUCCESSFUL.java` + +### Move Input Pattern + +The client prompts for a move and sends it to server. Pattern used in new handlers: + +```java +String input = SimpleWriter.write(nickname, "move"); +// Parse "row,col" format +// Handle special commands: "board"/"b", "history"/"h", "exit"/"e" +if (input matches "\\d+,\\d+") { + String moveData = MapHelper.newInstance() + .put("row", row).put("col", col).json(); + pushToServer(channel, ServerEventCode.CODE_GAME_MOVE, moveData); +} else if (input is "board" or "b") { + // print board locally (need to store board state client-side or request from server) +} else if (input is "exit" or "e") { + pushToServer(channel, ServerEventCode.CODE_CLIENT_EXIT, null); +} +``` + +**Key decision:** Store board state client-side (in a static field on the listener or a shared client state object) so "board" and "history" commands work without server round-trip. + +### Client-Side State + +Add a simple static state holder (or use existing `User.java`): + +```java +// In ClientEventListener or a new small class +static Board localBoard = null; +static PieceType myPiece = null; +static String myNickname = null; +``` + +Set these in `CODE_GAME_STARTING` handler. Update board in `CODE_GAME_MOVE_SUCCESS` handler. + +### Files to Verify (Chinese text removal) +- `ClientEventListener_CODE_GAME_WATCH.java` -- grep found Chinese; remove +- `ClientEventListener_CODE_GAME_WATCH_SUCCESSFUL.java` -- check + +### SimpleClient.java Changes +- Remove `serverAddressSource` array (fetches from upstream ratel repo) +- When no `-h` flag provided, print error asking user to specify host instead of fetching server list +- Remove `getServerAddressList()` method +- Keep language selection logic (only en_US matters now) + +### Risk Assessment + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|------------| +| Move input parsing errors (non "row,col" format) | Medium | Low | Validate format, re-prompt on bad input | +| Client board state out of sync with server | Low | Medium | Server is authoritative; client board is display-only. Re-sync on each CODE_GAME_MOVE_SUCCESS | +| Blocking on SimpleWriter.write() during opponent's turn | Low | Low | Existing pattern -- client blocks on stdin. Move prompt only shown when it's player's turn | + +### Success Criteria +- [ ] 5 new client event handler files created for Gomoku move codes +- [ ] `CODE_GAME_STARTING` prints board, not poker cards +- [ ] `CODE_GAME_OVER` shows winner without scores +- [ ] Client can display board and prompt for "row,col" input +- [ ] No Poker imports in any client file +- [ ] No Chinese text in any client file +- [ ] `mvn compile -pl landlords-client` passes diff --git a/plans/260409-1701-caro-simplification/phase-05-integration-verify.md b/plans/260409-1701-caro-simplification/phase-05-integration-verify.md new file mode 100644 index 0000000..49537e9 --- /dev/null +++ b/plans/260409-1701-caro-simplification/phase-05-integration-verify.md @@ -0,0 +1,116 @@ +## Phase 5: Integration Test & Compile Verify + +### Context Links +- [Plan overview](./plan.md) +- [Phase 3](./phase-03-rewrite-server-events.md), [Phase 4](./phase-04-rewrite-client-events.md) (must both complete first) + +### Overview +- **Priority:** P1 +- **Status:** Pending +- **Effort:** 1h +- **Blocked by:** Phase 3, Phase 4 + +Full build verification, fix remaining compile errors, clean up README, and validate the game flow works end-to-end. + +### Implementation Steps + +#### 1. Full Maven Build +```bash +mvn clean compile +``` +Fix any compile errors iteratively. Common expected issues: +- Missing imports of deleted classes in files not yet touched +- `ClientRole.PLAYER` references in files outside the main event handlers +- `ClientType` references anywhere +- `getNext()`/`getPre()` calls if any kept file uses them + +#### 2. Run Existing Tests +```bash +mvn test +``` +- `GomokuHelperTest.java` should pass (tests Gomoku logic, no poker deps) +- Deleted tests (PokerHelperTest, MediumRobotDecisionMakersTests) are gone -- no failures from those + +#### 3. Add Basic Gomoku Integration Test + +Create `landlords-common/src/test/java/org/nico/ratel/landlords/helper/tests/GomokuIntegrationTest.java`: +- Test full game flow in-memory: create Room, assign players, make moves, detect win +- Test draw detection (fill board) +- Test invalid move rejection (occupied, out of bounds, wrong turn) +- Test board reset + +#### 4. Clean Up README.md +- Remove references to original ratel/landlords +- Remove badge URLs pointing to ainilili/ratel +- Remove serverlist.json references +- Remove ecosystem links (go-ratel-client etc.) or mark as incompatible +- Remove bilibili video link +- Keep installation instructions, update to reflect current project +- Update game commands section (already correct for Gomoku) + +#### 5. Grep Sweep -- Verify No Leftovers + +Run these greps to ensure nothing was missed: + +```bash +# No poker/landlord references in kept Java files +grep -r "Poker\|PokerSell\|PokerHelper\|PokerLevel\|PokerType" --include="*.java" . +grep -r "landlord\|LANDLORD\|Landlord" --include="*.java" . +grep -r "LastCardsUtils\|lastCards\|lastPokers" --include="*.java" . + +# No Chinese characters in Java files +grep -rP "[\x{4e00}-\x{9fff}]" --include="*.java" . + +# No references to deleted event codes +grep -r "CODE_GAME_POKER\|CODE_GAME_LANDLORD\|CODE_SHOW_POKERS" --include="*.java" . +``` + +Allowed exceptions: +- `LandlordException.java` class name -- rename to `GameException.java` or leave (low priority) +- Package names contain `landlords` -- intentionally kept (see plan.md decision #1) +- `LICENSE` file -- keep as-is + +#### 6. Verify Game Flow Manually (if time permits) + +Start server: +```bash +java -jar landlords-server/target/landlords-server-1.4.0.jar -p 1024 +``` + +Start 2 clients: +```bash +java -jar landlords-client/target/landlords-client-1.4.0.jar -h 127.0.0.1 -p 1024 +``` + +Test flow: +1. Client 1: set nickname, create room +2. Client 2: set nickname, join room +3. Verify game auto-starts, board displays +4. Make alternating moves, verify board updates +5. Play to win condition, verify game over message + +### Cleanup Items (Low Priority, Optional) + +| Item | Rationale | +|------|-----------| +| Rename `LandlordException` to `GameException` | Cosmetic, low value | +| Rename modules `landlords-*` to `caro-*` | High churn, defer to separate PR | +| Remove `FormatPrinter.java` | Check if used; if not, delete | +| Remove `features/Features.java` | Check if only VERSION constant; if so, keep | +| Simplify `SimpleClient.java` server list fetching | Already addressed in Phase 4 | + +### Risk Assessment + +| Risk | Likelihood | Impact | Mitigation | +|------|-----------|--------|------------| +| Hidden compile error in untouched file | Medium | Low | Full `mvn compile` catches all | +| GomokuHelperTest relies on deleted code | Low | Low | Test file already reviewed -- uses only Gomoku classes | +| Manual test reveals game flow bug | Medium | Medium | Fix in this phase before merging | + +### Success Criteria +- [ ] `mvn clean compile` passes with zero errors +- [ ] `mvn test` passes -- all tests green +- [ ] Grep sweep shows no poker/landlord references in Java code (except package names and LandlordException) +- [ ] No Chinese characters in Java files +- [ ] README reflects current Gomoku project +- [ ] GomokuIntegrationTest covers: valid move, invalid move, win detection, draw detection diff --git a/plans/260409-1701-caro-simplification/plan.md b/plans/260409-1701-caro-simplification/plan.md new file mode 100644 index 0000000..fb25af2 --- /dev/null +++ b/plans/260409-1701-caro-simplification/plan.md @@ -0,0 +1,46 @@ +--- +title: "Caro/Gomoku Codebase Simplification" +description: "Strip landlords card game code, fix Gomoku game flow end-to-end, simplify to working client-server Gomoku" +status: pending +priority: P1 +effort: 6h +branch: master +tags: [cleanup, gomoku, simplification] +created: 2026-04-09 +--- + +# Caro/Gomoku Codebase Simplification + +## Overview + +Strip all leftover Chinese Landlords card game code from this Netty-based project, leaving a clean Gomoku (Five-in-a-Row) client-server application. The Gomoku domain classes (Board, GameMove, GomokuHelper, GomokuAI, PieceType, GameResult) already exist and are well-implemented. The main gap is the server/client event handlers still run landlords logic. + +## Phase Summary + +| # | Phase | Status | Effort | Blocked By | +|---|-------|--------|--------|------------| +| 1 | Delete dead files | Pending | 30m | - | +| 2 | Clean shared code (common module) | Pending | 1h | Phase 1 | +| 3 | Rewrite server event handlers | Pending | 2h | Phase 2 | +| 4 | Rewrite client event handlers | Pending | 1.5h | Phase 2 | +| 5 | Integration test & compile verify | Pending | 1h | Phase 3, 4 | + +## Phases + +- [Phase 1: Delete Dead Files](./phase-01-delete-dead-files.md) +- [Phase 2: Clean Shared Code](./phase-02-clean-shared-code.md) +- [Phase 3: Rewrite Server Event Handlers](./phase-03-rewrite-server-events.md) +- [Phase 4: Rewrite Client Event Handlers](./phase-04-rewrite-client-events.md) +- [Phase 5: Integration Test & Compile Verify](./phase-05-integration-verify.md) + +## Key Architectural Decisions + +1. **Keep module names as `landlords-*`** -- renaming Maven modules cascades into groupId, package names, imports across every file. High churn, zero functional value. Defer to a separate PR if desired. +2. **Keep WebSocket support** -- already wired, removing adds risk, keeping costs nothing. +3. **2-player rooms** -- Gomoku is 2-player. Change room full check from `size == 3` to `size == 2`. Auto-start when second player joins. +4. **Remove scoring system** -- Gomoku has no points/scoring. Strip `score`, `scoreRate`, `baseScore`, `scoreInc` from Room and ClientSide. +5. **PVE uses GomokuAI** -- Replace old robot system with single GomokuAI class. Delete AbstractRobotDecisionMakers, Easy/MediumRobotDecisionMakers, RobotDecisionMakers. + +## Rollback Plan + +Each phase is a separate commit. `git revert` any phase independently. Phase 1 (file deletion) is fully recoverable from git history.