```html

<!DOCTYPE html>

<html lang="zh">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

  <title>🔍 解密游戏框架</title>

  <style>

    * {

      margin: 0;

      padding: 0;

      box-sizing: border-box;

      font-family: 'Segoe UI', Roboto, system-ui, sans-serif;

    }

 

    body {

      background: linear-gradient(145deg, #0b1a2b 0%, #1a2f3f 100%);

      min-height: 100vh;

      display: flex;

      justify-content: center;

      align-items: center;

      padding: 16px;

    }

 

    .game-container {

      max-width: 680px;

      width: 100%;

      background: rgba(28, 40, 51, 0.85);

      backdrop-filter: blur(8px);

      -webkit-backdrop-filter: blur(8px);

      border-radius: 48px;

      padding: 28px 24px 32px;

      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6), inset 0 1px 2px rgba(255, 255, 255, 0.08);

      border: 1px solid rgba(255, 255, 255, 0.04);

      transition: all 0.2s ease;

    }

 

    h1 {

      font-size: 2rem;

      font-weight: 500;

      letter-spacing: 2px;

      color: #d4e9ff;

      text-shadow: 0 2px 6px rgba(0, 20, 40, 0.7);

      display: flex;

      align-items: center;

      gap: 12px;

      margin-bottom: 20px;

      border-bottom: 1px solid rgba(255, 255, 255, 0.06);

      padding-bottom: 14px;

    }

 

    h1 small {

      font-size: 0.9rem;

      font-weight: 300;

      color: #8bb4d0;

      margin-left: auto;

      letter-spacing: 0.3px;

    }

 

    .puzzle-panel {

      background: #1f3345;

      border-radius: 32px;

      padding: 28px 24px;

      margin-bottom: 28px;

      box-shadow: inset 0 6px 12px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(255, 255, 255, 0.02);

      border: 1px solid #2f4a5e;

    }

 

    .puzzle-header {

      display: flex;

      justify-content: space-between;

      align-items: center;

      margin-bottom: 12px;

      color: #aac3d6;

      font-size: 0.9rem;

      letter-spacing: 0.4px;

    }

 

    .puzzle-id {

      background: #0d1e2b;

      padding: 4px 16px;

      border-radius: 40px;

      font-weight: 500;

      color: #b3d6f0;

      border: 1px solid #2a4b5e;

    }

 

    .puzzle-text {

      font-size: 1.3rem;

      line-height: 1.6;

      color: #ebf5ff;

      font-weight: 400;

      padding: 8px 0 4px;

      text-shadow: 0 1px 2px rgba(0,0,0,0.3);

      min-height: 4.2rem;

    }

 

    .clue-box {

      background: #132433;

      border-radius: 20px;

      padding: 14px 20px;

      margin: 18px 0 12px;

      border-left: 5px solid #4b8bb8;

      color: #cfdef0;

      font-size: 1rem;

      box-shadow: inset 0 2px 6px rgba(0,0,0,0.4);

    }

 

    .clue-box span {

      font-weight: 300;

      color: #95bedb;

      margin-right: 8px;

    }

 

    .input-area {

      display: flex;

      flex-direction: column;

      gap: 14px;

      margin-top: 18px;

    }

 

    .input-row {

      display: flex;

      flex-wrap: wrap;

      gap: 12px;

    }

 

    .input-row input {

      flex: 2;

      min-width: 180px;

      background: #0f1f2d;

      border: 1px solid #2f4a5e;

      border-radius: 48px;

      padding: 14px 22px;

      font-size: 1rem;

      color: #e5f0fa;

      outline: none;

      transition: 0.25s;

      box-shadow: inset 0 4px 8px rgba(0, 0, 0, 0.5);

    }

 

    .input-row input:focus {

      border-color: #5b9bc7;

      background: #122b3b;

      box-shadow: 0 0 0 3px rgba(70, 140, 200, 0.3), inset 0 4px 8px rgba(0,0,0,0.6);

    }

 

    .input-row input::placeholder {

      color: #6a8aa3;

      font-weight: 300;

      letter-spacing: 0.3px;

    }

 

    .action-group {

      display: flex;

      flex: 1;

      gap: 10px;

      flex-wrap: wrap;

    }

 

    .btn {

      background: #2f4d63;

      border: none;

      border-radius: 48px;

      padding: 12px 24px;

      font-weight: 500;

      font-size: 1rem;

      color: #f0faff;

      cursor: pointer;

      transition: all 0.15s ease;

      box-shadow: 0 6px 0 #0e1e2b, 0 4px 12px rgba(0, 0, 0, 0.4);

      display: inline-flex;

      align-items: center;

      justify-content: center;

      gap: 6px;

      flex: 1;

      min-width: 100px;

      letter-spacing: 0.5px;

      border: 1px solid #4c7088;

    }

 

    .btn:active {

      transform: translateY(4px);

      box-shadow: 0 2px 0 #0e1e2b;

    }

 

    .btn-primary {

      background: #3d7b9e;

      border-color: #6aa9cc;

      box-shadow: 0 6px 0 #1b4053, 0 4px 12px rgba(0, 0, 0, 0.4);

    }

 

    .btn-success {

      background: #3a8b6e;

      border-color: #5eb894;

      box-shadow: 0 6px 0 #1d4d3b, 0 4px 12px rgba(0, 0, 0, 0.4);

    }

 

    .btn-warning {

      background: #b5793a;

      border-color: #dba35a;

      box-shadow: 0 6px 0 #704a1f, 0 4px 12px rgba(0, 0, 0, 0.4);

    }

 

    .btn:disabled {

      opacity: 0.5;

      transform: translateY(2px);

      box-shadow: 0 3px 0 #0e1e2b;

      pointer-events: none;

    }

 

    .message-box {

      margin-top: 18px;

      padding: 12px 18px;

      border-radius: 30px;

      background: #10212e;

      color: #b6d6ed;

      border: 1px solid #2a4a5e;

      font-size: 0.95rem;

      min-height: 3.2rem;

      display: flex;

      align-items: center;

      gap: 8px;

      flex-wrap: wrap;

      box-shadow: inset 0 2px 6px rgba(0,0,0,0.4);

    }

 

    .message-box .emoji {

      font-size: 1.4rem;

    }

 

    .status-badge {

      margin-left: auto;

      background: #1d3545;

      padding: 4px 14px;

      border-radius: 40px;

      font-size: 0.8rem;

      color: #9abdd9;

      border: 1px solid #355d74;

    }

 

    .footer-actions {

      display: flex;

      gap: 12px;

      margin-top: 24px;

      flex-wrap: wrap;

    }

 

    .footer-actions .btn {

      flex: 1;

      min-width: 100px;

    }

 

    .progress-indicator {

      display: flex;

      justify-content: center;

      gap: 12px;

      margin: 16px 0 6px;

    }

 

    .dot {

      width: 12px;

      height: 12px;

      border-radius: 20px;

      background: #2a475b;

      border: 1px solid #3e6279;

      transition: 0.2s;

    }

 

    .dot.active {

      background: #6ab0d9;

      border-color: #a2d4f0;

      box-shadow: 0 0 12px #3f94c2;

    }

 

    .dot.solved {

      background: #5cb58b;

      border-color: #8fd6b0;

    }

 

    @media (max-width: 480px) {

      .game-container { padding: 16px; }

      .puzzle-panel { padding: 20px 16px; }

      .puzzle-text { font-size: 1.1rem; }

      .input-row input { min-width: 140px; }

      .btn { padding: 12px 14px; min-width: 70px; }

    }

  </style>

</head>

<body>

<div class="game-container" id="app">

  <h1>

    🕵️ 解密·框架

    <small id="puzzleCounter">1 / 4</small>

  </h1>

 

  <div class="puzzle-panel">

    <div class="puzzle-header">

      <span class="puzzle-id" id="puzzleId"># 谜题 1</span>

      <span class="status-badge" id="statusBadge">🔒 未解</span>

    </div>

 

    <div class="puzzle-text" id="puzzleText">

      点击「线索」或输入答案...

    </div>

 

    <div class="clue-box" id="clueBox">

      <span>💡 线索</span> <span id="clueText">输入框内输入答案, 点击验证</span>

    </div>

 

    <div class="input-area">

      <div class="input-row">

        <input type="text" id="answerInput" placeholder="输入你的答案..." autocomplete="off" />

        <div class="action-group">

          <button class="btn btn-primary" id="checkBtn">🔎 验证</button>

          <button class="btn btn-warning" id="hintBtn">💬 线索</button>

        </div>

      </div>

    </div>

 

    <div class="message-box" id="messageBox">

      <span class="emoji">📌</span>

      <span id="messageText">准备开始解谜</span>

      <span class="status-badge" id="detailBadge">⚡</span>

    </div>

  </div>

 

  <!-- 进度点 -->

  <div class="progress-indicator" id="progressDots"></div>

 

  <div class="footer-actions">

    <button class="btn" id="resetBtn">🔄 重置进度</button>

    <button class="btn btn-success" id="nextBtn">▶ 下一题</button>

  </div>

</div>

 

<script>

  (function() {

    // ---------- 谜题库 ----------

    const PUZZLES = [

      {

        id: 1,

        text: '我生于黑暗,却在光中消逝。我随你而行,却从不说话。我是什么?',

        clue: '想想你的影子... 或者更具体的,夜晚的伙伴。',

        answer: '影子',

        // 可接受多种答案(转小写比较)

        normalize: (s) => s.trim().toLowerCase().replace(/\s+/g, '')

      },

      {

        id: 2,

        text: '我有城市,没有房屋;有森林,没有树木;有河流,没有水滴。我是什么?',

        clue: '一张纸上的世界,却能装下整个地球。',

        answer: '地图',

        normalize: (s) => s.trim().toLowerCase().replace(/\s+/g, '')

      },

      {

        id: 3,

        text: '我越老越年轻,但永远不会死去。我存在每个地方,但从未被看见。我是?',

        clue: '无形的流逝,每个瞬间都在改变。',

        answer: '时间',

        normalize: (s) => s.trim().toLowerCase().replace(/\s+/g, '')

      },

      {

        id: 4,

        text: '我拥有钥匙却打不开锁,我有空间却没有房间,你可以进入却无法离开。我是什么?',

        clue: '键盘上的世界,每天都会遇见。',

        answer: '键盘',

        normalize: (s) => s.trim().toLowerCase().replace(/\s+/g, '')

      }

    ];

 

    // ---------- 状态 ----------

    let currentIndex = 0; // 0-based

    let solvedStatus = [false, false, false, false];

    let gameCompleted = false;

 

    // DOM 元素

    const puzzleTextEl = document.getElementById('puzzleText');

    const puzzleIdEl = document.getElementById('puzzleId');

    const clueTextEl = document.getElementById('clueText');

    const statusBadge = document.getElementById('statusBadge');

    const answerInput = document.getElementById('answerInput');

    const checkBtn = document.getElementById('checkBtn');

    const hintBtn = document.getElementById('hintBtn');

    const nextBtn = document.getElementById('nextBtn');

    const resetBtn = document.getElementById('resetBtn');

    const messageText = document.getElementById('messageText');

    const messageBox = document.getElementById('messageBox');

    const puzzleCounter = document.getElementById('puzzleCounter');

    const progressDots = document.getElementById('progressDots');

    const detailBadge = document.getElementById('detailBadge');

 

    // ---------- 辅助函数 ----------

    function renderProgressDots() {

      progressDots.innerHTML = '';

      for (let i = 0; i < PUZZLES.length; i++) {

        const dot = document.createElement('span');

        dot.className = 'dot';

        if (i === currentIndex) dot.classList.add('active');

        if (solvedStatus[i]) dot.classList.add('solved');

        progressDots.appendChild(dot);

      }

    }

 

    // 更新界面 (根据 currentIndex 和 solvedStatus)

    function updatePuzzleUI() {

      const puzzle = PUZZLES[currentIndex];

      const isSolved = solvedStatus[currentIndex];

 

      // 文本

      puzzleTextEl.textContent = puzzle.text;

      puzzleIdEl.textContent = `# 谜题 ${puzzle.id}`;

      // 只显示当前谜题的线索(点击线索按钮会刷新)

      clueTextEl.textContent = puzzle.clue;

 

      // 状态徽章

      if (isSolved) {

        statusBadge.innerHTML = '✅ 已解';

        statusBadge.style.color = '#8cd4b0';

      } else {

        statusBadge.innerHTML = '🔒 未解';

        statusBadge.style.color = '#9abdd9';

      }

 

      // 更新计数器

      const solvedCount = solvedStatus.filter(v => v === true).length;

      puzzleCounter.textContent = `${currentIndex+1} / ${PUZZLES.length}`;

 

      // 更新进度点

      renderProgressDots();

 

      // 如果全部解开,特殊显示

      if (solvedCount === PUZZLES.length && !gameCompleted) {

        gameCompleted = true;

        messageText.textContent = '🎉 恭喜!所有谜题已解开! 你太棒了!';

        detailBadge.textContent = '🏆';

        messageBox.style.borderColor = '#5cb58b';

        // 自动把下一题禁用? 但下一题按钮可以循环,但已经完成所有谜题

      } else {

        // 重置消息(如果完成状态被清除)

        if (gameCompleted && solvedCount < PUZZLES.length) {

          gameCompleted = false;

          messageBox.style.borderColor = '#2a4a5e';

          messageText.textContent = '继续解谜吧...';

          detailBadge.textContent = '⚡';

        }

      }

 

      // 如果当前谜题已解,输入框可置灰? 但依然可以输入,但验证会提示已解。

      // 让输入框保持可用,但验证时会有提示。

      answerInput.value = '';

      answerInput.focus();

 

      // 联动 nextBtn 禁用逻辑:如果当前谜题未解,nextBtn 不能直接跳转(但允许强制跳转?我们设定为可以跳,但会提示)

      // 但设计上允许自由跳转,但是解锁下一个谜题建议必须解开当前? 我们采用自由跳转,但给出提醒。

      // 但最好保留自由,不然会卡住。 我们就自由,但验证时判断。

    }

 

    // 显示消息

    function setMessage(text, emoji = '📌', isSuccess = false, isError = false) {

      messageText.textContent = text;

      document.querySelector('.message-box .emoji').textContent = emoji;

      if (isSuccess) {

        messageBox.style.borderLeft = '5px solid #5cb58b';

      } else if (isError) {

        messageBox.style.borderLeft = '5px solid #c97a5a';

      } else {

        messageBox.style.borderLeft = '5px solid #4b8bb8';

      }

    }

 

    // 检查当前谜题答案

    function checkAnswer() {

      const puzzle = PUZZLES[currentIndex];

      const userAnswer = answerInput.value;

      if (!userAnswer.trim()) {

        setMessage('请输入答案再验证', '✍️', false, true);

        return;

      }

 

      const normalize = puzzle.normalize || ((s) => s.trim().toLowerCase().replace(/\s+/g, ''));

      const normalizedUser = normalize(userAnswer);

      const normalizedCorrect = normalize(puzzle.answer);

 

      if (normalizedUser === normalizedCorrect) {

        // 正确!

        if (!solvedStatus[currentIndex]) {

          solvedStatus[currentIndex] = true;

          setMessage(`✅ 完全正确!谜题 ${puzzle.id} 已解开!`, '🎯', true, false);

          // 更新UI

          updatePuzzleUI();

          // 检查是否全部完成

          if (solvedStatus.every(v => v === true)) {

            setMessage('🎉 恭喜!所有谜题已解开! 你太棒了!', '🏆', true, false);

            gameCompleted = true;

            detailBadge.textContent = '🏆';

          } else {

            // 解开后自动显示下一个? 可以给用户选择, 但我们不自动跳转,提示下一题可用

            setMessage(`✅ 谜题 ${puzzle.id} 已解开!点击「下一题」继续`, '👉', true, false);

          }

        } else {

          setMessage(`⏳ 谜题 ${puzzle.id} 已经解开过了,试试下一题吧`, '🔄', false, false);

        }

      } else {

        setMessage(`❌ 答案不对,再想想或者查看线索`, '🤔', false, true);

      }

    }

 

    // 显示线索 (把线索放入消息区)

    function showHint() {

      const puzzle = PUZZLES[currentIndex];

      const clue = puzzle.clue;

      setMessage(`💡 线索: ${clue}`, '🔍', false, false);

      // 同时更新clueBox

      clueTextEl.textContent = clue;

    }

 

    // 跳转到下一题 (循环)

    function goToNextPuzzle() {

      if (solvedStatus.every(v => v === true)) {

        setMessage('🎉 所有谜题已解!你可以重置重新挑战', '🌟', false, false);

        return;

      }

 

      // 如果当前未解,可以提示,但允许跳转,我们提供警告并跳转

      if (!solvedStatus[currentIndex]) {

        setMessage(`⚠️ 当前谜题尚未解开,但你可以自由跳转`, '🔄', false, true);

      } else {

        setMessage(`➡️ 进入下一题`, '📖', false, false);

      }

 

      // 循环到下一个未解谜题? 更自然:直接下一个,循环

      let nextIndex = (currentIndex + 1) % PUZZLES.length;

      // 如果下一个已经解了并且不是所有都解,找最近的未解,但循环太复杂,简单递增

      // 但为了避免一直显示已解,跳过已解? 使用户体验更好:尝试找最近的未解谜题

      let attempts = 0;

      while (solvedStatus[nextIndex] && attempts < PUZZLES.length) {

        nextIndex = (nextIndex + 1) % PUZZLES.length;

        attempts++;

      }

      // 如果所有都解了,上面已经处理了

      currentIndex = nextIndex;

      updatePuzzleUI();

      // 清空消息

      if (!solvedStatus[currentIndex]) {

        setMessage(`🔍 谜题 ${PUZZLES[currentIndex].id} 待解`, '📌', false, false);

      } else {

        setMessage(`✅ 谜题 ${PUZZLES[currentIndex].id} 已解,继续挑战`, '🎯', false, false);

      }

    }

 

    // 重置进度

    function resetGame() {

      solvedStatus = [false, false, false, false];

      currentIndex = 0;

      gameCompleted = false;

      messageBox.style.borderLeft = '5px solid #4b8bb8';

      updatePuzzleUI();

      setMessage('🔄 已重置所有谜题,重新开始吧', '🔄', false, false);

      detailBadge.textContent = '⚡';

      answerInput.focus();

    }

 

    // ---------- 绑定事件 ----------

    function init() {

      // 渲染初始

      updatePuzzleUI();

      setMessage('输入答案,点击验证或按 Enter', '📌', false, false);

 

      // 按钮事件

      checkBtn.addEventListener('click', checkAnswer);

      hintBtn.addEventListener('click', showHint);

      nextBtn.addEventListener('click', goToNextPuzzle);

      resetBtn.addEventListener('click', resetGame);

 

      // 回车键

      answerInput.addEventListener('keydown', (e) => {

        if (e.key === 'Enter') {

          e.preventDefault();

          checkAnswer();

        }

      });

 

      // 点击输入框的时候如果有消息提示可以清除? 但是保留

      answerInput.addEventListener('focus', () => {

        // 小细节,如果当前已解,可以提示

        if (solvedStatus[currentIndex]) {

          setMessage(`💡 谜题 ${PUZZLES[currentIndex].id} 已解,试试下一题`, '📌', false, false);

        }

      });

 

      // 当点击进度点可以跳转? 简单交互: 点进度点跳转到对应谜题 (用户体验)

      progressDots.addEventListener('click', (e) => {

        const dot = e.target.closest('.dot');

        if (!dot) return;

        const index = Array.from(progressDots.children).indexOf(dot);

        if (index === -1 || index === currentIndex) return;

        // 跳转

        currentIndex = index;

        updatePuzzleUI();

        const puzzle = PUZZLES[currentIndex];

        if (solvedStatus[currentIndex]) {

          setMessage(`✅ 谜题 ${puzzle.id} 已解`, '📌', false, false);

        } else {

          setMessage(`🔍 谜题 ${puzzle.id} 待解`, '📌', false, false);

        }

        answerInput.focus();

      });

    }

 

    // 页面完全加载后初始化

    if (document.readyState === 'loading') {

      document.addEventListener('DOMContentLoaded', init);

    } else {

      init();

    }

  })();

</script>

</body>

</html>

```

 

玩法与交互说明

 

玩家将依次挑战N个谜题,通过输入答案并验证来推进游戏。整个框架围绕“解谜-反馈-推进”的核心循环设计。

 

· 谜题与线索:每个谜题都配有文字描述和一条可查看的线索。可以在输入框中作答,或点击“线索”按钮获取提示。

· 验证与反馈:输入答案后点击“验证”或按回车键,系统会立即判断对错,并通过消息区域和状态徽章给出清晰反馈。

· 进度与导航:顶部的进度点和计数器会显示您的整体进度。通过“下一题”按钮或点击进度点自由切换谜题,“重置进度”按钮则可随时重新开始。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐