272 lines
9.7 KiB
Markdown
272 lines
9.7 KiB
Markdown
# 背景
|
||
文件名:2025-10-28_1_gomoku.md
|
||
创建于:2025-10-28_17:08:29
|
||
创建者:User
|
||
主分支:main
|
||
任务分支:task/gomoku_2025-10-28_1
|
||
Yolo模式:Off
|
||
|
||
# 任务描述
|
||
创建一个五子棋(Gomoku)游戏模块,支持双人对战功能。
|
||
|
||
## 核心需求
|
||
1. **游戏模式**:双人对战(两个用户在同一个聊天中对战)
|
||
2. **棋盘规格**:标准15x15棋盘
|
||
3. **禁手规则**:需要实现禁手规则(三三禁手、四四禁手、长连禁手)
|
||
4. **超时规则**:不需要回合时间限制
|
||
5. **并发对战**:允许多轮对战同时存在,只要交战双方不同即可
|
||
6. **显示方式**:使用emoji绘制棋盘(⚫⚪➕)+ 坐标系统(A-O列,1-15行)
|
||
|
||
## 功能清单
|
||
- 开始游戏:`.gomoku start @对手` 或 `.gomoku @对手`
|
||
- 落子:`.gomoku A1` 或 `.gomoku 落子 A1`
|
||
- 认输:`.gomoku resign` 或 `.gomoku 认输`
|
||
- 查看棋盘:`.gomoku show` 或 `.gomoku 查看`
|
||
- 查看战绩:`.gomoku stats` 或 `.gomoku 战绩`
|
||
- 帮助信息:`.gomoku help` 或 `.gomoku 帮助`
|
||
|
||
## 技术要点
|
||
1. 继承`BaseGame`基类
|
||
2. 游戏状态存储在数据库中(使用chat_id + 对战双方ID作为键)
|
||
3. 需要实现五子棋禁手规则的判定逻辑
|
||
4. 需要实现胜负判定(五子连珠)
|
||
5. 棋盘使用二维数组表示,支持坐标转换(A-O, 1-15)
|
||
|
||
# 项目概览
|
||
|
||
## 现有架构
|
||
- **框架**:FastAPI
|
||
- **数据库**:SQLite(使用标准库sqlite3)
|
||
- **游戏基类**:`games/base.py - BaseGame`
|
||
- **路由处理**:`routers/callback.py`
|
||
- **数据库操作**:`core/database.py - Database类`
|
||
|
||
## 现有游戏
|
||
- 石头剪刀布(rps)
|
||
- 问答游戏(quiz)
|
||
- 猜数字(guess)
|
||
- 成语接龙(idiom)
|
||
- 骰娘系统(dice)
|
||
- 运势占卜(fortune)
|
||
|
||
## 数据库表结构
|
||
1. **users**:用户基本信息
|
||
2. **game_states**:游戏状态(支持chat_id, user_id, game_type的唯一约束)
|
||
3. **game_stats**:游戏统计(wins, losses, draws, total_plays)
|
||
|
||
# 分析
|
||
|
||
## 核心挑战
|
||
|
||
### 1. 游戏状态管理
|
||
- 现有的`game_states`表使用`(chat_id, user_id, game_type)`作为唯一键
|
||
- 五子棋需要双人对战,需要同时记录两个玩家
|
||
- 需要设计状态数据结构,存储:
|
||
- 对战双方ID(player1_id, player2_id)
|
||
- 当前轮到谁(current_player_id)
|
||
- 棋盘状态(15x15二维数组)
|
||
- 游戏状态(waiting, playing, finished)
|
||
- 胜者ID(winner_id,如果有)
|
||
|
||
### 2. 多轮对战并发
|
||
- 允许同一个chat中有多轮对战,只要对战双方不同
|
||
- 需要一个机制来标识不同的对战局(可以用对战双方ID的组合)
|
||
- 状态查询需要能够找到特定用户参与的对战
|
||
|
||
### 3. 禁手规则实现
|
||
禁手规则(仅对黑方,即先手玩家):
|
||
- **三三禁手**:一手棋同时形成两个或以上的活三
|
||
- **四四禁手**:一手棋同时形成两个或以上的活四或冲四
|
||
- **长连禁手**:一手棋形成六子或以上的连珠
|
||
|
||
需要实现:
|
||
- 判断某个位置的四个方向(横、竖、左斜、右斜)的连珠情况
|
||
- 判断活三、活四、冲四的定义
|
||
- 在落子时检查是否触发禁手
|
||
|
||
### 4. 坐标系统
|
||
- 列:A-O(15列)
|
||
- 行:1-15(15行)
|
||
- 需要坐标转换函数:`parse_coord("A1") -> (0, 0)`
|
||
- 需要显示转换函数:`format_coord(0, 0) -> "A1"`
|
||
|
||
### 5. 棋盘显示
|
||
使用emoji:
|
||
- ⚫ 黑子(先手)
|
||
- ⚪ 白子(后手)
|
||
- ➕ 空位
|
||
- 需要添加行号和列号标注
|
||
|
||
示例:
|
||
```
|
||
A B C D E F G H I J K L M N O
|
||
1 ➕➕➕➕➕➕➕➕➕➕➕➕➕➕➕
|
||
2 ➕➕➕➕➕➕➕➕➕➕➕➕➕➕➕
|
||
3 ➕➕⚫➕➕➕➕➕➕➕➕➕➕➕➕
|
||
...
|
||
```
|
||
|
||
## 数据结构设计
|
||
|
||
### state_data结构
|
||
```python
|
||
{
|
||
"player1_id": 123456, # 黑方(先手)
|
||
"player2_id": 789012, # 白方(后手)
|
||
"current_player": 123456, # 当前轮到谁
|
||
"board": [[0]*15 for _ in range(15)], # 0:空, 1:黑, 2:白
|
||
"status": "playing", # waiting, playing, finished
|
||
"winner_id": None, # 胜者ID
|
||
"moves": [], # 历史落子记录 [(row, col, player_id), ...]
|
||
"last_move": None # 最后一手 (row, col)
|
||
}
|
||
```
|
||
|
||
### 游戏状态存储策略
|
||
- 使用chat_id作为会话ID
|
||
- 使用较小的user_id作为主键中的user_id(保证唯一性)
|
||
- 在state_data中存储完整的对战信息
|
||
- 查询时需要检查用户是否是player1或player2
|
||
|
||
# 提议的解决方案
|
||
|
||
## 方案选择
|
||
使用现有的数据库表结构,通过精心设计state_data来支持双人对战。
|
||
|
||
## 实现方案
|
||
|
||
### 1. 游戏类:`games/gomoku.py`
|
||
继承`BaseGame`,实现以下方法:
|
||
- `handle()` - 主处理逻辑
|
||
- `get_help()` - 帮助信息
|
||
- `_start_game()` - 开始游戏
|
||
- `_make_move()` - 落子
|
||
- `_show_board()` - 显示棋盘
|
||
- `_resign()` - 认输
|
||
- `_get_stats()` - 查看战绩
|
||
|
||
### 2. 五子棋逻辑:单独模块或工具类
|
||
- `_parse_coord()` - 解析坐标
|
||
- `_format_coord()` - 格式化坐标
|
||
- `_render_board()` - 渲染棋盘
|
||
- `_check_win()` - 检查胜负
|
||
- `_check_forbidden()` - 检查禁手
|
||
- `_is_valid_move()` - 检查落子是否合法
|
||
|
||
### 3. 禁手检测逻辑
|
||
实现辅助方法:
|
||
- `_count_line()` - 统计某方向的连珠情况
|
||
- `_is_live_three()` - 判断活三
|
||
- `_is_live_four()` - 判断活四
|
||
- `_is_rush_four()` - 判断冲四
|
||
- `_check_three_three()` - 检查三三禁手
|
||
- `_check_four_four()` - 检查四四禁手
|
||
- `_check_overline()` - 检查长连禁手
|
||
|
||
### 4. 状态管理
|
||
- 使用`min(player1_id, player2_id)`作为数据库中的user_id
|
||
- 在state_data中完整存储对战信息
|
||
- 提供辅助方法查找用户当前参与的游戏
|
||
|
||
### 5. 路由注册
|
||
在`routers/callback.py`的`handle_command()`函数中添加:
|
||
```python
|
||
if game_type == 'gomoku':
|
||
from games.gomoku import GomokuGame
|
||
game = GomokuGame()
|
||
return await game.handle(command, chat_id, user_id)
|
||
```
|
||
|
||
### 6. 指令解析
|
||
在`utils/parser.py`的`CommandParser`类中添加gomoku指令识别
|
||
|
||
### 7. 配置更新
|
||
在`config.py`中添加五子棋相关配置(如果需要)
|
||
|
||
# 当前执行步骤:"已完成所有实施步骤"
|
||
|
||
# 任务进度
|
||
|
||
## [2025-10-28 17:18:21]
|
||
- 已修改:
|
||
- config.py - 添加gomoku配置
|
||
- utils/parser.py - 添加gomoku指令映射
|
||
- games/gomoku_logic.py - 创建五子棋逻辑模块(新文件)
|
||
- games/gomoku.py - 创建五子棋游戏类(新文件)
|
||
- routers/callback.py - 添加gomoku路由
|
||
- games/base.py - 更新帮助信息和统计信息
|
||
- 更改:完成五子棋游戏的完整实现,包括:
|
||
- 群级游戏池管理(支持多轮对战并存)
|
||
- 标准15x15棋盘
|
||
- 完整的禁手规则(三三、四四、长连)
|
||
- 坐标系统(A-O列,1-15行)
|
||
- emoji棋盘渲染(⚫⚪➕)
|
||
- 胜负判定
|
||
- 战绩统计
|
||
- 原因:实现用户需求的双人对战五子棋游戏
|
||
- 阻碍因素:用户识别和显示格式错误
|
||
- 状态:不成功
|
||
|
||
## [2025-10-28 17:36:07]
|
||
- 已修改:
|
||
- games/gomoku.py - 修复用户识别和显示格式
|
||
- 更改:
|
||
- 修复 `_parse_opponent()` 方法,使用正确的WPS @用户格式 `<at user_id="xxx"></at>` 进行解析
|
||
- 修改所有用户显示,从 `@用户{user_id}` 改为 `<at user_id="{user_id}"></at>`,以正确显示用户的群名称
|
||
- 涉及修改:开始游戏、落子、显示棋盘、认输、列出对战等所有用户显示位置
|
||
- 原因:修复用户识别失败和显示错误的问题
|
||
- 阻碍因素:用户识别仍然失败
|
||
- 状态:不成功
|
||
|
||
## [2025-10-28 17:42:24]
|
||
- 已修改:
|
||
- games/gomoku.py - 改进用户ID解析和添加调试日志
|
||
- routers/callback.py - 增强日志输出
|
||
- 更改:
|
||
- 改进 `_parse_opponent()` 方法,支持多种@用户格式(双引号、单引号、不同的标签格式)
|
||
- 在 `handle()` 方法中添加详细的调试日志(command, args, action, opponent_id)
|
||
- 改进错误提示,显示实际接收到的参数内容
|
||
- 将 callback.py 中的消息内容日志级别从 DEBUG 改为 INFO,便于追踪
|
||
- 原因:进一步诊断用户ID识别失败的问题,添加调试信息帮助定位问题
|
||
- 阻碍因素:WPS callback不提供被@用户的ID信息
|
||
- 状态:不成功
|
||
|
||
## [2025-10-28 17:55:00]
|
||
- 已修改:
|
||
- games/gomoku.py - 重构游戏发起机制,从@用户改为挑战-接受模式
|
||
- games/base.py - 更新全局帮助信息
|
||
- routers/callback.py - 添加完整callback数据日志
|
||
- 更改:
|
||
- **核心架构变更**:从"@用户发起对战"改为"挑战-接受"机制
|
||
- 新增 `_create_challenge()` 方法 - 用户发起挑战
|
||
- 新增 `_accept_challenge()` 方法 - 其他用户接受挑战
|
||
- 新增 `_cancel_challenge()` 方法 - 取消自己的挑战
|
||
- 删除 `_parse_opponent()` 方法(不再需要)
|
||
- 删除 `_start_game()` 方法(由新方法替代)
|
||
- 更新游戏池数据结构,添加 `challenges` 列表
|
||
- 更新所有帮助信息和错误提示
|
||
- 指令变更:
|
||
- `.gomoku challenge` / `.gomoku start` - 发起挑战
|
||
- `.gomoku accept` / `.gomoku join` - 接受挑战
|
||
- `.gomoku cancel` - 取消挑战
|
||
- 原因:WPS callback消息内容中@用户只是文本形式(如"@揭英飙"),不包含user_id,无法实现@用户发起对战
|
||
- 阻碍因素:无
|
||
- 状态:成功
|
||
|
||
## [2025-10-28 17:56:03]
|
||
- 已修改:
|
||
- games/gomoku_logic.py - 修复棋盘对齐问题
|
||
- 更改:
|
||
- 优化 `render_board()` 函数的格式化逻辑
|
||
- 列标题:每个字母后面加一个空格,确保与棋子列对齐
|
||
- 行号:调整前导空格,从 " {row_num} " 改为 "{row_num} "
|
||
- 棋子:每个emoji后面加一个空格,行尾去除多余空格
|
||
- 整体对齐:确保列标题、行号、棋子三者在Markdown代码块中正确对齐
|
||
- 原因:修复用户反馈的棋盘文本对齐问题
|
||
- 阻碍因素:无
|
||
- 状态:未确认
|
||
|
||
# 最终审查
|
||
(待完成后填写)
|
||
|