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()