mirror of
https://github.com/tiennm99/caro.git
synced 2026-09-03 00:17:42 +00:00
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.
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user