<!DOCTYPE html>
<html lang="zh-CN">
<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;
    }
    body {
      background: #1a1a2e;
      font-family: 'Segoe UI', sans-serif;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      touch-action: none;
      user-select: none;
      -webkit-user-select: none;
    }
    .game-container {
      background: #16213e;
      border-radius: 16px;
      padding: 15px;
      box-shadow: 0 8px 30px rgba(0,0,0,0.6);
      max-width: 95vw;
      max-height: 95vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
    }
    .header {
      display: flex;
      justify-content: space-between;
      width: 100%;
      color: #e0e0e0;
      font-size: 1.2rem;
      font-weight: bold;
    }
    .score {
      color: #f7c948;
    }
    .best {
      color: #ff6b6b;
    }
    canvas {
      background: #0f0f1a;
      border-radius: 8px;
      display: block;
      touch-action: none;
      box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
    }
    .controls {
      display: flex;
      gap: 10px;
      align-items: center;
      flex-wrap: wrap;
      justify-content: center;
    }
    .btn {
      background: #0f3460;
      color: white;
      border: none;
      border-radius: 8px;
      padding: 10px 20px;
      font-size: 1rem;
      cursor: pointer;
      transition: background 0.2s;
      min-width: 70px;
    }
    .btn:hover {
      background: #1a4a7a;
    }
    .btn:active {
      transform: scale(0.95);
    }
    .dpad {
      display: grid;
      grid-template-columns: repeat(3, 50px);
      grid-template-rows: repeat(3, 50px);
      gap: 5px;
      justify-content: center;
      margin-top: 5px;
    }
    .dpad-btn {
      background: #1a1a3a;
      border: 2px solid #444;
      border-radius: 10px;
      color: white;
      font-size: 1.5rem;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;
      transition: background 0.2s;
    }
    .dpad-btn:active {
      background: #2a2a5a;
    }
    .dpad-btn.up { grid-column: 2; grid-row: 1; }
    .dpad-btn.left { grid-column: 1; grid-row: 2; }
    .dpad-btn.down { grid-column: 2; grid-row: 3; }
    .dpad-btn.right { grid-column: 3; grid-row: 2; }
    .status {
      color: #aaa;
      font-size: 0.9rem;
    }
  </style>
</head>
<body>
  <div class="game-container">
    <div class="header">
      <span>🐍 贪吃蛇</span>
      <span>分数: <span id="score">0</span></span>
      <span>最高: <span id="best">0</span></span>
    </div>
    <canvas id="gameCanvas"></canvas>
    <div class="controls">
      <button class="btn" id="restartBtn">重新开始</button>
      <button class="btn" id="pauseBtn">暂停</button>
    </div>
    <div class="dpad">
      <div class="dpad-btn up" data-dir="up">▲</div>
      <div class="dpad-btn left" data-dir="left">◀</div>
      <div class="dpad-btn down" data-dir="down">▼</div>
      <div class="dpad-btn right" data-dir="right">▶</div>
    </div>
    <div class="status" id="status">按方向键或点击按钮开始</div>
  </div>

  <script>
    (function() {
      const canvas = document.getElementById('gameCanvas');
      const ctx = canvas.getContext('2d');
      const scoreEl = document.getElementById('score');
      const bestEl = document.getElementById('best');
      const statusEl = document.getElementById('status');
      const restartBtn = document.getElementById('restartBtn');
      const pauseBtn = document.getElementById('pauseBtn');

      // 游戏参数
      const GRID_SIZE = 20; // 格子大小
      let cols, rows;
      let snake, direction, nextDirection, food, score, bestScore, gameOver, paused, gameLoop;
      let speed = 150; // 毫秒

      // 初始化画布大小
      function resizeCanvas() {
        const maxWidth = Math.min(window.innerWidth - 40, 400);
        const maxHeight = Math.min(window.innerHeight - 200, 400);
        const size = Math.min(maxWidth, maxHeight);
        canvas.width = size;
        canvas.height = size;
        cols = Math.floor(size / GRID_SIZE);
        rows = Math.floor(size / GRID_SIZE);
        // 确保格子数至少15
        if (cols < 15) cols = 15;
        if (rows < 15) rows = 15;
        canvas.width = cols * GRID_SIZE;
        canvas.height = rows * GRID_SIZE;
        // 重新初始化游戏(如果游戏已开始)
        if (snake) {
          resetGame();
        }
      }

      // 初始化或重置游戏
      function resetGame() {
        snake = [
          {x: Math.floor(cols/2), y: Math.floor(rows/2)},
          {x: Math.floor(cols/2)-1, y: Math.floor(rows/2)},
          {x: Math.floor(cols/2)-2, y: Math.floor(rows/2)},
        ];
        direction = 'right';
        nextDirection = 'right';
        score = 0;
        gameOver = false;
        paused = false;
        pauseBtn.textContent = '暂停';
        statusEl.textContent = '游戏进行中';
        scoreEl.textContent = '0';
        generateFood();
        clearInterval(gameLoop);
        gameLoop = setInterval(gameTick, speed);
      }

      // 生成食物
      function generateFood() {
        while (true) {
          food = {x: Math.floor(Math.random()*cols), y: Math.floor(Math.random()*rows)};
          if (!snake.some(s => s.x === food.x && s.y === food.y)) break;
        }
      }

      // 游戏主循环
      function gameTick() {
        if (gameOver || paused) return;

        // 更新方向
        direction = nextDirection;

        // 计算新蛇头
        let head = {...snake[0]};
        switch(direction) {
          case 'up': head.y--; break;
          case 'down': head.y++; break;
          case 'left': head.x--; break;
          case 'right': head.x++; break;
        }

        // 检查碰撞
        if (head.x < 0 || head.x >= cols || head.y < 0 || head.y >= rows ||
            snake.some(s => s.x === head.x && s.y === head.y)) {
          gameOver = true;
          clearInterval(gameLoop);
          statusEl.textContent = '游戏结束!点击重新开始';
          if (score > bestScore) {
            bestScore = score;
            localStorage.setItem('snakeBest', bestScore);
            bestEl.textContent = bestScore;
          }
          draw();
          return;
        }

        // 移动蛇
        snake.unshift(head);
        if (head.x === food.x && head.y === food.y) {
          score++;
          scoreEl.textContent = score;
          generateFood();
        } else {
          snake.pop();
        }

        draw();
      }

      // 绘制
      function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 绘制网格线(浅色)
        ctx.strokeStyle = '#2a2a4a';
        ctx.lineWidth = 1;
        for (let i = 0; i <= cols; i++) {
          ctx.beginPath();
          ctx.moveTo(i*GRID_SIZE, 0);
          ctx.lineTo(i*GRID_SIZE, canvas.height);
          ctx.stroke();
        }
        for (let i = 0; i <= rows; i++) {
          ctx.beginPath();
          ctx.moveTo(0, i*GRID_SIZE);
          ctx.lineTo(canvas.width, i*GRID_SIZE);
          ctx.stroke();
        }

        // 绘制食物
        ctx.fillStyle = '#ff4757';
        ctx.beginPath();
        ctx.arc(food.x*GRID_SIZE + GRID_SIZE/2, food.y*GRID_SIZE + GRID_SIZE/2, GRID_SIZE/2 - 2, 0, Math.PI*2);
        ctx.fill();

        // 绘制蛇
        snake.forEach((seg, idx) => {
          const gradient = ctx.createRadialGradient(
            seg.x*GRID_SIZE + GRID_SIZE/2, seg.y*GRID_SIZE + GRID_SIZE/2, 2,
            seg.x*GRID_SIZE + GRID_SIZE/2, seg.y*GRID_SIZE + GRID_SIZE/2, GRID_SIZE/2
          );
          if (idx === 0) {
            gradient.addColorStop(0, '#7bed9f');
            gradient.addColorStop(1, '#2ed573');
          } else {
            gradient.addColorStop(0, '#3ae374');
            gradient.addColorStop(1, '#1e9e4a');
          }
          ctx.fillStyle = gradient;
          ctx.fillRect(seg.x*GRID_SIZE + 1, seg.y*GRID_SIZE + 1, GRID_SIZE - 2, GRID_SIZE - 2);
          // 蛇头眼睛
          if (idx === 0) {
            ctx.fillStyle = 'white';
            ctx.beginPath();
            ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 - 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 3, 0, Math.PI*2);
            ctx.fill();
            ctx.beginPath();
            ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 + 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 3, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = 'black';
            ctx.beginPath();
            ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 - 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 1.5, 0, Math.PI*2);
            ctx.fill();
            ctx.beginPath();
            ctx.arc(seg.x*GRID_SIZE + GRID_SIZE/2 + 4, seg.y*GRID_SIZE + GRID_SIZE/2 - 3, 1.5, 0, Math.PI*2);
            ctx.fill();
          }
        });

        // 游戏结束后显示遮罩
        if (gameOver) {
          ctx.fillStyle = 'rgba(0,0,0,0.6)';
          ctx.fillRect(0, 0, canvas.width, canvas.height);
          ctx.fillStyle = 'white';
          ctx.font = 'bold 24px sans-serif';
          ctx.textAlign = 'center';
          ctx.fillText('游戏结束', canvas.width/2, canvas.height/2 - 10);
          ctx.font = '16px sans-serif';
          ctx.fillText('点击重新开始', canvas.width/2, canvas.height/2 + 25);
        }
      }

      // 设置方向
      function setDirection(dir) {
        if (gameOver) return;
        // 防止反向
        if ((direction === 'up' && dir === 'down') ||
            (direction === 'down' && dir === 'up') ||
            (direction === 'left' && dir === 'right') ||
            (direction === 'right' && dir === 'left')) {
          return;
        }
        nextDirection = dir;
      }

      // 键盘事件
      document.addEventListener('keydown', (e) => {
        switch(e.key) {
          case 'ArrowUp': e.preventDefault(); setDirection('up'); break;
          case 'ArrowDown': e.preventDefault(); setDirection('down'); break;
          case 'ArrowLeft': e.preventDefault(); setDirection('left'); break;
          case 'ArrowRight': e.preventDefault(); setDirection('right'); break;
          case ' ': e.preventDefault(); togglePause(); break;
        }
      });

      // 按钮事件
      restartBtn.addEventListener('click', () => {
        resetGame();
        draw();
      });

      pauseBtn.addEventListener('click', togglePause);

      function togglePause() {
        if (gameOver) return;
        paused = !paused;
        pauseBtn.textContent = paused ? '继续' : '暂停';
        statusEl.textContent = paused ? '已暂停' : '游戏进行中';
      }

      // 方向按钮
      document.querySelectorAll('.dpad-btn').forEach(btn => {
        btn.addEventListener('click', () => {
          setDirection(btn.dataset.dir);
        });
      });

      // 触摸滑动(在canvas上)
      let touchStartX, touchStartY;
      canvas.addEventListener('touchstart', (e) => {
        e.preventDefault();
        const touch = e.touches[0];
        touchStartX = touch.clientX;
        touchStartY = touch.clientY;
      }, {passive: false});

      canvas.addEventListener('touchmove', (e) => {
        e.preventDefault();
      }, {passive: false});

      canvas.addEventListener('touchend', (e) => {
        e.preventDefault();
        if (touchStartX === undefined) return;
        const touch = e.changedTouches[0];
        const dx = touch.clientX - touchStartX;
        const dy = touch.clientY - touchStartY;
        if (Math.abs(dx) < 20 && Math.abs(dy) < 20) return;
        if (Math.abs(dx) > Math.abs(dy)) {
          setDirection(dx > 0 ? 'right' : 'left');
        } else {
          setDirection(dy > 0 ? 'down' : 'up');
        }
        touchStartX = undefined;
        touchStartY = undefined;
      }, {passive: false});

      // 窗口大小改变时重置
      window.addEventListener('resize', () => {
        resizeCanvas();
        draw();
      });

      // 初始化
      bestScore = parseInt(localStorage.getItem('snakeBest') || '0');
      bestEl.textContent = bestScore;
      resizeCanvas();
      resetGame();
      draw();
    })();
  </script>
</body>
</html>