194 lines
5.7 KiB
Python
194 lines
5.7 KiB
Python
"""石头剪刀布游戏"""
|
||
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 🪨
|
||
```
|
||
"""
|
||
|