8.3 KiB
8.3 KiB
背景
文件名:2025-10-28_1_add-idiom-chain-game.md 创建于:2025-10-28_15:43:00 创建者:admin 主分支:main 任务分支:task/add-idiom-chain-game_2025-10-28_1 Yolo模式:Off
任务描述
在WPS Bot Game项目中新增一个成语接龙游戏功能。
核心需求
- 群内多人游戏,机器人作为裁判和出题者
- 允许按拼音接龙(包括谐音接龙)
- 没有时间限制
- 不需要提示功能
- 游戏记录保存到.stats统计中
- 不允许重复使用成语
- 不需要难度分级(非人机对战)
- 需要裁判指令用于接受/拒绝玩家回答
游戏玩法
- 机器人出题(给出起始成语)
- 群内玩家轮流接龙
- 机器人判断接龙是否有效(拼音/谐音匹配、未重复使用)
- 裁判可以手动接受或拒绝某个回答
- 记录每个玩家的成功接龙次数
项目概览
项目结构
WPSBotGame/
├── app.py # FastAPI主应用
├── config.py # 配置管理
├── core/
│ ├── database.py # SQLite数据库操作
│ ├── middleware.py # 中间件
│ └── models.py # 数据模型
├── games/ # 游戏模块
│ ├── base.py # 游戏基类
│ ├── dice.py # 骰娘游戏
│ ├── rps.py # 石头剪刀布
│ ├── fortune.py # 运势占卜
│ ├── guess.py # 猜数字
│ └── quiz.py # 问答游戏
├── data/ # 数据文件
│ ├── bot.db # SQLite数据库
│ ├── quiz.json # 问答题库
│ └── fortunes.json # 运势数据
├── routers/ # 路由处理
│ ├── callback.py # WPS回调处理
│ └── health.py # 健康检查
└── utils/ # 工具模块
├── message.py # 消息发送
├── parser.py # 指令解析
└── rate_limit.py # 限流控制
技术栈
- FastAPI:Web框架
- SQLite:数据存储
- WPS协作机器人API:消息接收与发送
现有游戏架构
- 所有游戏继承
BaseGame基类 - 必须实现
handle(command, chat_id, user_id)方法处理指令 - 必须实现
get_help()方法返回帮助信息 - 游戏状态存储在数据库
game_states表:(chat_id, user_id, game_type)作为联合主键 - 游戏统计存储在
game_stats表:记录wins,losses,draws,total_plays - 指令通过
CommandParser解析,在callback.py中分发到对应游戏处理器
数据库设计
game_states表
- chat_id: 会话ID
- user_id: 用户ID
- game_type: 游戏类型
- state_data: JSON格式的游戏状态数据
- created_at/updated_at: 时间戳
game_stats表
- user_id: 用户ID
- game_type: 游戏类型
- wins/losses/draws/total_plays: 统计数据
分析
关键技术挑战
1. 群级别vs个人级别状态管理
现有游戏(猜数字、问答)都是个人独立状态,使用(chat_id, user_id, game_type)作为主键。
成语接龙是群内共享游戏,需要:
- 群级别的游戏状态:当前成语、已用成语列表、接龙长度、当前轮到谁
- 个人级别的统计:每个玩家的成功接龙次数
可能方案:
- 使用特殊user_id(如0或-1)存储群级别游戏状态
- 或者在state_data中存储所有玩家信息
2. 成语词库准备
需要准备:
- 成语列表(至少500-1000个常用成语)
- 每个成语的拼音信息(用于判断接龙是否匹配)
- 数据格式:JSON文件,类似quiz.json
3. 拼音匹配逻辑
- 需要拼音库支持(pypinyin)
- 支持谐音匹配(声母韵母匹配)
- 处理多音字情况
4. 裁判指令设计
需要额外指令:
.idiom accept- 接受上一个回答.idiom reject- 拒绝上一个回答- 需要权限控制(谁可以当裁判?)
5. 游戏流程设计
1. 开始游戏:.idiom start
- 机器人随机给出起始成语
- 创建群级别游戏状态
2. 玩家接龙:.idiom [成语]
- 检查是否在词库中
- 检查拼音是否匹配(首字拼音 == 上一个成语尾字拼音)
- 检查是否已使用过
- 自动判断或等待裁判确认
3. 裁判操作:.idiom accept/reject
- 手动接受或拒绝最近的回答
4. 查看状态:.idiom status
- 显示当前成语、已用成语数量、参与人数
5. 结束游戏:.idiom stop
- 显示统计信息
- 更新每个玩家的game_stats
现有代码分析
CommandParser (utils/parser.py)
需要添加成语接龙指令映射:
'.idiom': 'idiom',
'.成语接龙': 'idiom',
callback.py (routers/callback.py)
需要在handle_command函数中添加idiom游戏分支:
if game_type == 'idiom':
from games.idiom import IdiomGame
game = IdiomGame()
return await game.handle(command, chat_id, user_id)
base.py (games/base.py)
需要更新get_help_message()和get_stats_message(),添加成语接龙信息。
config.py
可能需要添加成语接龙相关配置:
"idiom": {
"auto_judge": True, # 是否自动判断
"require_approval": False, # 是否需要裁判确认
}
提议的解决方案
(待INNOVATE模式填写)
当前执行步骤:"1. 创建任务文件"
任务进度
[2025-10-28 15:45:00]
- 已修改:requirements.txt, config.py, utils/parser.py, routers/callback.py, games/base.py
- 已创建:games/idiom.py
- 更改:
- 在requirements.txt中添加pypinyin==0.51.0依赖
- 在config.py的GAME_CONFIG中添加idiom配置(起始成语池、历史显示数量)
- 在utils/parser.py的COMMAND_MAP中添加.idiom、.成语接龙、.成语指令映射
- 创建games/idiom.py实现完整的成语接龙游戏逻辑:
- IdiomGame类继承BaseGame
- 实现handle()主指令分发方法
- 实现_start_game()开始游戏
- 实现_make_chain()玩家接龙
- 实现_set_next_user()指定下一位
- 实现_reject_idiom()裁判拒绝
- 实现_show_status()显示状态
- 实现_show_blacklist()显示黑名单
- 实现_stop_game()结束游戏
- 实现_get_pinyin()获取拼音(支持多音字)
- 实现_check_pinyin_match()检查拼音匹配(忽略声调)
- 实现_parse_mentioned_user()解析@用户
- 实现_can_answer()权限检查(防连续、指定轮次)
- 实现_validate_idiom()词语验证(4字、拼音匹配、未使用、未黑名单)
- 实现get_help()帮助信息
- 在routers/callback.py的handle_command()中添加idiom游戏分支
- 在games/base.py的get_help_message()中添加成语接龙帮助信息
- 在games/base.py的get_stats_message()的game_names字典中添加idiom映射
- 原因:实现成语接龙游戏功能的所有核心代码
- 阻碍因素:无
- 状态:未确认
[2025-10-28 15:50:00]
- 已修改:games/base.py
- 更改:在get_help_message()的成语接龙部分添加黑名单相关指令说明
- 添加
.idiom reject [词语]- 拒绝词语加入黑名单(仅发起人) - 添加
.idiom blacklist- 查看黑名单
- 添加
- 原因:用户反馈.help帮助信息中看不到黑名单机制的使用说明
- 阻碍因素:无
- 状态:未确认
[2025-10-28 15:55:00]
- 已修改:games/idiom.py
- 已创建:data/idiom_blacklist.json
- 更改:将黑名单机制从游戏状态改为全局永久存储
- 创建data/idiom_blacklist.json作为全局黑名单数据文件
- 在IdiomGame.init()中添加黑名单文件路径和懒加载变量
- 添加_load_blacklist()方法从文件懒加载全局黑名单
- 添加_save_blacklist()方法保存黑名单到文件
- 修改_validate_idiom()方法检查全局黑名单而非游戏状态中的黑名单
- 修改_start_game()方法移除state_data中的blacklist字段初始化
- 修改_reject_idiom()方法将词语添加到全局黑名单并保存到文件
- 修改_show_blacklist()方法显示全局黑名单,不再依赖游戏状态
- 更新所有提示信息,明确说明是"永久禁用"
- 原因:用户要求被拒绝的词语应该永久不可用,而不是仅本局游戏不可用
- 阻碍因素:无
- 状态:未确认
最终审查
(待REVIEW模式完成后填写)