修改为发起/接受对局以避开at无法获取id的问题
This commit is contained in:
@@ -228,7 +228,29 @@ if game_type == 'gomoku':
|
||||
- 改进错误提示,显示实际接收到的参数内容
|
||||
- 将 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,无法实现@用户发起对战
|
||||
- 阻碍因素:无
|
||||
- 状态:未确认
|
||||
|
||||
# 最终审查
|
||||
|
||||
@@ -74,7 +74,8 @@ def get_help_message() -> str:
|
||||
- `.idiom blacklist` - 查看黑名单
|
||||
|
||||
### ⚫ 五子棋
|
||||
- `.gomoku @对手` - 发起对战
|
||||
- `.gomoku challenge` - 发起挑战
|
||||
- `.gomoku accept` - 接受挑战
|
||||
- `.gomoku A1` - 落子
|
||||
- `.gomoku show` - 显示棋盘
|
||||
- `.gomoku resign` - 认输
|
||||
|
||||
192
games/gomoku.py
192
games/gomoku.py
@@ -54,6 +54,18 @@ class GomokuGame(BaseGame):
|
||||
if action in ['help', '帮助']:
|
||||
return self.get_help()
|
||||
|
||||
# 发起挑战
|
||||
if action in ['challenge', 'start', '挑战', '开始']:
|
||||
return self._create_challenge(chat_id, user_id)
|
||||
|
||||
# 接受挑战
|
||||
if action in ['accept', 'join', '接受', '加入']:
|
||||
return self._accept_challenge(chat_id, user_id)
|
||||
|
||||
# 取消挑战
|
||||
if action in ['cancel', '取消']:
|
||||
return self._cancel_challenge(chat_id, user_id)
|
||||
|
||||
# 列出所有对战
|
||||
if action in ['list', '列表', '查看']:
|
||||
return self._list_games(chat_id)
|
||||
@@ -75,48 +87,14 @@ class GomokuGame(BaseGame):
|
||||
if coord is not None:
|
||||
return self._make_move(chat_id, user_id, action)
|
||||
|
||||
# 尝试解析为@对手(开始游戏)
|
||||
opponent_id = self._parse_opponent(args)
|
||||
logger.info(f"五子棋指令解析 - opponent_id: {opponent_id}")
|
||||
if opponent_id is not None:
|
||||
return self._start_game(chat_id, user_id, opponent_id)
|
||||
|
||||
# 未识别的指令
|
||||
logger.warning(f"五子棋未识别的指令 - args: {args}")
|
||||
return f"❌ 未识别的指令:{args}\n\n💡 提示:\n- 要开始游戏,请使用 `.gomoku` 然后@对手\n- 要落子,请使用 `.gomoku A1`(坐标格式)\n- 要查看帮助,请使用 `.gomoku help`"
|
||||
return f"❌ 未识别的指令:{args}\n\n💡 提示:\n- 发起挑战:`.gomoku challenge`\n- 接受挑战:`.gomoku accept`\n- 落子:`.gomoku A1`\n- 查看帮助:`.gomoku help`"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理五子棋指令错误: {e}", exc_info=True)
|
||||
return f"❌ 处理指令出错: {str(e)}"
|
||||
|
||||
def _parse_opponent(self, args: str) -> Optional[int]:
|
||||
"""解析@对手的用户ID
|
||||
|
||||
Args:
|
||||
args: 参数字符串
|
||||
|
||||
Returns:
|
||||
用户ID或None
|
||||
"""
|
||||
# WPS格式:<at user_id="123456"></at> 或其他变体
|
||||
# 尝试多种格式
|
||||
patterns = [
|
||||
r'<at\s+user_id="(\d+)"[^>]*>', # <at user_id="123456"> 或 <at user_id="123456"></at>
|
||||
r'<at\s+user_id=\'(\d+)\'[^>]*>', # <at user_id='123456'>
|
||||
r'user_id="(\d+)"', # 直接查找 user_id="xxx"
|
||||
r'user_id=\'(\d+)\'', # 直接查找 user_id='xxx'
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
match = re.search(pattern, args)
|
||||
if match:
|
||||
try:
|
||||
return int(match.group(1))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _get_game_pool(self, chat_id: int) -> Dict[str, Any]:
|
||||
"""获取游戏池
|
||||
|
||||
@@ -163,56 +141,93 @@ class GomokuGame(BaseGame):
|
||||
|
||||
return None
|
||||
|
||||
def _start_game(self, chat_id: int, user_id: int, opponent_id: int) -> str:
|
||||
"""开始新游戏
|
||||
def _create_challenge(self, chat_id: int, user_id: int) -> str:
|
||||
"""创建挑战
|
||||
|
||||
Args:
|
||||
chat_id: 会话ID
|
||||
user_id: 发起者ID
|
||||
opponent_id: 对手ID
|
||||
|
||||
Returns:
|
||||
提示消息
|
||||
"""
|
||||
# 检查是否与自己对战
|
||||
if user_id == opponent_id:
|
||||
return "❌ 不能和自己下棋哦!"
|
||||
|
||||
# 获取游戏池
|
||||
pool = self._get_game_pool(chat_id)
|
||||
games = pool.get("games", [])
|
||||
challenges = pool.get("challenges", [])
|
||||
|
||||
# 检查用户是否已经在对战中
|
||||
user_game = self._find_user_game(chat_id, user_id)
|
||||
if user_game:
|
||||
return "⚠️ 你已经在对战中!\n\n输入 `.gomoku show` 查看棋盘"
|
||||
|
||||
# 检查用户是否已经发起了挑战
|
||||
for challenge in challenges:
|
||||
if challenge["challenger_id"] == user_id:
|
||||
return "⚠️ 你已经发起了一个挑战!\n\n等待其他人接受,或输入 `.gomoku cancel` 取消挑战"
|
||||
|
||||
# 创建挑战
|
||||
current_time = int(time.time())
|
||||
challenge = {
|
||||
"challenger_id": user_id,
|
||||
"created_at": current_time
|
||||
}
|
||||
|
||||
challenges.append(challenge)
|
||||
pool["challenges"] = challenges
|
||||
self._save_game_pool(chat_id, pool)
|
||||
|
||||
text = f"## 🎯 五子棋挑战\n\n"
|
||||
text += f"<at user_id=\"{user_id}\"></at> 发起了五子棋挑战!\n\n"
|
||||
text += f"💡 想要应战吗?输入 `.gomoku accept` 接受挑战"
|
||||
|
||||
return text
|
||||
|
||||
def _accept_challenge(self, chat_id: int, user_id: int) -> str:
|
||||
"""接受挑战
|
||||
|
||||
Args:
|
||||
chat_id: 会话ID
|
||||
user_id: 接受者ID
|
||||
|
||||
Returns:
|
||||
提示消息
|
||||
"""
|
||||
# 获取游戏池
|
||||
pool = self._get_game_pool(chat_id)
|
||||
games = pool.get("games", [])
|
||||
challenges = pool.get("challenges", [])
|
||||
|
||||
if not challenges:
|
||||
return "⚠️ 当前没有挑战可以接受\n\n输入 `.gomoku challenge` 发起挑战"
|
||||
|
||||
# 检查用户是否已经在对战中
|
||||
user_game = self._find_user_game(chat_id, user_id)
|
||||
if user_game:
|
||||
return "⚠️ 你已经在对战中!\n\n输入 `.gomoku show` 查看棋盘"
|
||||
|
||||
# 获取最新的挑战
|
||||
challenge = challenges[-1]
|
||||
challenger_id = challenge["challenger_id"]
|
||||
|
||||
# 不能接受自己的挑战
|
||||
if challenger_id == user_id:
|
||||
return "❌ 不能接受自己的挑战!"
|
||||
|
||||
# 检查是否已达到最大并发数
|
||||
active_games = [g for g in games if g["status"] == "playing"]
|
||||
if len(active_games) >= self.max_concurrent_games:
|
||||
return f"⚠️ 当前聊天已有 {len(active_games)} 局对战,已达到最大并发数限制"
|
||||
|
||||
# 检查这两个用户是否已经在对战
|
||||
for game in active_games:
|
||||
players = {game["player_black"], game["player_white"]}
|
||||
if user_id in players and opponent_id in players:
|
||||
return "⚠️ 你们已经有一局正在进行的对战了!\n\n输入 `.gomoku show` 查看棋盘"
|
||||
|
||||
# 检查用户是否已经在其他对战中
|
||||
user_game = self._find_user_game(chat_id, user_id)
|
||||
if user_game:
|
||||
opponent = user_game["player_white"] if user_game["player_black"] == user_id else user_game["player_black"]
|
||||
return f"⚠️ 你已经在与 <at user_id=\"{opponent}\"></at> 对战中!\n\n输入 `.gomoku show` 查看棋盘"
|
||||
|
||||
opponent_game = self._find_user_game(chat_id, opponent_id)
|
||||
if opponent_game:
|
||||
other = opponent_game["player_white"] if opponent_game["player_black"] == opponent_id else opponent_game["player_black"]
|
||||
return f"⚠️ 对手已经在与 <at user_id=\"{other}\"></at> 对战中!"
|
||||
|
||||
# 创建新游戏
|
||||
# 创建游戏
|
||||
current_time = int(time.time())
|
||||
game_id = f"p{user_id}_p{opponent_id}_{current_time}"
|
||||
game_id = f"p{challenger_id}_p{user_id}_{current_time}"
|
||||
|
||||
new_game = {
|
||||
"game_id": game_id,
|
||||
"player_black": user_id, # 发起者执黑(先手)
|
||||
"player_white": opponent_id, # 对手执白(后手)
|
||||
"current_player": user_id, # 黑方先手
|
||||
"player_black": challenger_id, # 挑战者执黑(先手)
|
||||
"player_white": user_id, # 接受者执白(后手)
|
||||
"current_player": challenger_id, # 黑方先手
|
||||
"board": logic.create_empty_board(),
|
||||
"status": "playing",
|
||||
"winner": None,
|
||||
@@ -223,13 +238,18 @@ class GomokuGame(BaseGame):
|
||||
}
|
||||
|
||||
games.append(new_game)
|
||||
|
||||
# 移除已接受的挑战
|
||||
challenges.remove(challenge)
|
||||
|
||||
pool["games"] = games
|
||||
pool["challenges"] = challenges
|
||||
self._save_game_pool(chat_id, pool)
|
||||
|
||||
text = f"## ⚫ 五子棋对战开始!\n\n"
|
||||
text += f"**黑方(先手)**:<at user_id=\"{user_id}\"></at> ⚫\n\n"
|
||||
text += f"**白方(后手)**:<at user_id=\"{opponent_id}\"></at> ⚪\n\n"
|
||||
text += f"**轮到**:<at user_id=\"{user_id}\"></at> ⚫\n\n"
|
||||
text += f"**黑方(先手)**:<at user_id=\"{challenger_id}\"></at> ⚫\n\n"
|
||||
text += f"**白方(后手)**:<at user_id=\"{user_id}\"></at> ⚪\n\n"
|
||||
text += f"**轮到**:<at user_id=\"{challenger_id}\"></at> ⚫\n\n"
|
||||
text += "💡 提示:\n"
|
||||
text += "- 黑方有禁手规则(三三、四四、长连禁手)\n"
|
||||
text += "- 输入 `.gomoku A1` 在A1位置落子\n"
|
||||
@@ -237,6 +257,37 @@ class GomokuGame(BaseGame):
|
||||
|
||||
return text
|
||||
|
||||
def _cancel_challenge(self, chat_id: int, user_id: int) -> str:
|
||||
"""取消挑战
|
||||
|
||||
Args:
|
||||
chat_id: 会话ID
|
||||
user_id: 用户ID
|
||||
|
||||
Returns:
|
||||
提示消息
|
||||
"""
|
||||
# 获取游戏池
|
||||
pool = self._get_game_pool(chat_id)
|
||||
challenges = pool.get("challenges", [])
|
||||
|
||||
# 查找用户的挑战
|
||||
user_challenge = None
|
||||
for challenge in challenges:
|
||||
if challenge["challenger_id"] == user_id:
|
||||
user_challenge = challenge
|
||||
break
|
||||
|
||||
if not user_challenge:
|
||||
return "⚠️ 你没有发起挑战"
|
||||
|
||||
# 移除挑战
|
||||
challenges.remove(user_challenge)
|
||||
pool["challenges"] = challenges
|
||||
self._save_game_pool(chat_id, pool)
|
||||
|
||||
return "✅ 已取消挑战"
|
||||
|
||||
def _make_move(self, chat_id: int, user_id: int, coord: str) -> str:
|
||||
"""落子
|
||||
|
||||
@@ -477,12 +528,14 @@ class GomokuGame(BaseGame):
|
||||
return """## ⚫ 五子棋
|
||||
|
||||
### 基础用法
|
||||
- `.gomoku @对手` - 向对手发起对战
|
||||
- `.gomoku challenge` - 发起挑战
|
||||
- `.gomoku accept` - 接受挑战
|
||||
- `.gomoku A1` - 在A1位置落子
|
||||
- `.gomoku show` - 显示当前棋盘
|
||||
- `.gomoku resign` - 认输
|
||||
|
||||
### 其他指令
|
||||
- `.gomoku cancel` - 取消自己的挑战
|
||||
- `.gomoku list` - 列出所有进行中的对战
|
||||
- `.gomoku stats` - 查看个人战绩
|
||||
|
||||
@@ -502,7 +555,8 @@ class GomokuGame(BaseGame):
|
||||
|
||||
### 示例
|
||||
```
|
||||
.gomoku @123456 # 向用户123456发起对战
|
||||
.gomoku challenge # 发起挑战
|
||||
.gomoku accept # 接受挑战
|
||||
.gomoku H8 # 在中心位置落子
|
||||
.gomoku show # 查看棋盘
|
||||
.gomoku resign # 认输
|
||||
|
||||
@@ -29,6 +29,7 @@ async def callback_receive(request: Request):
|
||||
data = await request.json()
|
||||
logger.info(f"收到消息: chatid={data.get('chatid')}, creator={data.get('creator')}")
|
||||
logger.info(f"消息内容: {data.get('content')}")
|
||||
logger.info(f"完整callback数据: {data}")
|
||||
|
||||
# 验证请求
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user