GROUP123-LYT/structual.py
DROUP123 7144087596 feat: 添加HTML版本海龟汤游戏并优化Python版本
refactor: 重构Python版本代码,增加API错误处理和默认题目功能

docs: 更新README文档,添加开发心得和运行指南

chore: 添加项目依赖到requirements.txt
2026-01-07 17:08:47 +08:00

489 lines
21 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 os
import json
import time
from datetime import datetime
from openai import OpenAI
from dotenv import load_dotenv
import traceback
# 加载环境变量
load_dotenv()
# 初始化OpenAI客户端
client = None
try:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key or api_key.strip() == "your_api_key_here" or api_key.strip() == "*****":
print("API密钥未配置请在.env文件中设置DEEPSEEK_API_KEY")
user_input = input("是否继续使用默认题目?(y/n): ")
if user_input.lower() != "y":
print("程序已退出。")
exit(1)
else:
print("将使用默认题目继续游戏。")
else:
client = OpenAI(
api_key=api_key,
base_url="https://api.deepseek.com"
)
print(f"API客户端初始化成功使用的API Key: {api_key[:10]}...")
except Exception as e:
print(f"API客户端初始化失败: {e}")
traceback.print_exc()
user_input = input("是否使用默认题目继续游戏?(y/n): ")
if user_input.lower() != "y":
print("程序已退出。")
exit(1)
else:
print("将使用默认题目继续游戏。")
# 游戏数据存储文件
GAME_DATA_FILE = "turtle_soup_data.json"
# 确保数据文件存在
def ensure_data_file_exists():
if not os.path.exists(GAME_DATA_FILE):
with open(GAME_DATA_FILE, "w", encoding="utf-8") as f:
json.dump({"games": [], "statistics": {"total_games": 0, "total_questions": 0, "win_rate": 0.0}}, f, ensure_ascii=False, indent=2)
# 加载游戏数据
def load_game_data():
ensure_data_file_exists()
with open(GAME_DATA_FILE, "r", encoding="utf-8") as f:
return json.load(f)
# 保存游戏数据
def save_game_data(data):
with open(GAME_DATA_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
class TurtleSoupGame:
"""海龟汤游戏类"""
def __init__(self):
self.story = None
self.solution = None
self.game_over = False
self.session_id = str(int(time.time()))
self.game_start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.game_end_time = None
self.session_data = {
"session_id": self.session_id,
"start_time": self.game_start_time,
"end_time": None,
"story": None,
"solution": None,
"game_type": "",
"is_custom": False,
"questions": [],
"guesses": [],
"hints": [],
"result": "未完成"
}
def generate_story(self, theme=None, difficulty=None):
"""生成海龟汤题目"""
print("正在生成海龟汤题目...")
# 检查API客户端是否可用
if client is None:
print("⚠️ API客户端未初始化将使用默认题目...")
# 使用默认题目
self.story = "一个男人走进一家餐厅,点了一份海龟汤。喝了一口后,他放下汤匙,默默地付了钱离开了餐厅。"
self.solution = "这个男人曾经遭遇海难,和同伴被困在荒岛上。为了生存,同伴们煮了海龟汤给他喝,并告诉他这是他妻子的肉。获救后,他在餐厅喝到真正的海龟汤,才知道自己被骗了,同伴们牺牲了自己来救他。"
# 更新会话数据
self.session_data["story"] = self.story
self.session_data["solution"] = self.solution
self.session_data["game_type"] = "默认"
self.session_data["is_custom"] = False
print("✅ 海龟汤题目生成成功 ✅")
print(f"\n🥣 汤面:{self.story}\n")
print("🔍 你可以通过提问来猜测故事的真相,游戏中我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'结束'退出游戏。\n")
return
retry_count = 0
max_retries = 3
while retry_count < max_retries:
try:
# 构建系统提示词
system_prompt = "你是一个海龟汤游戏的出题者。请生成一个有趣且有挑战性的海龟汤题目包含两个部分1) 简短的奇怪情境描述2-3句话2) 完整的故事解释(包含事件的前因后果)。请确保情境足够引人入胜,让玩家有探索的欲望。"
# 添加主题和难度设置
if theme:
system_prompt += f"\n\n主题要求:{theme}"
if difficulty:
system_prompt += f"\n\n难度要求:{difficulty}"
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{
"role": "system",
"content": system_prompt
},
{
"role": "user",
"content": "生成一个海龟汤题目,用中文回答。格式要求:\n情境:[情境描述]\n答案:[完整解释]"
}
],
temperature=1.3,
timeout=30 # 添加30秒超时设置
)
print("API调用成功正在解析结果...")
result = response.choices[0].message.content.strip()
# 解析生成的内容
if "情境:" in result and "答案:" in result:
scenario_part = result.split("情境:")[1].split("答案:")[0].strip()
solution_part = result.split("答案:")[1].strip()
# 质量验证
if len(scenario_part) < 10 or len(solution_part) < 50:
print("⚠️ 生成的内容质量不足,重试中...")
retry_count += 1
time.sleep(1)
continue
self.story = scenario_part
self.solution = solution_part
# 更新会话数据
self.session_data["story"] = self.story
self.session_data["solution"] = self.solution
self.session_data["game_type"] = f"{theme if theme else '随机'}-{difficulty if difficulty else '随机'}"
self.session_data["is_custom"] = False
print("✅ 海龟汤题目生成成功 ✅")
print(f"\n🥣 汤面:{self.story}\n")
print("🔍 你可以通过提问来猜测故事的真相,游戏中我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'结束'退出游戏。\n")
return
else:
print("⚠️ 生成的内容格式不符合要求,重试中...")
retry_count += 1
time.sleep(1)
except Exception as e:
print(f"❌ 生成题目时出错 (尝试 {retry_count+1}/{max_retries}): {e}")
retry_count += 1
time.sleep(1)
# 所有重试都失败,使用默认题目
print("⚠️ 所有重试都失败,使用默认题目...")
self.story = "一个男人走进一家餐厅,点了一份海龟汤。喝了一口后,他放下汤匙,默默地付了钱离开了餐厅。"
self.solution = "这个男人曾经遭遇海难,和同伴被困在荒岛上。为了生存,同伴们煮了海龟汤给他喝,并告诉他这是他妻子的肉。获救后,他在餐厅喝到真正的海龟汤,才知道自己被骗了,同伴们牺牲了自己来救他。"
# 更新会话数据
self.session_data["story"] = self.story
self.session_data["solution"] = self.solution
self.session_data["game_type"] = "默认"
self.session_data["is_custom"] = False
print("✅ 海龟汤题目生成成功 ✅")
print(f"\n🥣 汤面:{self.story}\n")
print("🔍 你可以通过提问来猜测故事的真相,游戏中我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'结束'退出游戏。\n")
def guess_solution(self, guess):
"""处理玩家的答案猜测"""
print(f"\n🎯 你的猜测:{guess}")
print("🤔 正在评估你的猜测...")
# 记录猜测
self.session_data["guesses"].append({
"guess": guess,
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
try:
# 使用AI评估玩家的猜测
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{
"role": "system",
"content": f"你是一个海龟汤游戏的裁判。以下是海龟汤的完整汤底:{self.solution}\n\n现在玩家提出了一个猜测,请你根据汤底内容,评估玩家的猜测是否正确。\n\n评估标准:\n1. 如果玩家的猜测准确包含了汤底的核心信息(主要人物、关键事件、因果关系),回答'正确'\n2. 如果玩家的猜测部分正确,但缺少关键信息,回答'部分正确'\n3. 如果玩家的猜测完全错误,回答'错误'\n\n请只返回'正确''部分正确''错误',不要添加任何其他解释。"
},
{
"role": "user",
"content": guess
}
],
temperature=0.3
)
result = response.choices[0].message.content.strip()
# 根据评估结果显示反馈
if result == "正确":
print("\n🎉 恭喜你!你的猜测完全正确!")
print(f"🔓 === 完整答案(汤底)=== 🔓")
print(f"🍲 汤底:{self.solution}\n")
self.game_over = True
self.session_data["result"] = "胜利"
self.save_game_session()
elif result == "部分正确":
print("\n👍 你的猜测部分正确,但还有一些关键信息没有猜出来。")
print("🔍 继续提问,获取更多线索吧!\n")
else:
print("\n👎 你的猜测不正确,再试一次吧!")
print("🔍 继续提问,获取更多线索吧!\n")
except Exception as e:
print(f"\n❌ 评估猜测时出错: {e}")
traceback.print_exc()
print("🔍 继续提问,获取更多线索吧!\n")
def get_hint(self):
"""生成游戏提示"""
print("\n💡 正在生成提示...")
try:
# 使用AI从汤底中生成提示
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{
"role": "system",
"content": f"你是一个海龟汤游戏的裁判。以下是海龟汤的完整汤底:{self.solution}\n\n请从汤底中提取1-2条关键线索这些线索应该能够帮助玩家更好地理解故事但又不会直接泄露答案。\n\n线索要求:\n1. 只提供事实性信息,不包含解释\n2. 使用简洁的语言\n3. 不要提到汤底的最终结局\n4. 每条线索以'提示X'开头"
},
{
"role": "user",
"content": "请生成1-2条线索"
}
],
temperature=0.5
)
hint = response.choices[0].message.content.strip()
print(f"\n🎯 提示:\n{hint}\n")
# 记录提示
self.session_data["hints"].append({
"hint": hint,
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
except Exception as e:
print(f"\n❌ 生成提示时出错: {e}")
traceback.print_exc()
# 如果AI生成失败提供一个通用提示
generic_hint = "提示1关注汤面中的异常细节\n提示2考虑人物之间的关系和动机"
print(f"\n🎯 提示:\n{generic_hint}\n")
# 记录提示
self.session_data["hints"].append({
"hint": generic_hint,
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
def answer_question(self, question):
"""回答用户的问题"""
# 检查是否是查看答案命令
if question.strip().lower() in ["答案", "查看答案"]:
print(f"\n🔓 === 完整答案(汤底)=== 🔓")
print(f"🍲 汤底:{self.solution}\n")
self.game_over = True
self.session_data["result"] = "查看答案"
self.save_game_session()
return
# 检查是否是结束游戏命令
if question.strip().lower() in ["结束", "退出"]:
print("\n👋 游戏已结束,感谢参与!")
self.game_over = True
self.session_data["result"] = "中途退出"
self.save_game_session()
return
# 检查是否是生成新题命令
if question.strip().lower() in ["新题", "重新开始", "生成新题", "换一个"]:
print("\n🔄 正在生成新的海龟汤题目...\n")
self.save_game_session() # 保存当前游戏
self.__init__() # 重置游戏状态
self.generate_story()
return
# 检查是否是创建自定义题目命令
if question.strip().lower() in ["自定义", "创建题目", "自己出题"]:
self.create_custom_story()
return
# 检查是否是获取提示命令
if question.strip().lower() in ["提示", "线索", "给个提示", "给点线索"]:
self.get_hint()
return
# 检查是否是猜测答案命令
if question.strip().lower().startswith("猜测") or question.strip().lower().startswith("我猜"):
# 提取猜测内容(去除命令前缀)
guess = question.strip()[2:].strip()
if guess:
self.guess_solution(guess)
else:
print("\n⚠️ 请输入你的猜测内容,例如:猜测 小明是个摄影师\n")
return
# 记录问题
self.session_data["questions"].append({
"question": question,
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
try:
# 使用AI回答问题
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{
"role": "system",
"content": f"你是一个海龟汤游戏的裁判。以下是海龟汤的完整故事:{self.solution}\n\n现在玩家提出了一个问题,请你根据故事内容,只能用'''''无关'来回答。如果问题直接或间接涉及到故事的关键信息,回答'''';如果问题与故事完全无关,回答'无关'"
},
{
"role": "user",
"content": question
}
],
temperature=0.3 # 降低温度,使回答更准确
)
answer = response.choices[0].message.content.strip()
# 确保回答符合要求
if answer not in ["", "", "无关"]:
# 如果回答不符合要求,尝试解析
if "" in answer:
answer = ""
elif "" in answer:
answer = ""
else:
answer = "无关"
# 记录回答
self.session_data["questions"][-1]["answer"] = answer
return answer
except Exception as e:
print(f"回答问题时出错: {e}")
traceback.print_exc()
return "无关"
def save_game_session(self):
"""保存游戏会话数据到JSON文件"""
self.game_end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.session_data["end_time"] = self.game_end_time
# 加载现有数据
ensure_data_file_exists()
game_data = load_game_data()
# 添加当前游戏数据
game_data["games"].append(self.session_data)
# 更新统计信息
total_games = len(game_data["games"])
won_games = sum(1 for game in game_data["games"] if game["result"] == "胜利")
total_questions = sum(len(game["questions"]) for game in game_data["games"])
game_data["statistics"] = {
"total_games": total_games,
"total_questions": total_questions,
"win_rate": won_games / total_games if total_games > 0 else 0.0
}
# 保存数据
save_game_data(game_data)
print("📊 游戏数据已保存!")
def create_custom_story(self):
"""创建自定义题目"""
print("\n📝 创建自定义海龟汤题目")
try:
# 获取用户输入的汤面
story = input("请输入汤面(奇怪的情境): ")
if not story.strip():
print("⚠️ 汤面不能为空,请重新输入!\n")
return
# 获取用户输入的汤底
solution = input("请输入汤底(完整解释): ")
if not solution.strip():
print("⚠️ 汤底不能为空,请重新输入!\n")
return
self.story = story.strip()
self.solution = solution.strip()
# 更新会话数据
self.session_data["story"] = self.story
self.session_data["solution"] = self.solution
self.session_data["game_type"] = "自定义"
self.session_data["is_custom"] = True
print("\n✅ 自定义题目创建成功!")
print(f"🥣 汤面:{self.story}\n")
print("🔍 你可以通过提问来猜测故事的真相,游戏中我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'结束'退出游戏。\n")
except Exception as e:
print(f"\n❌ 创建自定义题目时出错: {e}")
traceback.print_exc()
def play(self):
"""开始游戏"""
print("📜 🐢 ================== 海龟汤游戏 ================== 🐢 📜")
print("🔍 海龟汤是一种情境猜谜游戏,我会给出一个奇怪的情境,你可以通过提问来猜测故事的真相。")
print("💬 我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'自定义'创建自己的题目,")
print("📋 输入'提示'获取线索,输入'猜测 内容'尝试猜测答案,输入'结束'退出游戏。\n")
# 确保数据文件存在
ensure_data_file_exists()
# 游戏模式选择
while True:
print("🎮 游戏模式选择:")
print("1. 使用AI生成的题目")
print("2. 自定义题目")
choice = input("请选择模式 (1/2): ")
if choice == "1":
# 生成题目
self.generate_story()
break
elif choice == "2":
# 创建自定义题目
self.create_custom_story()
break
else:
print("⚠️ 无效的选择,请重新输入!\n")
# 游戏主循环
while not self.game_over:
try:
question = input("👤 请提问:")
if not question.strip():
continue
answer = self.answer_question(question)
if not self.game_over: # 如果游戏还没结束且有回答
print(f"🤖 回答:{answer}\n")
except Exception as e:
print(f"❌ 游戏交互时出错: {e}")
traceback.print_exc()
continue
if __name__ == "__main__":
try:
game = TurtleSoupGame()
game.play()
except KeyboardInterrupt:
print("\n\n游戏已中断,感谢参与!")
except Exception as e:
print(f"\n游戏出错:{e}")
traceback.print_exc()