Files
WPSBot/games/rps.py
2025-10-28 13:00:35 +08:00

194 lines
5.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""石头剪刀布游戏"""
import random
import logging
from games.base import BaseGame
from utils.parser import CommandParser
logger = logging.getLogger(__name__)
class RPSGame(BaseGame):
"""石头剪刀布游戏"""
# 选择列表
CHOICES = ["石头", "剪刀", ""]
# 胜负关系key 击败 value
WINS_AGAINST = {
"石头": "剪刀",
"剪刀": "",
"": "石头"
}
# 英文/表情符号映射
CHOICE_MAP = {
"石头": "石头", "rock": "石头", "🪨": "石头", "👊": "石头",
"剪刀": "剪刀", "scissors": "剪刀", "✂️": "剪刀", "✌️": "剪刀",
"": "", "paper": "", "📄": "", "": ""
}
async def handle(self, command: str, chat_id: int, user_id: int) -> str:
"""处理石头剪刀布指令
Args:
command: 指令,如 ".rps 石头"".rps stats"
chat_id: 会话ID
user_id: 用户ID
Returns:
回复消息
"""
try:
# 提取参数
_, args = CommandParser.extract_command_args(command)
args = args.strip()
# 查看战绩
if args in ['stats', '战绩', '统计']:
return self._get_stats(user_id)
# 没有参数,显示帮助
if not args:
return self.get_help()
# 解析用户选择
player_choice = self._parse_choice(args)
if not player_choice:
return f"❌ 无效的选择:{args}\n\n{self.get_help()}"
# 机器人随机选择
bot_choice = random.choice(self.CHOICES)
# 判定胜负
result = self._judge(player_choice, bot_choice)
# 更新统计
if result == 'win':
self.db.update_game_stats(user_id, 'rps', win=True)
elif result == 'loss':
self.db.update_game_stats(user_id, 'rps', loss=True)
elif result == 'draw':
self.db.update_game_stats(user_id, 'rps', draw=True)
# 格式化输出
return self._format_result(player_choice, bot_choice, result)
except Exception as e:
logger.error(f"处理石头剪刀布指令错误: {e}", exc_info=True)
return f"❌ 处理指令出错: {str(e)}"
def _parse_choice(self, choice_str: str) -> str:
"""解析用户选择
Args:
choice_str: 用户输入的选择
Returns:
标准化的选择(石头/剪刀/布)或空字符串
"""
choice_str = choice_str.lower().strip()
return self.CHOICE_MAP.get(choice_str, "")
def _judge(self, player: str, bot: str) -> str:
"""判定胜负
Args:
player: 玩家选择
bot: 机器人选择
Returns:
'win', 'loss', 或 'draw'
"""
if player == bot:
return 'draw'
elif self.WINS_AGAINST[player] == bot:
return 'win'
else:
return 'loss'
def _format_result(self, player_choice: str, bot_choice: str, result: str) -> str:
"""格式化游戏结果
Args:
player_choice: 玩家选择
bot_choice: 机器人选择
result: 游戏结果
Returns:
格式化的Markdown消息
"""
# 表情符号映射
emoji_map = {
"石头": "🪨",
"剪刀": "✂️",
"": "📄"
}
text = f"## ✊ 石头剪刀布\n\n"
text += f"**你出**{emoji_map[player_choice]} {player_choice}\n\n"
text += f"**我出**{emoji_map[bot_choice]} {bot_choice}\n\n"
if result == 'win':
text += "**结果**<font color='#4CAF50'>🎉 你赢了!</font>\n"
elif result == 'loss':
text += "**结果**<font color='#F44336'>😢 你输了!</font>\n"
else:
text += "**结果**<font color='#FFC107'>🤝 平局!</font>\n"
return text
def _get_stats(self, user_id: int) -> str:
"""获取用户战绩
Args:
user_id: 用户ID
Returns:
战绩信息
"""
stats = self.db.get_game_stats(user_id, 'rps')
total = stats['total_plays']
if total == 0:
return "📊 你还没有玩过石头剪刀布呢~\n\n快来试试吧!输入 `.rps 石头/剪刀/布` 开始游戏"
wins = stats['wins']
losses = stats['losses']
draws = stats['draws']
win_rate = (wins / total * 100) if total > 0 else 0
text = f"## 📊 石头剪刀布战绩\n\n"
text += f"**总局数**{total}\n\n"
text += f"**胜利**{wins} 次 🎉\n\n"
text += f"**失败**{losses} 次 😢\n\n"
text += f"**平局**{draws} 次 🤝\n\n"
text += f"**胜率**<font color='#4CAF50'>{win_rate:.1f}%</font>\n"
return text
def get_help(self) -> str:
"""获取帮助信息"""
return """## ✊ 石头剪刀布
### 基础用法
- `.rps 石头` - 出石头
- `.rps 剪刀` - 出剪刀
- `.rps 布` - 出布
### 其他指令
- `.rps stats` - 查看战绩
### 支持的输入
- 中文:石头、剪刀、布
- 英文rock、scissors、paper
- 表情:🪨 ✂️ 📄
### 示例
```
.rps 石头
.rps rock
.rps 🪨
```
"""