Files
WPSBot/.tasks/2025-10-28_1_gomoku.md

9.7 KiB
Raw Permalink Blame History

背景

文件名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)作为唯一键
  • 五子棋需要双人对战,需要同时记录两个玩家
  • 需要设计状态数据结构,存储:
    • 对战双方IDplayer1_id, player2_id
    • 当前轮到谁current_player_id
    • 棋盘状态15x15二维数组
    • 游戏状态waiting, playing, finished
    • 胜者IDwinner_id如果有

2. 多轮对战并发

  • 允许同一个chat中有多轮对战只要对战双方不同
  • 需要一个机制来标识不同的对战局可以用对战双方ID的组合
  • 状态查询需要能够找到特定用户参与的对战

3. 禁手规则实现

禁手规则(仅对黑方,即先手玩家):

  • 三三禁手:一手棋同时形成两个或以上的活三
  • 四四禁手:一手棋同时形成两个或以上的活四或冲四
  • 长连禁手:一手棋形成六子或以上的连珠

需要实现:

  • 判断某个位置的四个方向(横、竖、左斜、右斜)的连珠情况
  • 判断活三、活四、冲四的定义
  • 在落子时检查是否触发禁手

4. 坐标系统

  • A-O15列
  • 1-1515行
  • 需要坐标转换函数: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结构

{
    "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.pyhandle_command()函数中添加:

if game_type == 'gomoku':
    from games.gomoku import GomokuGame
    game = GomokuGame()
    return await game.handle(command, chat_id, user_id)

6. 指令解析

utils/parser.pyCommandParser类中添加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代码块中正确对齐
  • 原因:修复用户反馈的棋盘文本对齐问题
  • 阻碍因素:无
  • 状态:未确认

最终审查

(待完成后填写)