241 lines
7.8 KiB
Python
241 lines
7.8 KiB
Python
"""猜数字游戏"""
|
||
import random
|
||
import logging
|
||
import time
|
||
from games.base import BaseGame
|
||
from utils.parser import CommandParser
|
||
from config import GAME_CONFIG
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class GuessGame(BaseGame):
|
||
"""猜数字游戏"""
|
||
|
||
def __init__(self):
|
||
"""初始化游戏"""
|
||
super().__init__()
|
||
self.config = GAME_CONFIG.get('guess', {})
|
||
self.min_number = self.config.get('min_number', 1)
|
||
self.max_number = self.config.get('max_number', 100)
|
||
self.max_attempts = self.config.get('max_attempts', 10)
|
||
|
||
async def handle(self, command: str, chat_id: int, user_id: int) -> str:
|
||
"""处理猜数字指令
|
||
|
||
Args:
|
||
command: 指令,如 ".guess start" 或 ".guess 50"
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
回复消息
|
||
"""
|
||
try:
|
||
# 提取参数
|
||
_, args = CommandParser.extract_command_args(command)
|
||
args = args.strip().lower()
|
||
|
||
# 开始游戏
|
||
if args in ['start', '开始']:
|
||
return self._start_game(chat_id, user_id)
|
||
|
||
# 结束游戏
|
||
if args in ['stop', '结束', 'end']:
|
||
return self._stop_game(chat_id, user_id)
|
||
|
||
# 尝试解析为数字
|
||
try:
|
||
guess = int(args)
|
||
return self._make_guess(chat_id, user_id, guess)
|
||
except ValueError:
|
||
return self.get_help()
|
||
|
||
except Exception as e:
|
||
logger.error(f"处理猜数字指令错误: {e}", exc_info=True)
|
||
return f"❌ 处理指令出错: {str(e)}"
|
||
|
||
def _start_game(self, chat_id: int, user_id: int) -> str:
|
||
"""开始新游戏
|
||
|
||
Args:
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
提示消息
|
||
"""
|
||
# 检查是否已有进行中的游戏
|
||
state = self.db.get_game_state(chat_id, user_id, 'guess')
|
||
if state:
|
||
state_data = state['state_data']
|
||
attempts = state_data.get('attempts', 0)
|
||
return f"⚠️ 你已经有一个进行中的游戏了!\n\n" \
|
||
f"已经猜了 {attempts} 次,继续猜测或输入 `.guess stop` 结束游戏"
|
||
|
||
# 生成随机数
|
||
target = random.randint(self.min_number, self.max_number)
|
||
|
||
# 保存游戏状态
|
||
state_data = {
|
||
'target': target,
|
||
'attempts': 0,
|
||
'guesses': [],
|
||
'max_attempts': self.max_attempts
|
||
}
|
||
self.db.save_game_state(chat_id, user_id, 'guess', state_data)
|
||
|
||
text = f"## 🔢 猜数字游戏开始!\n\n"
|
||
text += f"我想了一个 **{self.min_number}** 到 **{self.max_number}** 之间的数字\n\n"
|
||
text += f"你有 **{self.max_attempts}** 次机会猜对它\n\n"
|
||
text += f"输入 `.guess 数字` 开始猜测\n\n"
|
||
text += f"输入 `.guess stop` 结束游戏"
|
||
|
||
return text
|
||
|
||
def _make_guess(self, chat_id: int, user_id: int, guess: int) -> str:
|
||
"""进行猜测
|
||
|
||
Args:
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
guess: 猜测的数字
|
||
|
||
Returns:
|
||
结果消息
|
||
"""
|
||
# 检查游戏状态
|
||
state = self.db.get_game_state(chat_id, user_id, 'guess')
|
||
if not state:
|
||
return f"⚠️ 还没有开始游戏呢!\n\n输入 `.guess start` 开始游戏"
|
||
|
||
state_data = state['state_data']
|
||
target = state_data['target']
|
||
attempts = state_data['attempts']
|
||
guesses = state_data['guesses']
|
||
max_attempts = state_data['max_attempts']
|
||
|
||
# 检查数字范围
|
||
if guess < self.min_number or guess > self.max_number:
|
||
return f"❌ 请输入 {self.min_number} 到 {self.max_number} 之间的数字"
|
||
|
||
# 检查是否已经猜过
|
||
if guess in guesses:
|
||
return f"⚠️ 你已经猜过 {guess} 了!\n\n已猜过:{', '.join(map(str, sorted(guesses)))}"
|
||
|
||
# 更新状态
|
||
attempts += 1
|
||
guesses.append(guess)
|
||
|
||
# 判断结果
|
||
if guess == target:
|
||
# 猜对了!
|
||
self.db.delete_game_state(chat_id, user_id, 'guess')
|
||
self.db.update_game_stats(user_id, 'guess', win=True)
|
||
|
||
text = f"## 🎉 恭喜猜对了!\n\n"
|
||
text += f"**答案**:<font color='#4CAF50'>{target}</font>\n\n"
|
||
text += f"**用了**:{attempts} 次\n\n"
|
||
|
||
if attempts == 1:
|
||
text += "太神了!一次就猜中!🎯"
|
||
elif attempts <= 3:
|
||
text += "真厉害!运气爆棚!✨"
|
||
elif attempts <= 6:
|
||
text += "不错哦!🌟"
|
||
else:
|
||
text += "虽然用了不少次,但最终还是猜对了!💪"
|
||
|
||
return text
|
||
|
||
# 没猜对
|
||
if attempts >= max_attempts:
|
||
# 次数用完了
|
||
self.db.delete_game_state(chat_id, user_id, 'guess')
|
||
self.db.update_game_stats(user_id, 'guess', loss=True)
|
||
|
||
text = f"## 😢 游戏结束\n\n"
|
||
text += f"很遗憾,次数用完了\n\n"
|
||
text += f"**答案是**:<font color='#F44336'>{target}</font>\n\n"
|
||
text += f"下次再来挑战吧!"
|
||
|
||
return text
|
||
|
||
# 继续猜
|
||
state_data['attempts'] = attempts
|
||
state_data['guesses'] = guesses
|
||
self.db.save_game_state(chat_id, user_id, 'guess', state_data)
|
||
|
||
# 提示大小
|
||
hint = "太大了 📉" if guess > target else "太小了 📈"
|
||
remaining = max_attempts - attempts
|
||
|
||
text = f"## ❌ {hint}\n\n"
|
||
text += f"**第 {attempts} 次猜测**:{guess}\n\n"
|
||
text += f"**剩余机会**:{remaining} 次\n\n"
|
||
|
||
# 给一些范围提示
|
||
smaller_guesses = [g for g in guesses if g < target]
|
||
larger_guesses = [g for g in guesses if g > target]
|
||
|
||
if smaller_guesses and larger_guesses:
|
||
min_larger = min(larger_guesses)
|
||
max_smaller = max(smaller_guesses)
|
||
text += f"💡 提示:答案在 **{max_smaller}** 和 **{min_larger}** 之间\n\n"
|
||
|
||
text += f"已猜过:{', '.join(map(str, sorted(guesses)))}"
|
||
|
||
return text
|
||
|
||
def _stop_game(self, chat_id: int, user_id: int) -> str:
|
||
"""结束游戏
|
||
|
||
Args:
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
提示消息
|
||
"""
|
||
state = self.db.get_game_state(chat_id, user_id, 'guess')
|
||
if not state:
|
||
return "⚠️ 当前没有进行中的游戏"
|
||
|
||
state_data = state['state_data']
|
||
target = state_data['target']
|
||
attempts = state_data['attempts']
|
||
|
||
self.db.delete_game_state(chat_id, user_id, 'guess')
|
||
|
||
text = f"## 🔢 游戏已结束\n\n"
|
||
text += f"**答案是**:{target}\n\n"
|
||
text += f"你猜了 {attempts} 次\n\n"
|
||
text += "下次再来挑战吧!"
|
||
|
||
return text
|
||
|
||
def get_help(self) -> str:
|
||
"""获取帮助信息"""
|
||
return f"""## 🔢 猜数字游戏
|
||
|
||
### 基础用法
|
||
- `.guess start` - 开始游戏
|
||
- `.guess 数字` - 猜测数字
|
||
- `.guess stop` - 结束游戏
|
||
|
||
### 游戏规则
|
||
- 范围:{self.min_number} - {self.max_number}
|
||
- 机会:{self.max_attempts} 次
|
||
- 每次猜测后会提示"太大"或"太小"
|
||
- 猜对即可获胜
|
||
|
||
### 示例
|
||
```
|
||
.guess start # 开始游戏
|
||
.guess 50 # 猜50
|
||
.guess 75 # 猜75
|
||
.guess stop # 放弃游戏
|
||
```
|
||
"""
|
||
|