Files
WPSBot/games/rps.py

194 lines
5.7 KiB
Python
Raw Normal View History

2025-10-28 13:00:35 +08:00
"""石头剪刀布游戏"""
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` - 查看战绩
### 支持的输入
- 中文石头剪刀
- 英文rockscissorspaper
- 表情🪨 📄
### 示例
```
.rps 石头
.rps rock
.rps 🪨
```
"""