245 lines
7.7 KiB
Python
245 lines
7.7 KiB
Python
"""问答游戏"""
|
||
import json
|
||
import random
|
||
import logging
|
||
from pathlib import Path
|
||
from games.base import BaseGame
|
||
from utils.parser import CommandParser
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class QuizGame(BaseGame):
|
||
"""问答游戏"""
|
||
|
||
def __init__(self):
|
||
"""初始化游戏"""
|
||
super().__init__()
|
||
self._questions = None
|
||
|
||
def _load_questions(self):
|
||
"""懒加载题库"""
|
||
if self._questions is None:
|
||
try:
|
||
data_file = Path(__file__).parent.parent / "data" / "quiz.json"
|
||
with open(data_file, 'r', encoding='utf-8') as f:
|
||
data = json.load(f)
|
||
self._questions = data.get('questions', [])
|
||
logger.info(f"题库加载完成,共 {len(self._questions)} 道题")
|
||
except Exception as e:
|
||
logger.error(f"加载题库失败: {e}")
|
||
self._questions = []
|
||
|
||
async def handle(self, command: str, chat_id: int, user_id: int) -> str:
|
||
"""处理问答指令
|
||
|
||
Args:
|
||
command: 指令,如 ".quiz" 或 ".quiz 答案"
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
回复消息
|
||
"""
|
||
try:
|
||
# 加载题库
|
||
self._load_questions()
|
||
|
||
if not self._questions:
|
||
return "❌ 题库加载失败"
|
||
|
||
# 提取参数
|
||
_, args = CommandParser.extract_command_args(command)
|
||
args = args.strip()
|
||
|
||
# 检查是否有进行中的题目
|
||
state = self.db.get_game_state(chat_id, user_id, 'quiz')
|
||
|
||
if not args:
|
||
# 没有参数,出新题或显示当前题
|
||
if state:
|
||
# 显示当前题目
|
||
state_data = state['state_data']
|
||
return self._show_current_question(state_data)
|
||
else:
|
||
# 出新题
|
||
return self._new_question(chat_id, user_id)
|
||
else:
|
||
# 有参数,检查答案
|
||
if state:
|
||
return self._check_answer(chat_id, user_id, args)
|
||
else:
|
||
# 没有进行中的题目
|
||
return "⚠️ 当前没有题目,输入 `.quiz` 获取新题目"
|
||
|
||
except Exception as e:
|
||
logger.error(f"处理问答指令错误: {e}", exc_info=True)
|
||
return f"❌ 处理指令出错: {str(e)}"
|
||
|
||
def _new_question(self, chat_id: int, user_id: int) -> str:
|
||
"""出新题目
|
||
|
||
Args:
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
题目信息
|
||
"""
|
||
# 随机选择一道题
|
||
question = random.choice(self._questions)
|
||
|
||
# 保存游戏状态
|
||
state_data = {
|
||
'question_id': question['id'],
|
||
'question': question['question'],
|
||
'answer': question['answer'],
|
||
'keywords': question['keywords'],
|
||
'hint': question.get('hint', ''),
|
||
'category': question.get('category', ''),
|
||
'attempts': 0,
|
||
'max_attempts': 3
|
||
}
|
||
self.db.save_game_state(chat_id, user_id, 'quiz', state_data)
|
||
|
||
# 格式化输出
|
||
text = f"## 📝 问答题\n\n"
|
||
text += f"**分类**:{question.get('category', '未分类')}\n\n"
|
||
text += f"**问题**:{question['question']}\n\n"
|
||
text += f"💡 你有 **3** 次回答机会\n\n"
|
||
text += f"输入 `.quiz 答案` 来回答"
|
||
|
||
return text
|
||
|
||
def _show_current_question(self, state_data: dict) -> str:
|
||
"""显示当前题目
|
||
|
||
Args:
|
||
state_data: 游戏状态数据
|
||
|
||
Returns:
|
||
题目信息
|
||
"""
|
||
attempts = state_data['attempts']
|
||
max_attempts = state_data['max_attempts']
|
||
remaining = max_attempts - attempts
|
||
|
||
text = f"## 📝 当前题目\n\n"
|
||
text += f"**分类**:{state_data.get('category', '未分类')}\n\n"
|
||
text += f"**问题**:{state_data['question']}\n\n"
|
||
text += f"**剩余机会**:{remaining} 次\n\n"
|
||
|
||
# 如果已经尝试过,显示提示
|
||
if attempts > 0 and state_data.get('hint'):
|
||
text += f"💡 提示:{state_data['hint']}\n\n"
|
||
|
||
text += f"输入 `.quiz 答案` 来回答"
|
||
|
||
return text
|
||
|
||
def _check_answer(self, chat_id: int, user_id: int, user_answer: str) -> str:
|
||
"""检查答案
|
||
|
||
Args:
|
||
chat_id: 会话ID
|
||
user_id: 用户ID
|
||
user_answer: 用户答案
|
||
|
||
Returns:
|
||
结果信息
|
||
"""
|
||
state = self.db.get_game_state(chat_id, user_id, 'quiz')
|
||
if not state:
|
||
return "⚠️ 当前没有题目"
|
||
|
||
state_data = state['state_data']
|
||
correct_answer = state_data['answer']
|
||
keywords = state_data['keywords']
|
||
attempts = state_data['attempts']
|
||
max_attempts = state_data['max_attempts']
|
||
|
||
# 更新尝试次数
|
||
attempts += 1
|
||
|
||
# 检查答案(关键词匹配)
|
||
user_answer_lower = user_answer.lower().strip()
|
||
is_correct = False
|
||
|
||
for keyword in keywords:
|
||
if keyword.lower() in user_answer_lower:
|
||
is_correct = True
|
||
break
|
||
|
||
if is_correct:
|
||
# 回答正确
|
||
self.db.delete_game_state(chat_id, user_id, 'quiz')
|
||
self.db.update_game_stats(user_id, 'quiz', win=True)
|
||
|
||
text = f"## 🎉 回答正确!\n\n"
|
||
text += f"**答案**:<font color='#4CAF50'>{correct_answer}</font>\n\n"
|
||
text += f"**用了**:{attempts} 次机会\n\n"
|
||
|
||
if attempts == 1:
|
||
text += "太棒了!一次就答对!🎯"
|
||
else:
|
||
text += "虽然用了几次机会,但最终还是答对了!💪"
|
||
|
||
text += "\n\n输入 `.quiz` 获取下一题"
|
||
|
||
return text
|
||
|
||
# 回答错误
|
||
if attempts >= max_attempts:
|
||
# 机会用完
|
||
self.db.delete_game_state(chat_id, user_id, 'quiz')
|
||
self.db.update_game_stats(user_id, 'quiz', loss=True)
|
||
|
||
text = f"## ❌ 很遗憾,答错了\n\n"
|
||
text += f"**正确答案**:<font color='#F44336'>{correct_answer}</font>\n\n"
|
||
text += "下次加油!\n\n"
|
||
text += "输入 `.quiz` 获取下一题"
|
||
|
||
return text
|
||
|
||
# 还有机会
|
||
state_data['attempts'] = attempts
|
||
self.db.save_game_state(chat_id, user_id, 'quiz', state_data)
|
||
|
||
remaining = max_attempts - attempts
|
||
|
||
text = f"## ❌ 答案不对\n\n"
|
||
text += f"**你的答案**:{user_answer}\n\n"
|
||
text += f"**剩余机会**:{remaining} 次\n\n"
|
||
|
||
# 显示提示
|
||
if state_data.get('hint'):
|
||
text += f"💡 提示:{state_data['hint']}\n\n"
|
||
|
||
text += "再想想,继续回答吧!"
|
||
|
||
return text
|
||
|
||
def get_help(self) -> str:
|
||
"""获取帮助信息"""
|
||
return """## 📝 问答游戏
|
||
|
||
### 基础用法
|
||
- `.quiz` - 获取新题目
|
||
- `.quiz 答案` - 回答问题
|
||
|
||
### 游戏规则
|
||
- 每道题有 3 次回答机会
|
||
- 答错会显示提示
|
||
- 回答正确可继续下一题
|
||
|
||
### 示例
|
||
```
|
||
.quiz # 获取题目
|
||
.quiz Python # 回答
|
||
.quiz 北京 # 回答
|
||
```
|
||
|
||
💡 提示:题目涵盖编程、地理、常识等多个领域
|
||
"""
|
||
|