```tsx
import React, { useState, useEffect, useCallback, useRef } from 'react';

// 游戏常量
const GRID_SIZE = 20;
const CELL_SIZE = 20;
const INITIAL_SPEED = 150;
const MIN_SPEED = 50;
const SPEED_STEP = 10;
const INITIAL_SNAKE: [number, number][] = [[10, 10]];
const INITIAL_FOOD: [number, number] = [5, 5];

// 类型定义
type Direction = 'UP' | 'DOWN' | 'LEFT' | 'RIGHT';
type Position = [number, number];
type GameStatus = 'IDLE' | 'RUNNING' | 'PAUSED' | 'GAME_OVER';

interface GameState {
  snake: Position[];
  food: Position;
  direction: Direction;
  nextDirection: Direction;
  score: number;
  highScore: number;
  speed: number;
  status: GameStatus;
}

const SnakeGame: React.FC = () => {
  // 游戏状态
  const [gameState, setGameState] = useState<GameState>({
    snake: INITIAL_SNAKE,
    food: INITIAL_FOOD,
    direction: 'RIGHT',
    nextDirection: 'RIGHT',
    score: 0,
    highScore: parseInt(localStorage.getItem('snakeHighScore') || '0', 10),
    speed: INITIAL_SPEED,
    status: 'IDLE',
  });

  const [showInstructions, setShowInstructions] = useState(true);
  const gameLoopRef = useRef<number | null>(null);
  const directionRef = useRef<Direction>(gameState.direction);
  const nextDirectionRef = useRef<Direction>(gameState.nextDirection);

  // 生成随机食物位置（避开蛇身）
  const generateFood = useCallback((): Position => {
    const newFood: Position = [
      Math.floor(Math.random() * GRID_SIZE),
      Math.floor(Math.random() * GRID_SIZE),
    ];
    
    // 检查是否与蛇重叠
    const isOnSnake = gameState.snake.some(
      ([x, y]) => x === newFood[0] && y === newFood[1]
    );
    
    return isOnSnake ? generateFood() : newFood;
  }, [gameState.snake]);

  // 重置游戏
  const resetGame = useCallback(() => {
    setGameState(prev => ({
      ...prev,
      snake: INITIAL_SNAKE,
      food: INITIAL_FOOD,
      direction: 'RIGHT',
      nextDirection: 'RIGHT',
      score: 0,
      status: 'IDLE',
    }));
    directionRef.current = 'RIGHT';
    nextDirectionRef.current = 'RIGHT';
  }, []);

  // 开始游戏
  const startGame = useCallback(() => {
    if (gameState.status === 'GAME_OVER') {
      resetGame();
    }
    setGameState(prev => ({
      ...prev,
      status: 'RUNNING',
      direction: 'RIGHT',
      nextDirection: 'RIGHT',
    }));
    directionRef.current = 'RIGHT';
    nextDirectionRef.current = 'RIGHT';
  }, [gameState.status, resetGame]);

  // 切换暂停
  const togglePause = useCallback(() => {
    if (gameState.status === 'RUNNING') {
      setGameState(prev => ({ ...prev, status: 'PAUSED' }));
    } else if (gameState.status === 'PAUSED') {
      setGameState(prev => ({ ...prev, status: 'RUNNING' }));
    }
  }, [gameState.status]);

  // 键盘控制
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (gameState.status !== 'RUNNING') return;

      switch (e.key) {
        case 'ArrowUp':
          if (directionRef.current !== 'DOWN') {
            nextDirectionRef.current = 'UP';
          }
          break;
        case 'ArrowDown':
          if (directionRef.current !== 'UP') {
            nextDirectionRef.current = 'DOWN';
          }
          break;
        case 'ArrowLeft':
          if (directionRef.current !== 'RIGHT') {
            nextDirectionRef.current = 'LEFT';
          }
          break;
        case 'ArrowRight':
          if (directionRef.current !== 'LEFT') {
            nextDirectionRef.current = 'RIGHT';
          }
          break;
        case ' ':
          e.preventDefault();
          togglePause();
          break;
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [gameState.status, togglePause]);

  // 游戏主循环
  useEffect(() => {
    if (gameState.status !== 'RUNNING') return;

    const moveSnake = () => {
      setGameState(prev => {
        const { snake, food, score, highScore, speed } = prev;
        const head = [...snake[0]] as Position;
        directionRef.current = nextDirectionRef.current;

        // 移动头部
        switch (nextDirectionRef.current) {
          case 'UP':
            head[1] -= 1;
            break;
          case 'DOWN':
            head[1] += 1;
            break;
          case 'LEFT':
            head[0] -= 1;
            break;
          case 'RIGHT':
            head[0] += 1;
            break;
        }

        // 检查碰撞边界
        const hitWall = head[0] < 0 || head[0] >= GRID_SIZE || head[1] < 0 || head[1] >= GRID_SIZE;
        
        // 检查碰撞自身
        const hitSelf = snake.slice(1).some(([x, y]) => x === head[0] && y === head[1]);

        if (hitWall || hitSelf) {
          // 更新最高分
          const newHighScore = Math.max(score, highScore);
          localStorage.setItem('snakeHighScore', newHighScore.toString());
          
          return {
            ...prev,
            status: 'GAME_OVER',
            highScore: newHighScore,
          };
        }

        // 检查吃食物
        const ateFood = head[0] === food[0] && head[1] === food[1];
        const newSnake = [head, ...snake];
        const newFood = ateFood ? generateFood() : food;
        const newScore = ateFood ? score + 10 : score;
        const newSpeed = ateFood && speed > MIN_SPEED ? Math.max(speed - SPEED_STEP, MIN_SPEED) : speed;

        return {
          ...prev,
          snake: ateFood ? newSnake : newSnake.slice(0, -1),
          food: newFood,
          score: newScore,
          speed: newSpeed,
        };
      });
    };

    gameLoopRef.current = window.setTimeout(moveSnake, gameState.speed);
    return () => {
      if (gameLoopRef.current) {
        clearTimeout(gameLoopRef.current);
      }
    };
  }, [gameState.status, gameState.speed, generateFood]);

  // 更新速度滑块
  const handleSpeedChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newSpeed = parseInt(e.target.value, 10);
    setGameState(prev => ({
      ...prev,
      speed: newSpeed,
    }));
  };

  // 渲染游戏网格
  const renderGrid = () => {
    const cells = [];
    for (let y = 0; y < GRID_SIZE; y++) {
      for (let x = 0; x < GRID_SIZE; x++) {
        const isSnakeHead = gameState.snake[0][0] === x && gameState.snake[0][1] === y;
        const isSnakeBody = gameState.snake.slice(1).some(([sx, sy]) => sx === x && sy === y);
        const isFood = gameState.food[0] === x && gameState.food[1] === y;

        let cellClass = 'cell';
        if (isSnakeHead) {
          cellClass += ' snake-head';
        } else if (isSnakeBody) {
          cellClass += ' snake-body';
        } else if (isFood) {
          cellClass += ' food';
        }

        cells.push(
          <div
            key={`${x}-${y}`}
            className={cellClass}
            style={{
              width: `${CELL_SIZE}px`,
              height: `${CELL_SIZE}px`,
              backgroundColor: isSnakeHead 
                ? '#4CAF50' 
                : isSnakeBody 
                  ? '#2E7D32' 
                  : isFood 
                    ? '#FF5252' 
                    : '#f5f5f5',
              border: '1px solid #e0e0e0',
            }}
          />
        );
      }
    }
    return cells;
  };

  // 渲染分数图表（模拟简单柱状图）
  const renderScoreChart = () => {
    const maxScore = Math.max(gameState.score, gameState.highScore, 50);
    const currentHeight = Math.max(20, (gameState.score / (maxScore || 1)) * 100);
    const highHeight = Math.max(20, (gameState.highScore / (maxScore || 1)) * 100);

    return (
      <div className="chart-container">
        <div className="chart-labels">
          <span>当前分</span>
          <span>最高分</span>
        </div>
        <div className="chart-bars">
          <div 
            className="chart-bar current"
            style={{ height: `${currentHeight}%` }}
          />
          <div 
            className="chart-bar high"
            style={{ height: `${highHeight}%` }}
          />
        </div>
        <div className="chart-values">
          <span>{gameState.score}</span>
          <span>{gameState.highScore}</span>
        </div>
      </div>
    );
  };

  return (
    <div className="snake-game-container">
      <style jsx>{`
        .snake-game-container {
          font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
          max-width: 800px;
          margin: 0 auto;
          padding: 20px;
          background-color: #f9f9f9;
          border-radius: 12px;
          box-shadow: 0 4px 12px rgba(0,0,0,0.1);
        }
        .game-header {
          text-align: center;
          margin-bottom: 20px;
        }
        .game-title {
          color: #1976D2;
          font-size: 28px;
          margin: 0;
          font-weight: 700;
        }
        .game-subtitle {
          color: #666;
          font-size: 16px;
          margin-top: 8px;
        }
        .game-controls {
          display: flex;
          justify-content: center;
          gap: 12px;
          margin-bottom: 20px;
          flex-wrap: wrap;
        }
        .control-btn {
          padding: 10px 20px;
          font-size: 16px;
          font-weight: 600;
          border: none;
          border-radius: 6px;
          cursor: pointer;
          transition: all 0.2s;
          min-width: 120px;
        }
        .control-btn:hover:not(:disabled) {
          transform: translateY(-2px);
          box-shadow: 0 4px 8px rgba(0,0,0,0.15);
        }
        .control-btn:disabled {
          opacity: 0.6;
          cursor: not-allowed;
        }
        .btn-start {
          background-color: #4CAF50;
          color: white;
        }
        .btn-pause {
          background-color: #FF9800;
          color: white;
        }
        .btn-reset {
          background-color: #f44336;
          color: white;
        }
        .speed-control {
          background-color: white;
          padding: 16px;
          border-radius: 8px;
          margin-bottom: 20px;
          box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .speed-label {
          display: flex;
          justify-content: space-between;
          margin-bottom: 8px;
          font-weight: 600;
          color: #333;
        }
        .slider-container {
          display: flex;
          align-items: center;
          gap: 12px;
        }
        .speed-slider {
          flex: 1;
          height: 8px;
          -webkit-appearance: none;
          background: #e0e0e0;
          border-radius: 4px;
          outline: none;
        }
        .speed-slider::-webkit-slider-thumb {
          -webkit-appearance: none;
          width: 20px;
          height: 20px;
          border-radius: 50%;
          background: #1976D2;
          cursor: pointer;
          box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }
        .speed-value {
          min-width: 40px;
          text-align: center;
          font-weight: bold;
          color: #1976D2;
        }
        .game-board {
          background-color: white;
          border-radius: 8px;
          padding: 16px;
          box-shadow: 0 2px 8px rgba(0,0,0,0.1);
          margin-bottom: 20px;
          display: inline-block;
        }
        .grid {
          display: grid;
          grid-template-columns: repeat(${GRID_SIZE}, ${CELL_SIZE}px);
          gap: 1px;
          background-color: #e0e0e0;
          border-radius: 4px;
          overflow: hidden;
        }
        .cell {
          background-color: #f5f5f5;
        }
        .snake-head {
          border-radius: 3px;
        }
        .snake-body {
          border-radius: 2px;
        }
        .food {
          border-radius: 50%;
          animation: pulse 2s infinite;
        }
        @keyframes pulse {
          0% { transform: scale(1); }
          50% { transform: scale(1.1); }
          100% { transform: scale(1); }
        }
        .game-status {
          text-align: center;
          font-size: 18px;
          font-weight: bold;
          margin: 16px 0;
          min-height: 24px;
        }
        .status-running { color: #4CAF50; }
        .status-paused { color: #FF9800; }
        .status-game-over { color: #f44336; }
        .status-idle { color: #2196F3; }
        .score-display {
          display: flex;
          justify-content: space-around;
          margin: 16px 0;
          font-size: 18px;
          font-weight: bold;
        }
        .score-item {
          background-color: white;
          padding: 12px 20px;
          border-radius: 6px;
          box-shadow: 0 2px 4px rgba(0,0,0,0.05);
          min-width: 120px;
        }
        .score-label {
          color: #666;
          font-size: 14px;
          margin-bottom: 4px;
        }
        .score-value {
          font-size: 24px;
          color: #1976D2;
        }
        .chart-container {
          background-color: white;
          padding: 16px;
          border-radius: 8px;
          margin-bottom: 20px;
          box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .chart-labels {
          display: flex;
          justify-content: space-between;
          margin-bottom: 8px;
          font-size: 14px;
          color: #666;
        }
        .chart-bars {
          display: flex;
          justify-content: space-between;
          height: 100px;
          position: relative;
        }
        .chart-bar {
          width: 40px;
          position: absolute;
          bottom: 0;
          border-radius: 4px 4px 0 0;
        }
        .chart-bar.current {
          background-color: #4CAF50;
          left: 20%;
        }
        .chart-bar.high {
          background-color: #2196F3;
          left: 70%;
        }
        .chart-values {
          display: flex;
          justify-content: space-between;
          margin-top: 8px;
          font-weight: bold;
        }
        .instructions {
          background-color: white;
          padding: 16px;
          border-radius: 8px;
          margin-bottom: 20px;
          box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .instructions h3 {
          margin-top: 0;
          color: #1976D2;
        }
        .instructions ul {
          padding-left: 20px;
          margin-bottom: 0;
        }
        .instructions li {
          margin-bottom: 8px;
          line-height: 1.4;
        }
        .key {
          display: inline-block;
          background-color: #e3f2fd;
          padding: 2px 8px;
          border-radius: 4px;
          font-family: monospace;
          font-weight: bold;
          margin: 0 2px;
        }
        @media (max-width: 600px) {
          .game-controls {
            flex-direction: column;
            align-items: center;
          }
          .control-btn {
            width: 100%;
            max-width: 200px;
          }
        }
      `}</style>

      <div className="game-header">
        <h1 className="game-title">🐍 贪吃蛇游戏</h1>
        <p className="game-subtitle">七年级数学 · 逻辑与算法思维</p>
      </div>

      <div className="instructions">
        <h3>🎮 游戏说明</h3>
        <ul>
          <li>使用 <span className="key">↑</span> <span className="key">↓</span> <span className="key">←</span> <span className="key">→</span> 方向键控制蛇的移动方向</li>
          <li>按 <span className="key">空格键</span> 暂停/继续游戏</li>
          <li>吃到红色食物得 10 分，蛇会变长</li>
          <li>撞到墙壁或自己的身体游戏结束</li>
          <li>调整滑块改变游戏速度（数值越小越快）</li>
        </ul>
      </div>

      <div className="score-display">
        <div className="score-item">
          <div className="score-label">当前得分</div>
          <div className="score-value">{gameState.score}</div>
        </div>
        <div className="score-item">
          <div className="score-label">最高得分</div>
          <div className="score-value">{gameState.highScore}</div>
        </div>
      </div>

      <div className="game-controls">
        <button 
          className="control-btn btn-start"
          onClick={startGame}
          disabled={gameState.status === 'RUNNING'}
        >
          {gameState.status === 'GAME_OVER' ? '重新开始' : '开始游戏'}
        </button>
        <button 
          className="control-btn btn-pause"
          onClick={togglePause}
          disabled={gameState.status === 'IDLE' || gameState.status === 'GAME_OVER'}
        >
          {gameState.status === 'PAUSED' ? '继续' : '暂停'}
        </button>
        <button 
          className="control-btn btn-reset"
          onClick={resetGame}
        >
          重置
        </button>
      </div>

      <div className="game-status">
        {gameState.status === 'IDLE' && <span className="status-idle">准备就绪，点击“开始游戏”启动</span>}
        {gameState.status === 'RUNNING' && <span className="status-running">🎮 游戏进行中...</span>}
        {gameState.status === 'PAUSED' && <span className="status-paused">⏸️ 游戏已暂停</span>}
        {gameState.status === 'GAME_OVER' && <span className="status-game-over">💥 游戏结束！点击“重新开始”继续</span>}
      </div>

      <div className="speed-control">
        <div className="speed-label">
          <span>游戏速度控制</span>
          <span>（数值越小越快）</span>
        </div>
        <div className="slider-container">
          <input
            type="range"
            min={MIN_SPEED}
            max={INITIAL_SPEED}
            step={SPEED_STEP}
            value={gameState.speed}
            onChange={handleSpeedChange}
            className="speed-slider"
          />
          <span className="speed-value">{gameState.speed}ms</span>
        </div>
      </div>

      <div className="chart-container">
        <h3>📊 得分对比图</h3>
        {renderScoreChart()}
      </div>

      <div className="game-board">
        <h3>🎮 游戏区域</h3>
        <div className="grid">
          {renderGrid()}
        </div>
      </div>

      <div className="instructions">
        <h3>💡 数学小知识</h3>
        <ul>
          <li>贪吃蛇体现了<strong>坐标系</strong>思想：每个位置用(x, y)表示</li>
          <li>蛇的移动是<strong>向量运算</strong>：方向+位置=新位置</li>
          <li>碰撞检测运用了<strong>逻辑判断</strong>和<strong>集合关系</strong></li>
          <li>游戏速度调节展示了<strong>变量与函数关系</strong></li>
        </ul>
      </div>
    </div>
  );
};

export default SnakeGame;
```