feat: 添加HTML版本海龟汤游戏并优化Python版本

refactor: 重构Python版本代码,增加API错误处理和默认题目功能

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

chore: 添加项目依赖到requirements.txt
This commit is contained in:
DROUP123 2026-01-07 17:08:47 +08:00
parent 72bec8db47
commit 7144087596
5 changed files with 985 additions and 708 deletions

View File

@ -4,14 +4,19 @@
| 姓名 | 学号 | 主要贡献 (具体分工) |
| ---- | ---- | ------------------ |
| 张三 | 2023xxxx | (组长) 核心逻辑开发、Prompt 编写 |
| 李四 | 2023xxxx | 前端界面设计、HTML版本开发 |
| 王五 | 2023xxxx | 文档撰写、测试与Bug修复 |
| 徐艺桐 | 2412131221 | (组长) 核心逻辑开发、代码编写、创意提供与整合|
| 陈晓璐 | 2410511126 | 前端界面设计、HTML版本开发、撰写心得|
| 尚小雅 | 2410511127 | 前期工作台配置、后期测试与Bug修复|
## 项目简介 & 运行指南
### 简介
这是一个海龟汤游戏项目提供了一个交互式平台用户可以通过提问来猜测海龟汤题目的答案。项目包含HTML版本和Python版本支持15个精心设计的海龟汤题目包括代孕等主题具有完善的关键词匹配系统和现代化的用户界面。
这是一个海龟汤游戏项目提供了一个交互式平台用户可以通过提问来猜测海龟汤题目的答案。项目包含HTML版本海龟汤和python版本需配置也可以直接运行structaul.py游玩文字版可AI编写也可以自定义海龟汤题目包括许多主题具有完善的关键词匹配系统和现代化的用户界面。
### 开发心得
开发海龟汤推理游戏解决传统游戏中主持人负担重、体验不均和故事有限等痛点。通过AI担任主持人玩家可随时游戏推理爱好者能获得无限新故事。
首次用AI编码时颇为震撼它快速生成出清晰的状态管理代码但随后发现其缺乏业务理解需不断调校提示词。最惊喜的是在描述“提问匹配逻辑”后AI不仅实现关键词匹配还建议加入语义相似度计算。而最挫败的是实现进度保存时AI反复给出简单方案忽略隔离、兼容等系统设计问题甚至有时无法理解我的要求最终仍需自主重构。它无法前瞻性地考虑未来故事数据结构变更带来的“兼容性”挑战。它给出的往往是教科书式的、孤立的代码块而非一个考虑了数据流、错误边界和长期演进的稳健系统设计。
这段经历让我反思AI时代程序员的核心竞争力正转向问题定义、系统架构与调试能力。AI擅长执行明确指令但无法替代人类对复杂系统的理解、对用户体验的洞察以及伦理责任的把握。我们不再是单纯的代码实现者更是人机协作的架构师——善于拆解问题、设计稳健架构并以创造力和判断力确保最终质量。技术工具会进化但人类的深度思考与综合判断始终无可替代。AI不会让程序员失业但它会重新定义什么才是“优秀”的程序员。那些只会写基础代码的程序员可能会被替代。
### 如何运行
@ -51,7 +56,7 @@
- 使用"查看答案"按钮直接查看完整答案
2. **题目特点**
- 包含15个多样化的海龟汤题目
- 包含个多样化的海龟汤题目
- 涵盖代孕、犯罪、情感等多种主题
- 每个题目都有详细的关键词匹配系统

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
openai>=2.14.0
python-dotenv>=1.2.1

View File

@ -10,16 +10,32 @@ import traceback
load_dotenv()
# 初始化OpenAI客户端
client = None
try:
client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com"
)
print(f"API客户端初始化成功使用的API Key: {os.getenv('DEEPSEEK_API_KEY')[:10]}...")
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()
exit(1)
user_input = input("是否使用默认题目继续游戏?(y/n): ")
if user_input.lower() != "y":
print("程序已退出。")
exit(1)
else:
print("将使用默认题目继续游戏。")
# 游戏数据存储文件
GAME_DATA_FILE = "turtle_soup_data.json"
@ -65,84 +81,112 @@ class TurtleSoupGame:
"result": "未完成"
}
def generate_story(self, story_type="随机"):
def generate_story(self, theme=None, difficulty=None):
"""生成海龟汤题目"""
print("正在生成海龟汤题目...")
try:
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{
"role": "system",
"content": "你是一个海龟汤游戏的出题者。请生成一个有趣且有挑战性的海龟汤题目包含两个部分1) 简短的奇怪情境描述2-3句话2) 完整的故事解释(包含事件的前因后果)。请确保情境足够引人入胜,让玩家有探索的欲望。"
},
{
"role": "user",
"content": "生成一个海龟汤题目,用中文回答。格式要求:\n情境:[情境描述]\n答案:[完整解释]"
}
],
temperature=1.3,
timeout=30 # 添加30秒超时设置
)
print("API调用成功正在解析结果...")
result = response.choices[0].message.content.strip()
print(f"\nAPI返回的原始内容: {result[:100]}...\n")
# 解析生成的内容
if "情境:" in result and "答案:" in result:
scenario_part = result.split("情境:")[1].split("答案:")[0].strip()
solution_part = result.split("答案:")[1].strip()
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"] = story_type
self.session_data["is_custom"] = False
print("✅ 海龟汤题目生成成功 ✅")
print(f"\n🥣 汤面:{self.story}\n")
print("🔍 你可以通过提问来猜测故事的真相,游戏中我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'结束'退出游戏。\n")
else:
print("⚠️ 生成的内容格式不符合要求,使用默认题目...")
# 使用默认题目
self.story = "一个男人走进一家餐厅,点了一份海龟汤。喝了一口后,他放下汤匙,默默地付了钱离开了餐厅。"
self.solution = "这个男人曾经遭遇海难,和同伴被困在荒岛上。为了生存,同伴们煮了海龟汤给他喝,并告诉他这是他妻子的肉。获救后,他在餐厅喝到真正的海龟汤,才知道自己被骗了,同伴们牺牲了自己来救他。"
# 更新会话数据
self.session_data["story"] = self.story
self.session_data["solution"] = self.solution
self.session_data["game_type"] = story_type
self.session_data["is_custom"] = False
print("✅ 海龟汤题目生成成功 ✅")
print(f"\n🥣 汤面:{self.story}\n")
print("🔍 你可以通过提问来猜测故事的真相,游戏中我只会回答'''''无关'")
print("📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'结束'退出游戏。\n")
except Exception as e:
print(f"❌ 生成题目时出错: {e}")
print("❌ 详细错误信息:")
traceback.print_exc()
# 使用默认题目作为备选
print("\n⚠️ 使用默认题目...")
# 检查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"] = story_type
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):
"""处理玩家的答案猜测"""

View File

@ -1,634 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🐢 海龟汤游戏</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.game-container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
width: 100%;
max-width: 800px;
max-height: 90vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.game-header {
background: linear-gradient(135deg, #4a6fa5 0%, #16222a 100%);
color: white;
padding: 30px;
text-align: center;
}
.game-header h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.game-header p {
font-size: 1.1em;
opacity: 0.9;
}
.game-main {
flex: 1;
padding: 30px;
overflow-y: auto;
}
.soup-section {
margin-bottom: 30px;
text-align: center;
}
.soup-section h2 {
color: #4a6fa5;
margin-bottom: 15px;
font-size: 1.5em;
}
.soup-text {
background: #f8f9fa;
padding: 25px;
border-radius: 15px;
font-size: 1.2em;
line-height: 1.8;
border-left: 5px solid #4a6fa5;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.chat-section {
margin-bottom: 30px;
}
.chat-section h2 {
color: #4a6fa5;
margin-bottom: 15px;
font-size: 1.5em;
}
.chat-history {
background: #f8f9fa;
padding: 20px;
border-radius: 15px;
max-height: 300px;
overflow-y: auto;
margin-bottom: 20px;
}
.chat-message {
margin-bottom: 15px;
padding: 12px 18px;
border-radius: 18px;
max-width: 80%;
word-wrap: break-word;
}
.user-message {
background: #4a6fa5;
color: white;
margin-left: auto;
border-bottom-right-radius: 6px;
}
.bot-message {
background: #e9ecef;
color: #495057;
margin-right: auto;
border-bottom-left-radius: 6px;
}
.system-message {
background: #28a745;
color: white;
text-align: center;
margin: 0 auto 15px;
max-width: 90%;
border-radius: 12px;
padding: 10px;
}
.input-section {
display: flex;
gap: 10px;
}
#question-input {
flex: 1;
padding: 15px;
border: 2px solid #ced4da;
border-radius: 25px;
font-size: 1em;
transition: border-color 0.3s;
}
#question-input:focus {
outline: none;
border-color: #4a6fa5;
box-shadow: 0 0 0 0.2rem rgba(74, 111, 165, 0.25);
}
#send-button {
padding: 15px 30px;
background: linear-gradient(135deg, #4a6fa5, #16222a);
color: white;
border: none;
border-radius: 25px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
#send-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 15px rgba(74, 111, 165, 0.4);
}
#send-button:active {
transform: translateY(0);
}
.game-controls {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 20px;
}
.control-button {
flex: 1;
min-width: 120px;
padding: 12px;
background: linear-gradient(135deg, #6c757d, #495057);
color: white;
border: none;
border-radius: 20px;
font-size: 0.9em;
font-weight: bold;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.control-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(108, 117, 125, 0.4);
}
.new-game-btn {
background: linear-gradient(135deg, #28a745, #218838);
}
.hint-btn {
background: linear-gradient(135deg, #ffc107, #e0a800);
}
.answer-btn {
background: linear-gradient(135deg, #dc3545, #c82333);
}
.guess-btn {
background: linear-gradient(135deg, #fd7e14, #e0a800);
}
.footer {
text-align: center;
padding: 20px;
background: #f8f9fa;
border-top: 1px solid #dee2e6;
color: #6c757d;
}
/* 响应式设计 */
@media (max-width: 768px) {
.game-container {
margin: 10px;
max-height: none;
}
.game-header {
padding: 20px;
}
.game-header h1 {
font-size: 2em;
}
.game-main {
padding: 20px;
}
.input-section {
flex-direction: column;
}
.control-button {
min-width: auto;
}
}
</style>
</head>
<body>
<div class="game-container">
<header class="game-header">
<h1>🐢 海龟汤游戏</h1>
<p>通过提问来猜测故事的真相,我只会回答「是」、「否」或「无关」</p>
</header>
<main class="game-main">
<section class="soup-section">
<h2>🥣 汤面</h2>
<div class="soup-text" id="soup-text">点击「新游戏」开始游戏</div>
</section>
<section class="chat-section">
<h2>💬 对话</h2>
<div class="chat-history" id="chat-history">
<div class="system-message">欢迎来到海龟汤游戏!点击「新游戏」开始,或者查看规则。</div>
</div>
<div class="input-section">
<input type="text" id="question-input" placeholder="请输入你的问题..." autocomplete="off">
<button id="send-button">发送</button>
</div>
<div class="game-controls">
<button class="control-button new-game-btn" id="new-game-btn">新游戏</button>
<button class="control-button hint-btn" id="hint-btn">提示</button>
<button class="control-button answer-btn" id="answer-btn">查看答案</button>
<button class="control-button guess-btn" id="guess-btn">我来猜测</button>
</div>
</section>
</main>
<footer class="footer">
<p>🐢 海龟汤游戏 | 直接在浏览器中游玩</p>
</footer>
</div>
<script>
// 初始化函数确保页面加载完成后执行所有DOM操作
window.addEventListener('load', () => {
// 海龟汤题目库
const DEFAULT_STORIES = [
{
scenario: "一个男人走进一家餐厅,点了一份海龟汤。喝了一口后,他放下汤匙,默默地付了钱离开了餐厅。",
solution: "这个男人曾经遭遇海难,和同伴被困在荒岛上。为了生存,同伴们煮了海龟汤给他喝,并告诉他这是他妻子的肉。获救后,他在餐厅喝到真正的海龟汤,才知道自己被骗了,同伴们牺牲了自己来救他。"
},
{
scenario: "一个女人从窗户跳了出去,却没有受伤。她回头看了看,然后笑了。",
solution: "这个女人是一名囚犯,她被关在飞机的货舱里。当飞机飞行时,她打开了飞机上的紧急出口窗户,利用降落伞安全着陆。回头看到飞机继续飞行,她知道自己成功逃脱了,所以笑了。"
},
{
scenario: "一个人下雨天走在路上,没有打伞,头发却没有湿。他是怎么做到的?",
solution: "这个人是秃头,没有头发,所以头发不会湿。"
},
{
scenario: "一个小偷晚上潜入一栋房子,偷了一些贵重物品。当他准备离开时,听到了敲门声, subsequent邻居死了。",
solution: "小偷在偷东西时,不小心碰倒了楼梯上的花瓶,花瓶滚下楼梯,发出很大的声响。邻居听到声响后出来查看,在下楼梯时被滚下来的花瓶绊倒,摔死了。"
},
{
scenario: "一个人在沙漠中发现了一个瓶子,打开后却死亡了。",
solution: "这个瓶子是一个地雷的触发装置。当这个人打开瓶子时,触发了地雷,导致他死亡。"
},
{
scenario: "一个小女孩在生日宴会上吹灭了蜡烛,她的父母却哭了。",
solution: "小女孩患有绝症,医生告诉她的父母她只能活到七岁。今天是她的七岁生日,当她吹灭蜡烛时,她的父母知道这可能是她最后一个生日了,所以哭了。"
},
{
scenario: "一个消防员在火灾现场救出了所有人,当他准备离开时,按下了电梯按钮,却突然哭了。",
solution: "消防员在火灾中救出了所有人,但在最后一次进入火场时,他的队友被困在了里面。当他按下电梯按钮,准备离开时,看到了电梯里显示的楼层,意识到队友所在的楼层已经被大火吞噬,队友已经牺牲,所以哭了。"
},
{
scenario: "一个女人在图书馆工作,每天都会在一本书里夹一张纸条。有一天,她没有夹纸条,她的丈夫失踪了。",
solution: "女人的丈夫是一名记者,正在调查一个犯罪团伙。他每天都会到图书馆找女人,通过书中的纸条传递信息。有一天,犯罪团伙发现了他们的计划,绑架了丈夫,并威胁女人如果再传递信息就杀死丈夫。所以女人不敢再夹纸条了。"
},
{
scenario: "一个猎人在森林中开枪,结果却被捕了。",
solution: "猎人在森林中打猎时,误将一名徒步旅行者当成了猎物开枪打死了。他因为过失杀人而被捕。"
},
{
scenario: "一个人买了一瓶饮料,看到瓶盖里写着「再来一瓶」,却哭了。",
solution: "这个人患有癌症,需要昂贵的治疗费用。他的家庭已经负债累累,当他看到瓶盖里的「再来一瓶」时,想起自己的病情和家庭的困境,感到绝望,所以哭了。"
},
{
scenario: "一个火车站的工作人员,每天都会在站台上做一个奇怪的手势,火车司机看到后就会停车。",
solution: "这个工作人员负责在站台上保护乘客的安全。有一天,一个小孩跑到了铁轨上,工作人员看到后,做出了紧急停车的手势。火车司机看到后立即停车,避免了悲剧的发生。从那以后,工作人员每天都会做这个手势,提醒火车司机注意安全。"
},
{
scenario: "一个女人在医院里生下了一个孩子,但是她却没有见过这个孩子的父亲。",
solution: "这个女人是一名代孕妈妈。一对不能生育的夫妇雇佣她代孕,孩子的生物学父亲是这对夫妇中的丈夫,但女人从未见过他。"
},
{
scenario: "一个警察在咖啡馆里喝咖啡,突然打翻了杯子,然后冲出了咖啡馆。",
solution: "警察正在追捕一名通缉犯。当他在咖啡馆里喝咖啡时,看到通缉犯走进了咖啡馆。他不小心打翻了杯子,然后立即冲出咖啡馆去追捕通缉犯。"
},
{
scenario: "一个男人在马路上行走,突然心脏病发作。一辆路过的汽车紧急刹车,却导致了他的死亡。",
solution: "男人心脏病发作时,一辆汽车紧急刹车,发出很大的声响。这个声响导致男人受到惊吓,心脏病加重,最终死亡。"
},
{
scenario: "一个人在海边散步,捡到了一个漂流瓶。当他打开瓶子看到里面的内容后,跳海自杀了。",
solution: "这个人患有抑郁症,曾经在绝望中写了一封遗书,装进漂流瓶里扔进了大海。几年后,他的病情有所好转,开始重新面对生活。当他在海边捡到这个漂流瓶,看到自己几年前写的遗书时,想起了过去的痛苦,感到绝望,所以跳海自杀了。"
}
];
// 关键词列表
const YES_KEYWORDS = [
// 海难荒岛系列
"海难", "荒岛", "同伴", "牺牲", "妻子", "肉", "获救", "被困", "生存",
// 囚犯飞机系列
"囚犯", "飞机", "窗户", "失压", "密封", "机舱",
// 秃头系列
"秃头", "头发", "湿",
// 小偷系列
"小偷", "楼梯", "摔", "敲门", "邻居",
// 地雷系列
"地雷", "触发", "沙漠", "瓶子",
// 绝症生日系列
"绝症", "生日", "蜡烛", "提前", "父母", "哭泣",
// 消防员系列
"消防员", "火灾", "队友", "牺牲", "电梯", "楼层", "哭泣",
// 图书馆记者系列
"图书馆", "纸条", "丈夫", "失踪", "记者", "绑架", "囚禁", "犯罪团伙",
// 猎人误伤系列
"猎人", "误伤", "森林", "徒步旅行", "法律责任", "枪声",
// 癌症治疗系列
"癌症", "治疗费用", "再来一瓶", "承受能力", "昂贵",
// 火车站救孩子系列
"火车站", "工作人员", "救孩子", "刹车", "站台", "手势",
// 代孕系列
"代孕妈妈", "代孕", "不能生育", "夫妇", "医院", "孩子", "父亲", "生物学父亲",
// 警察通缉犯系列
"警察", "通缉犯", "追捕", "咖啡馆", "打翻", "冲出",
// 心脏病发作系列
"心脏病", "紧急刹车", "巧合", "外伤", "过马路", "发作",
// 漂流瓶自杀系列
"漂流瓶", "自杀", "抑郁症", "荒岛", "幸存", "命运的讽刺", "跳海", "海浪"
];
const NO_KEYWORDS = [
"毒药", "刀", "枪", "炸弹", "爆炸",
"中毒", "淹死", "电击", "触电",
"刺杀", "枪杀", "投毒", "谋杀",
"自杀死", "他杀死", "掐死", "勒死"
];
// 游戏状态
let currentStory = null;
let currentSolution = null;
let gameOver = false;
// DOM元素 - 在页面加载完成后获取
const soupText = document.getElementById('soup-text');
const chatHistory = document.getElementById('chat-history');
const questionInput = document.getElementById('question-input');
const sendButton = document.getElementById('send-button');
const newGameBtn = document.getElementById('new-game-btn');
const hintBtn = document.getElementById('hint-btn');
const answerBtn = document.getElementById('answer-btn');
const guessBtn = document.getElementById('guess-btn');
// 初始化游戏
function initGame() {
// 随机选择一个题目
const randomIndex = Math.floor(Math.random() * DEFAULT_STORIES.length);
const story = DEFAULT_STORIES[randomIndex];
currentStory = story.scenario;
currentSolution = story.solution;
gameOver = false;
// 更新界面
updateSoupText();
clearChatHistory();
addSystemMessage('游戏开始!请开始提问,我只会回答「是」、「否」或「无关」。');
}
// 更新汤面显示
function updateSoupText() {
soupText.textContent = currentStory;
}
// 清空聊天历史
function clearChatHistory() {
chatHistory.innerHTML = '';
}
// 添加系统消息
function addSystemMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.className = 'system-message';
messageDiv.textContent = message;
chatHistory.appendChild(messageDiv);
scrollToBottom();
}
// 添加用户消息
function addUserMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.className = 'chat-message user-message';
messageDiv.textContent = message;
chatHistory.appendChild(messageDiv);
scrollToBottom();
}
// 添加机器人消息
function addBotMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.className = 'chat-message bot-message';
messageDiv.textContent = message;
chatHistory.appendChild(messageDiv);
scrollToBottom();
}
// 滚动到底部
function scrollToBottom() {
chatHistory.scrollTop = chatHistory.scrollHeight;
}
// 回答问题
function answerQuestion(question) {
if (gameOver) return "游戏已结束,请点击「新游戏」重新开始。";
const questionLower = question.toLowerCase();
const solutionLower = currentSolution.toLowerCase();
// 检查命令
if (questionLower.includes("答案") || questionLower.includes("真相")) {
revealAnswer();
return;
}
if (questionLower.includes("提示") || questionLower.includes("线索")) {
giveHint();
return;
}
// 关键词匹配
const questionYesKeywords = YES_KEYWORDS.filter(keyword => questionLower.includes(keyword));
if (questionYesKeywords.length > 0) {
// 检查这些关键词是否在答案中出现
for (const keyword of questionYesKeywords) {
if (solutionLower.includes(keyword)) {
return "是";
}
}
return "否";
} else if (NO_KEYWORDS.some(keyword => questionLower.includes(keyword))) {
return "否";
} else {
return "无关";
}
}
// 给出提示
function giveHint() {
if (!currentSolution) return;
const solution = currentSolution;
let hint = "";
// 简单的提示生成逻辑
if (solution.includes("海难")) {
hint = "这个故事与海难和生存有关。";
} else if (solution.includes("囚犯")) {
hint = "这个故事与囚犯和飞机有关。";
} else if (solution.includes("秃头")) {
hint = "这个故事与头发有关。";
} else if (solution.includes("小偷")) {
hint = "这个故事与小偷和邻居有关。";
} else if (solution.includes("地雷")) {
hint = "这个故事与沙漠和危险物品有关。";
} else if (solution.includes("绝症")) {
hint = "这个故事与疾病和生日有关。";
} else if (solution.includes("消防员")) {
hint = "这个故事与火灾救援有关。";
} else if (solution.includes("图书馆")) {
hint = "这个故事与图书馆和信息传递有关。";
} else if (solution.includes("猎人")) {
hint = "这个故事与打猎和意外有关。";
} else if (solution.includes("癌症")) {
hint = "这个故事与疾病和经济困难有关。";
} else if (solution.includes("火车站")) {
hint = "这个故事与火车站和安全有关。";
} else if (solution.includes("代孕")) {
hint = "这个故事与生育和医院有关。";
} else if (solution.includes("警察")) {
hint = "这个故事与警察和追捕有关。";
} else if (solution.includes("心脏病")) {
hint = "这个故事与疾病和交通事故有关。";
} else if (solution.includes("漂流瓶")) {
hint = "这个故事与海洋和心理健康有关。";
} else {
hint = "关注故事中的关键人物和事件之间的联系。";
}
addSystemMessage(`💡 提示:${hint}`);
}
// 显示答案
function revealAnswer() {
if (!currentSolution) return;
gameOver = true;
addSystemMessage(`🔓 答案:${currentSolution}`);
addSystemMessage('游戏结束!点击「新游戏」开始新的一局。');
}
// 处理猜测
function handleGuess() {
const guess = prompt("请输入你的猜测:");
if (guess) {
addUserMessage(`猜测:${guess}`);
const guessLower = guess.toLowerCase();
const solutionLower = currentSolution.toLowerCase();
// 简单的猜测评估逻辑
if (solutionLower.includes(guessLower)) {
addBotMessage("恭喜你!猜测正确!");
revealAnswer();
} else {
addBotMessage("猜测不正确,请继续提问。");
}
}
}
// 发送问题
function sendQuestion() {
const question = questionInput.value.trim();
if (!question) return;
addUserMessage(question);
questionInput.value = '';
const answer = answerQuestion(question);
if (answer) {
addBotMessage(answer);
}
}
// 事件监听器 - 在页面加载完成后绑定
sendButton.addEventListener('click', sendQuestion);
questionInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendQuestion();
}
});
newGameBtn.addEventListener('click', initGame);
hintBtn.addEventListener('click', () => {
if (!currentStory) {
addSystemMessage('请先点击「新游戏」开始游戏。');
} else {
giveHint();
}
});
answerBtn.addEventListener('click', () => {
if (!currentStory) {
addSystemMessage('请先点击「新游戏」开始游戏。');
} else {
revealAnswer();
}
});
guessBtn.addEventListener('click', () => {
if (!currentStory) {
addSystemMessage('请先点击「新游戏」开始游戏。');
} else {
handleGuess();
}
});
// 初始化 - 添加欢迎消息
addSystemMessage('欢迎来到海龟汤游戏!点击「新游戏」开始游戏。');
});
</script>
</body>
</html>

860
turtle_soup_html_v2.html Normal file
View File

@ -0,0 +1,860 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>海龟汤游戏</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: '微软雅黑', Arial, sans-serif;
background-color: #f5f5f5;
color: #333;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: white;
min-height: 100vh;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
color: #ff6b35;
margin-bottom: 30px;
font-size: 2.5em;
text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
}
.game-info {
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
border-left: 4px solid #ff6b35;
}
.story-section {
background-color: #fff3cd;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 2px solid #ffeeba;
}
.story-title {
font-weight: bold;
color: #856404;
margin-bottom: 10px;
font-size: 1.2em;
}
.story-content {
font-size: 1.1em;
line-height: 1.8;
}
.chat-section {
margin-bottom: 20px;
}
.chat-history {
height: 300px;
overflow-y: auto;
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
border: 1px solid #dee2e6;
}
.message {
margin-bottom: 15px;
display: flex;
flex-direction: column;
}
.user-message {
align-items: flex-end;
}
.bot-message {
align-items: flex-start;
}
.message-content {
padding: 10px 15px;
border-radius: 18px;
max-width: 80%;
}
.user-message .message-content {
background-color: #007bff;
color: white;
}
.bot-message .message-content {
background-color: #e9ecef;
color: #333;
}
.message-time {
font-size: 0.8em;
color: #6c757d;
margin-top: 5px;
margin-right: 10px;
margin-left: 10px;
}
.input-section {
display: flex;
gap: 10px;
}
#question-input {
flex: 1;
padding: 12px;
border: 2px solid #dee2e6;
border-radius: 25px;
font-size: 1em;
outline: none;
transition: border-color 0.3s;
}
#question-input:focus {
border-color: #007bff;
}
#send-btn {
padding: 12px 24px;
background-color: #ff6b35;
color: white;
border: none;
border-radius: 25px;
font-size: 1em;
cursor: pointer;
transition: background-color 0.3s;
}
#send-btn:hover {
background-color: #ee5a24;
}
.command-buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
}
.cmd-btn {
padding: 8px 16px;
background-color: #28a745;
color: white;
border: none;
border-radius: 15px;
font-size: 0.9em;
cursor: pointer;
transition: background-color 0.3s;
}
.cmd-btn:hover {
background-color: #218838;
}
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.modal-content {
background-color: white;
margin: 15% auto;
padding: 30px;
border: 1px solid #888;
border-radius: 10px;
width: 80%;
max-width: 500px;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover {
color: black;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}
input[type="text"], textarea {
width: 100%;
padding: 10px;
border: 1px solid #dee2e6;
border-radius: 5px;
font-size: 1em;
}
textarea {
height: 100px;
resize: vertical;
}
.btn-primary {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
}
.btn-primary:hover {
background-color: #0056b3;
}
.game-over {
background-color: #d4edda;
padding: 20px;
border-radius: 8px;
border: 2px solid #c3e6cb;
margin-bottom: 20px;
text-align: center;
color: #155724;
}
.stats-section {
background-color: #d1ecf1;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #17a2b8;
margin-bottom: 20px;
}
/* 滚动条样式 */
.chat-history::-webkit-scrollbar {
width: 8px;
}
.chat-history::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.chat-history::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.chat-history::-webkit-scrollbar-thumb:hover {
background: #555;
}
@media (max-width: 600px) {
.container {
padding: 10px;
}
.story-content {
font-size: 1em;
}
.chat-history {
height: 200px;
}
.command-buttons {
flex-direction: column;
}
.cmd-btn {
width: 100%;
}
.message-content {
max-width: 90%;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🐢 海龟汤游戏 🐢</h1>
<div class="game-info">
<p>🔍 海龟汤是一种情境猜谜游戏,我会给出一个奇怪的情境,你可以通过提问来猜测故事的真相。</p>
<p>💬 我只会回答'是'、'否'或'无关'。</p>
<p>📋 输入'答案'查看完整故事,输入'新题'生成新的题目,输入'自定义'创建自己的题目,</p>
<p>📋 输入'提示'获取线索,输入'猜测 内容'尝试猜测答案,输入'结束'退出游戏。</p>
</div>
<div class="stats-section">
<div id="stats"></div>
</div>
<div class="story-section">
<div class="story-title">🥣 汤面</div>
<div class="story-content" id="story-content">请选择游戏模式开始游戏</div>
</div>
<div id="game-over" class="game-over" style="display: none;">
<h3 id="game-over-message"></h3>
<p id="solution-display"></p>
<button class="cmd-btn" onclick="startNewGame()">开始新游戏</button>
</div>
<div class="command-buttons">
<button class="cmd-btn" onclick="selectMode(1)">AI生成题目</button>
<button class="cmd-btn" onclick="selectMode(2)">自定义题目</button>
<button class="cmd-btn" onclick="showHint()">获取提示</button>
<button class="cmd-btn" onclick="showSolution()">查看答案</button>
<button class="cmd-btn" onclick="startNewGame()">新题</button>
<button class="cmd-btn" onclick="endGame()">结束游戏</button>
</div>
<div class="chat-section">
<div class="chat-history" id="chat-history"></div>
<div class="input-section">
<input type="text" id="question-input" placeholder="请输入问题或命令...">
<button id="send-btn" onclick="sendMessage()">发送</button>
</div>
</div>
<!-- 自定义题目模态框 -->
<div id="custom-modal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeModal()">&times;</span>
<h2>创建自定义题目</h2>
<div class="form-group">
<label for="custom-story">汤面(奇怪的情境)</label>
<textarea id="custom-story" placeholder="请输入汤面..."></textarea>
</div>
<div class="form-group">
<label for="custom-solution">汤底(完整解释)</label>
<textarea id="custom-solution" placeholder="请输入汤底..."></textarea>
</div>
<button class="btn-primary" onclick="saveCustomStory()">保存题目</button>
</div>
</div>
</div>
<script>
// 游戏状态
let gameState = {
story: null,
solution: null,
gameOver: false,
hints: [],
questions: [],
guesses: [],
startTime: null,
endTime: null,
result: "未完成",
isCustom: false
};
// 预设题目列表
const presetStories = [
{
story: "一个男人走进一家餐厅,点了一份海龟汤。喝了一口后,他放下汤匙,默默地付了钱离开了餐厅。",
solution: "这个男人曾经遭遇海难,和同伴被困在荒岛上。为了生存,同伴们煮了海龟汤给他喝,并告诉他这是他妻子的肉。获救后,他在餐厅喝到真正的海龟汤,才知道自己被骗了,同伴们牺牲了自己来救他。",
keywords: ["海难", "荒岛", "同伴", "牺牲", "被骗"]
},
{
story: "一个女人独居在公寓里,一天晚上她熄灭了灯准备睡觉。第二天早上,她打开报纸,看到一条消息后跳楼自杀了。",
solution: "这个女人是灯塔管理员,她熄灭的不是自己家的灯,而是灯塔的灯。结果导致一艘船在夜间触礁沉没,船上所有人都遇难了。看到报纸上的这个消息后,她因为内疚而自杀了。",
keywords: ["灯塔管理员", "灯塔", "船", "触礁", "遇难"]
},
{
story: "一个人在雨中行走,没有带任何雨具,头发却一点也没湿。",
solution: "这个人是光头,没有头发,所以即使在雨中行走,头发也不会湿。",
keywords: ["光头", "没有头发"]
}
];
// 初始化游戏
function initGame() {
loadGameStats();
updateStats();
addMessage("系统", "欢迎来到海龟汤游戏!请选择游戏模式开始游戏。");
}
// 选择游戏模式
function selectMode(mode) {
if (mode === 1) {
// 生成AI题目使用预设题目
generateStory();
} else if (mode === 2) {
// 显示自定义题目模态框
openModal();
}
}
// 生成题目
function generateStory() {
// 随机选择一个预设题目
const randomIndex = Math.floor(Math.random() * presetStories.length);
const selectedStory = presetStories[randomIndex];
gameState.story = selectedStory.story;
gameState.solution = selectedStory.solution;
gameState.isCustom = false;
gameState.gameOver = false;
gameState.startTime = new Date().toISOString();
gameState.endTime = null;
gameState.result = "未完成";
gameState.hints = [];
gameState.questions = [];
gameState.guesses = [];
// 更新界面
document.getElementById('story-content').textContent = gameState.story;
document.getElementById('game-over').style.display = 'none';
addMessage("系统", `汤面:${gameState.story}`);
addMessage("系统", "你可以通过提问来猜测故事的真相,游戏中我只会回答'是'、'否'或'无关'。");
}
// 打开自定义题目模态框
function openModal() {
document.getElementById('custom-modal').style.display = 'block';
}
// 关闭自定义题目模态框
function closeModal() {
document.getElementById('custom-modal').style.display = 'none';
// 清空表单
document.getElementById('custom-story').value = '';
document.getElementById('custom-solution').value = '';
}
// 保存自定义题目
function saveCustomStory() {
const customStory = document.getElementById('custom-story').value.trim();
const customSolution = document.getElementById('custom-solution').value.trim();
if (!customStory || !customSolution) {
alert("汤面和汤底不能为空!");
return;
}
gameState.story = customStory;
gameState.solution = customSolution;
gameState.isCustom = true;
gameState.gameOver = false;
gameState.startTime = new Date().toISOString();
gameState.endTime = null;
gameState.result = "未完成";
gameState.hints = [];
gameState.questions = [];
gameState.guesses = [];
// 更新界面
document.getElementById('story-content').textContent = gameState.story;
document.getElementById('game-over').style.display = 'none';
closeModal();
addMessage("系统", `汤面:${gameState.story}`);
addMessage("系统", "自定义题目创建成功!你可以通过提问来猜测故事的真相。");
}
// 发送消息
function sendMessage() {
const input = document.getElementById('question-input');
const message = input.value.trim();
if (!message) return;
// 清空输入框
input.value = '';
if (!gameState.story) {
addMessage("系统", "请先选择游戏模式开始游戏!");
return;
}
if (gameState.gameOver) {
addMessage("系统", "游戏已结束,请开始新游戏!");
return;
}
addMessage("我", message);
// 处理命令
const lowerMessage = message.toLowerCase();
if (lowerMessage.includes("答案") || lowerMessage.includes("查看答案")) {
showSolution();
return;
}
if (lowerMessage.includes("结束") || lowerMessage.includes("退出")) {
endGame();
return;
}
if (lowerMessage.includes("新题") || lowerMessage.includes("重新开始") || lowerMessage.includes("换一个")) {
startNewGame();
return;
}
if (lowerMessage.includes("自定义") || lowerMessage.includes("创建题目")) {
openModal();
return;
}
if (lowerMessage.includes("提示") || lowerMessage.includes("线索")) {
showHint();
return;
}
if (lowerMessage.startsWith("猜测") || lowerMessage.startsWith("我猜")) {
const guess = message.substring(2).trim();
handleGuess(guess);
return;
}
// 处理普通问题
handleQuestion(message);
}
// 处理问题
function handleQuestion(question) {
// 记录问题
gameState.questions.push({
question: question,
timestamp: new Date().toISOString()
});
// 简单的回答逻辑
let answer = "无关";
// 如果问题包含汤底中的关键词,回答"是"或"否"
// 这里使用简单的规则,实际应用中可以更复杂
if (gameState.solution.toLowerCase().includes(question.toLowerCase())) {
answer = "是";
} else if (gameState.solution.toLowerCase().includes(question.toLowerCase().replace("不", "")) ||
gameState.solution.toLowerCase().includes(question.toLowerCase().replace("不是", "是"))) {
answer = "否";
}
// 记录回答
gameState.questions[gameState.questions.length - 1].answer = answer;
addMessage("AI", answer);
}
// 处理猜测
function handleGuess(guess) {
// 记录猜测
gameState.guesses.push({
guess: guess,
timestamp: new Date().toISOString()
});
// 简单的猜测评估逻辑
const lowerGuess = guess.toLowerCase();
const lowerSolution = gameState.solution.toLowerCase();
// 检查是否包含所有关键词
const keywords = getKeywords(gameState.solution);
let matchCount = 0;
keywords.forEach(keyword => {
if (lowerGuess.includes(keyword)) {
matchCount++;
}
});
// 评估结果
if (matchCount >= keywords.length * 0.7) {
// 完全正确
addMessage("系统", "🎉 恭喜你!你的猜测完全正确!");
showSolution();
} else if (matchCount >= keywords.length * 0.3) {
// 部分正确
addMessage("系统", "👍 你的猜测部分正确,但还有一些关键信息没有猜出来。");
addMessage("系统", "🔍 继续提问,获取更多线索吧!");
} else {
// 错误
addMessage("系统", "👎 你的猜测不正确,再试一次吧!");
addMessage("系统", "🔍 继续提问,获取更多线索吧!");
}
}
// 提取关键词
function getKeywords(text) {
// 简单的关键词提取(移除常见停用词,取名词)
const stopWords = ['的', '了', '和', '是', '在', '有', '我', '你', '他', '她', '它', '们', '这', '那', '个', '件', '条', '只', '对', '于', '就', '也', '都', '但', '而', '所以', '因为', '如果', '虽然', '但是', '然而', '不过'];
// 简单分词(这里使用空格分词,实际应用中可以使用更复杂的分词方法)
let words = text.split(/[\s,.;?!]+/).filter(word => word.length > 1);
// 移除停用词
words = words.filter(word => !stopWords.includes(word));
// 返回前10个关键词
return words.slice(0, 10);
}
// 显示提示
function showHint() {
if (!gameState.solution) {
addMessage("系统", "请先选择游戏模式开始游戏!");
return;
}
if (gameState.gameOver) {
addMessage("系统", "游戏已结束,无法获取提示!");
return;
}
// 生成提示(基于汤底的部分内容)
let hint = "";
const solutionWords = gameState.solution.split(/\s+/);
if (gameState.hints.length === 0) {
// 第一个提示:提供人物信息
hint = "提示1故事中涉及到的主要人物是" + getMainCharacter(gameState.solution) + "。";
} else if (gameState.hints.length === 1) {
// 第二个提示:提供事件发生的地点
hint = "提示2故事发生在" + getLocation(gameState.solution) + "。";
} else if (gameState.hints.length === 2) {
// 第三个提示:提供关键物品
hint = "提示3故事中的关键物品是" + getKeyItem(gameState.solution) + "。";
} else {
// 没有更多提示
hint = "没有更多提示了,请尝试自己思考!";
}
if (!gameState.hints.includes(hint)) {
gameState.hints.push(hint);
}
addMessage("系统", hint);
}
// 辅助函数:获取主要人物
function getMainCharacter(solution) {
// 简单的人物提取,实际应用中可以更复杂
const possibleCharacters = ["男人", "女人", "男孩", "女孩", "老人", "孩子", "他", "她", "他们", "她们"];
for (let character of possibleCharacters) {
if (solution.includes(character)) {
return character;
}
}
return "一个人";
}
// 辅助函数:获取地点
function getLocation(solution) {
// 简单的地点提取,实际应用中可以更复杂
const possibleLocations = ["餐厅", "家里", "医院", "海滩", "森林", "办公室", "学校", "公寓", "灯塔"];
for (let location of possibleLocations) {
if (solution.includes(location)) {
return location;
}
}
return "某个地方";
}
// 辅助函数:获取关键物品
function getKeyItem(solution) {
// 简单的物品提取,实际应用中可以更复杂
const possibleItems = ["海龟汤", "灯", "雨伞", "报纸", "手机", "钥匙", "汤勺", "笔", "纸"];
for (let item of possibleItems) {
if (solution.includes(item)) {
return item;
}
}
return "某个物品";
}
// 显示答案
function showSolution() {
if (!gameState.solution) {
addMessage("系统", "请先选择游戏模式开始游戏!");
return;
}
gameState.gameOver = true;
gameState.endTime = new Date().toISOString();
gameState.result = "查看答案";
// 显示答案
const gameOverMessage = document.getElementById('game-over-message');
const solutionDisplay = document.getElementById('solution-display');
gameOverMessage.textContent = "游戏结束!汤底如下:";
solutionDisplay.innerHTML = `<strong>汤底:</strong>${gameState.solution}`;
document.getElementById('game-over').style.display = 'block';
addMessage("系统", `汤底:${gameState.solution}`);
// 保存游戏数据
saveGameSession();
}
// 结束游戏
function endGame() {
gameState.gameOver = true;
gameState.endTime = new Date().toISOString();
gameState.result = "中途退出";
addMessage("系统", "游戏已结束,感谢参与!");
// 保存游戏数据
saveGameSession();
}
// 开始新游戏
function startNewGame() {
// 清空聊天记录
document.getElementById('chat-history').innerHTML = '';
addMessage("系统", "正在准备新游戏...");
// 生成新题目
generateStory();
}
// 保存游戏会话
function saveGameSession() {
// 获取现有游戏数据
let gameData = JSON.parse(localStorage.getItem('turtleSoupData')) || {
games: [],
statistics: {
totalGames: 0,
totalQuestions: 0,
winRate: 0
}
};
// 添加当前游戏数据
gameData.games.push({
...gameState,
sessionId: `game_${Date.now()}`
});
// 更新统计信息
const totalGames = gameData.games.length;
const wonGames = gameData.games.filter(game => game.result === "胜利" || game.result === "查看答案").length;
const totalQuestions = gameData.games.reduce((sum, game) => sum + game.questions.length, 0);
gameData.statistics = {
totalGames: totalGames,
totalQuestions: totalQuestions,
winRate: wonGames / totalGames
};
// 保存数据到本地存储
localStorage.setItem('turtleSoupData', JSON.stringify(gameData));
// 更新统计信息显示
updateStats();
}
// 加载游戏统计信息
function loadGameStats() {
const gameData = JSON.parse(localStorage.getItem('turtleSoupData')) || {
games: [],
statistics: {
totalGames: 0,
totalQuestions: 0,
winRate: 0
}
};
return gameData.statistics;
}
// 更新统计信息显示
function updateStats() {
const stats = loadGameStats();
const statsElement = document.getElementById('stats');
statsElement.innerHTML = `
<p>📊 游戏统计:</p>
<p>总游戏数:${stats.totalGames}</p>
<p>总提问数:${stats.totalQuestions}</p>
<p>完成率:${(stats.winRate * 100).toFixed(1)}%</p>
`;
}
// 添加消息到聊天记录
function addMessage(sender, content) {
const chatHistory = document.getElementById('chat-history');
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender === "我" ? "user-message" : "bot-message"}`;
const messageContentDiv = document.createElement('div');
messageContentDiv.className = 'message-content';
messageContentDiv.textContent = content;
const messageTimeDiv = document.createElement('div');
messageTimeDiv.className = 'message-time';
messageTimeDiv.textContent = new Date().toLocaleTimeString();
messageDiv.appendChild(messageContentDiv);
messageDiv.appendChild(messageTimeDiv);
chatHistory.appendChild(messageDiv);
// 滚动到底部
chatHistory.scrollTop = chatHistory.scrollHeight;
}
// 键盘事件监听
document.getElementById('question-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// 关闭模态框(点击外部区域)
window.onclick = function(event) {
const modal = document.getElementById('custom-modal');
if (event.target === modal) {
closeModal();
}
}
// 初始化游戏
document.addEventListener('DOMContentLoaded', initGame);
</script>
</body>
</html>