推箱子html代码

wy 1月前

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>经典推箱子 | 1000关卡版</title>
  <!-- 引入Tailwind CSS -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- 引入Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <!-- 自定义配置 -->
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#4F46E5',
            secondary: '#10B981',
            wall: '#4B5563',
            box: '#F59E0B',
            target: '#EC4899',
            player: '#3B82F6',
            ground: '#F3F4F6',
            success: '#10B981',
          },
          fontFamily: {
            inter: ['Inter', 'system-ui', 'sans-serif'],
          },
        },
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .cell-shadow {
        box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
      }
      .game-shadow {
        box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
      }
      .btn-hover {
        @apply transition-all duration-300 hover:scale-105 hover:shadow-lg active:scale-95;
      }
      .animate-bounce-light {
        animation: bounce-light 1.5s infinite;
      }
      @keyframes bounce-light {
        0%, 100% {
          transform: translateY(0);
        }
        50% {
          transform: translateY(-5px);
        }
      }
      .level-progress {
        height: 8px;
        background: linear-gradient(90deg, #4F46E5 var(--progress, 0%), #E5E7EB 0%);
      }
    }
  </style>
</head>
<body class="font-inter bg-gradient-to-br from-indigo-50 to-purple-50 min-h-screen flex flex-col items-center justify-center p-4 text-gray-800">
  
  <!-- 游戏容器 -->
  <div class="max-w-4xl w-full mx-auto bg-white rounded-2xl p-6 game-shadow">
    <!-- 游戏标题 -->
    <header class="text-center mb-6">
      <h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-primary mb-2 flex items-center justify-center gap-2">
        <i class="fa fa-cube" aria-hidden="true"></i>
        经典推箱子 <span class="text-sm bg-primary/10 text-primary px-2 py-1 rounded-full">1000关卡版</span>
      </h1>
      <p class="text-gray-600">挑战1000个随机生成关卡,锻炼你的空间思维极限!</p>
    </header>
    
    <!-- 关卡进度条 -->
    <div class="mb-4">
      <div class="flex justify-between text-sm text-gray-500 mb-1">
        <span>关卡进度</span>
        <span id="progressText">1/1000</span>
      </div>
      <div id="levelProgressBar" class="level-progress rounded-full" style="--progress: 0.1%"></div>
    </div>
    
    <!-- 游戏信息栏 -->
    <div class="flex flex-wrap justify-between items-center mb-6 gap-4">
      <div class="flex items-center gap-4">
        <div class="flex items-center gap-2">
          <span class="text-gray-600">步数:</span>
          <span id="moveCount" class="text-xl font-bold text-primary">0</span>
        </div>
        <div class="flex items-center gap-2">
          <span class="text-gray-600">关卡:</span>
          <span id="currentLevel" class="text-xl font-bold text-primary">1</span>
        </div>
        <div class="flex items-center gap-2">
          <span class="text-gray-600">箱子:</span>
          <span id="boxCount" class="text-xl font-bold text-box">0/0</span>
        </div>
      </div>
      
      <div class="flex gap-3">
        <button id="resetBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg btn-hover flex items-center gap-2">
          <i class="fa fa-refresh" aria-hidden="true"></i>
          <span>重置</span>
        </button>
        <button id="levelSelectBtn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg btn-hover flex items-center gap-2">
          <i class="fa fa-list" aria-hidden="true"></i>
          <span>跳转关卡</span>
        </button>
      </div>
    </div>
    
    <!-- 游戏区域 -->
    <div class="flex justify-center mb-6">
      <div id="gameBoard" class="grid gap-0.5 bg-gray-300 p-1 rounded-lg"></div>
    </div>
    
    <!-- 移动控制区 (移动端) -->
    <div class="md:hidden grid grid-cols-3 gap-3 max-w-xs mx-auto mb-6">
      <div class="col-start-2">
        <button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="up">
          <i class="fa fa-arrow-up text-xl" aria-hidden="true"></i>
        </button>
      </div>
      <div class="col-start-1 row-start-2">
        <button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="left">
          <i class="fa fa-arrow-left text-xl" aria-hidden="true"></i>
        </button>
      </div>
      <div class="col-start-2 row-start-2">
        <button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="down">
          <i class="fa fa-arrow-down text-xl" aria-hidden="true"></i>
        </button>
      </div>
      <div class="col-start-3 row-start-2">
        <button class="direction-btn w-full p-4 bg-gray-200 rounded-lg btn-hover" data-direction="right">
          <i class="fa fa-arrow-right text-xl" aria-hidden="true"></i>
        </button>
      </div>
    </div>
    
    <!-- 游戏说明 -->
    <div class="bg-gray-50 p-4 rounded-lg text-sm text-gray-600">
      <h3 class="font-bold text-gray-800 mb-2 flex items-center gap-2">
        <i class="fa fa-info-circle" aria-hidden="true"></i>
        游戏说明
      </h3>
      <ul class="list-disc pl-5 space-y-1">
        <li>桌面端:使用方向键 ↑↓←→ 控制人物移动,R键快速重置</li>
        <li>移动端:点击方向按钮控制人物移动</li>
        <li>将所有箱子(黄色)推到目标位置(粉色)即可通关</li>
        <li>关卡难度随进度递增,支持直接跳转到任意关卡(1-1000)</li>
      </ul>
    </div>
  </div>
  
  <!-- 关卡选择模态框 -->
  <div id="levelModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-2xl p-6 max-w-md w-full mx-4">
      <div class="flex justify-between items-center mb-4">
        <h2 class="text-xl font-bold text-primary">跳转至关卡</h2>
        <button id="closeModalBtn" class="text-gray-500 hover:text-gray-700">
          <i class="fa fa-times text-xl" aria-hidden="true"></i>
        </button>
      </div>
      <div class="mb-4">
        <label for="levelInput" class="block text-gray-700 mb-2">输入关卡号 (1-1000)</label>
        <div class="flex gap-2">
          <input type="number" id="levelInput" min="1" max="1000" value="1" 
                 class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
          <button id="quickJumpBtn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-lg btn-hover">
            跳转
          </button>
        </div>
        <p class="text-gray-500 text-xs mt-1">当前关卡: <span id="currentLevelDisplay">1</span></p>
      </div>
      <div class="grid grid-cols-5 gap-2 mb-4">
        <!-- 快速选择关卡按钮将动态生成 -->
      </div>
      <button id="confirmLevelBtn" class="w-full bg-primary hover:bg-primary/90 text-white py-3 rounded-lg btn-hover">
        开始游戏
      </button>
    </div>
  </div>
  
  <!-- 胜利模态框 -->
  <div id="successModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-2xl p-6 max-w-md w-full mx-4 text-center">
      <div class="text-5xl text-success mb-4 animate-bounce-light">
        <i class="fa fa-trophy" aria-hidden="true"></i>
      </div>
      <h2 class="text-2xl font-bold text-gray-800 mb-2">恭喜通关!</h2>
      <p class="text-gray-600 mb-4">
        关卡 <span id="successLevel" class="font-bold text-primary">1</span> 完成<br>
        总步数: <span id="successMoves" class="font-bold text-primary">0</span> | 
        效率评级: <span id="efficiencyRating" class="font-bold text-primary">S</span>
      </p>
      <div class="mb-6">
        <div class="flex justify-between text-sm text-gray-500 mb-1">
          <span>总体进度</span>
          <span id="successProgressText">1/1000</span>
        </div>
        <div id="successProgressBar" class="level-progress rounded-full"></div>
      </div>
      <div class="flex gap-3">
        <button id="replayLevelBtn" class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 py-3 rounded-lg btn-hover">
          重新挑战
        </button>
        <button id="nextLevelBtn" class="flex-1 bg-primary hover:bg-primary/90 text-white py-3 rounded-lg btn-hover">
          下一关
        </button>
      </div>
    </div>
  </div>

  <script>
    // 游戏常量定义
    const CELL_TYPES = {
      EMPTY: 0,
      WALL: 1,
      BOX: 2,
      TARGET: 3,
      PLAYER: 4,
      BOX_ON_TARGET: 5,
      PLAYER_ON_TARGET: 6
    };
    
    // 方向映射
    const DIRECTIONS = {
      up: { x: 0, y: -1 },
      down: { x: 0, y: 1 },
      left: { x: -1, y: 0 },
      right: { x: 1, y: 0 }
    };
    
    // 游戏配置
    const GAME_CONFIG = {
      MAX_LEVELS: 1000,
      MIN_SIZE: 5,          // 最小地图尺寸
      MAX_SIZE: 15,         // 最大地图尺寸
      WALL_DENSITY: 0.2,    // 墙壁密度(随关卡递增)
      BOX_RATIO: 0.15       // 箱子占空地块比例(随关卡递增)
    };
    
    // 游戏状态
    let gameState = {
      currentLevel: 1,
      moveCount: 0,
      map: [],
      player: { x: 0, y: 0 },
      boxes: [],
      targets: [],
      mapSize: { width: 5, height: 5 },
      completedBoxes: 0
    };
    
    // DOM 元素
    const gameBoard = document.getElementById('gameBoard');
    const moveCountEl = document.getElementById('moveCount');
    const currentLevelEl = document.getElementById('currentLevel');
    const boxCountEl = document.getElementById('boxCount');
    const resetBtn = document.getElementById('resetBtn');
    const levelSelectBtn = document.getElementById('levelSelectBtn');
    const levelModal = document.getElementById('levelModal');
    const closeModalBtn = document.getElementById('closeModalBtn');
    const levelInput = document.getElementById('levelInput');
    const currentLevelDisplay = document.getElementById('currentLevelDisplay');
    const quickJumpBtn = document.getElementById('quickJumpBtn');
    const confirmLevelBtn = document.getElementById('confirmLevelBtn');
    const successModal = document.getElementById('successModal');
    const successLevelEl = document.getElementById('successLevel');
    const successMovesEl = document.getElementById('successMoves');
    const efficiencyRatingEl = document.getElementById('efficiencyRating');
    const replayLevelBtn = document.getElementById('replayLevelBtn');
    const nextLevelBtn = document.getElementById('nextLevelBtn');
    const directionBtns = document.querySelectorAll('.direction-btn');
    const levelProgressBar = document.getElementById('levelProgressBar');
    const progressText = document.getElementById('progressText');
    const successProgressBar = document.getElementById('successProgressBar');
    const successProgressText = document.getElementById('successProgressText');
    const quickLevelBtnsContainer = document.querySelector('.grid.grid-cols-5');
    
    // 生成随机数(包含最小值,不包含最大值)
    function random(min, max) {
      return Math.random() * (max - min) + min;
    }
    
    // 生成随机整数(包含最小值和最大值)
    function randomInt(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    
    // 根据关卡计算难度参数
    function calculateDifficultyParams(level) {
      // 难度因子(0-1之间)
      const difficultyFactor = Math.min(1, level / GAME_CONFIG.MAX_LEVELS);
      
      // 地图尺寸(随关卡增长)
      const sizeGrowth = Math.floor(difficultyFactor * (GAME_CONFIG.MAX_SIZE - GAME_CONFIG.MIN_SIZE));
      const mapSize = GAME_CONFIG.MIN_SIZE + sizeGrowth;
      
      // 墙壁密度(随关卡增长)
      const wallDensity = GAME_CONFIG.WALL_DENSITY + (difficultyFactor * 0.15);
      
      // 箱子比例(随关卡增长)
      const boxRatio = GAME_CONFIG.BOX_RATIO + (difficultyFactor * 0.1);
      
      return {
        mapSize,
        wallDensity: Math.min(0.35, wallDensity), // 最大墙壁密度限制
        boxRatio: Math.min(0.25, boxRatio)        // 最大箱子比例限制
      };
    }
    
    // 检查位置是否可达(BFS算法)
    function isReachable(map, start, end, boxes, mapSize) {
      const visited = Array(mapSize.height).fill().map(() => Array(mapSize.width).fill(false));
      const queue = [start];
      visited[start.y][start.x] = true;
      
      // 箱子位置集合
      const boxPositions = new Set(boxes.map(box => `${box.x},${box.y}`));
      
      while (queue.length > 0) {
        const { x, y } = queue.shift();
        
        // 到达目标
        if (x === end.x && y === end.y) return true;
        
        // 四个方向
        Object.values(DIRECTIONS).forEach(({ x: dx, y: dy }) => {
          const nx = x + dx;
          const ny = y + dy;
          
          // 边界检查
          if (nx < 0 || nx >= mapSize.width || ny < 0 || ny >= mapSize.height) return;
          
          // 墙壁检查
          if (map[ny][nx] === CELL_TYPES.WALL) return;
          
          // 箱子检查(不能穿过箱子)
          if (boxPositions.has(`${nx},${ny}`)) return;
          
          // 未访问过
          if (!visited[ny][nx]) {
            visited[ny][nx] = true;
            queue.push({ x: nx, y: ny });
          }
        });
      }
      
      return false;
    }
    
    // 生成随机地图(保证有解)
    function generateRandomMap(level) {
      const { mapSize, wallDensity, boxRatio } = calculateDifficultyParams(level);
      const width = mapSize;
      const height = mapSize;
      
      let map = [];
      let player = { x: 0, y: 0 };
      let boxes = [];
      let targets = [];
      let emptyCells = [];
      
      // 1. 初始化地图(全空)
      for (let y = 0; y < height; y++) {
        map[y] = [];
        for (let x = 0; x < width; x++) {
          // 边界设为墙壁
          if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
            map[y][x] = CELL_TYPES.WALL;
          } else {
            map[y][x] = CELL_TYPES.EMPTY;
            emptyCells.push({ x, y });
          }
        }
      }
      
      // 2. 随机生成内部墙壁
      const wallCount = Math.floor((width - 2) * (height - 2) * wallDensity);
      for (let i = 0; i < wallCount; i++) {
        if (emptyCells.length === 0) break;
        
        const randomIndex = randomInt(0, emptyCells.length - 1);
        const { x, y } = emptyCells[randomIndex];
        
        // 确保墙壁不会把地图分割成无法通过的区域(简单检查:周围墙壁不超过2个)
        let adjacentWalls = 0;
        Object.values(DIRECTIONS).forEach(({ x: dx, y: dy }) => {
          const nx = x + dx;
          const ny = y + dy;
          if (map[ny][nx] === CELL_TYPES.WALL) adjacentWalls++;
        });
        
        if (adjacentWalls < 3) {
          map[y][x] = CELL_TYPES.WALL;
          emptyCells.splice(randomIndex, 1);
        }
      }
      
      // 3. 选择玩家初始位置(随机空单元格)
      const playerIndex = randomInt(0, emptyCells.length - 1);
      player = { ...emptyCells[playerIndex] };
      map[player.y][player.x] = CELL_TYPES.PLAYER;
      
      // 4. 计算箱子数量和目标数量(箱子数 = 目标数)
      const boxCount = Math.max(1, Math.floor(emptyCells.length * boxRatio));
      
      // 5. 选择目标位置(确保与玩家位置不同)
      const availableTargets = emptyCells.filter(cell => !(cell.x === player.x && cell.y === player.y));
      for (let i = 0; i < boxCount && availableTargets.length > 0; i++) {
        const randomIndex = randomInt(0, availableTargets.length - 1);
        const target = availableTargets[randomIndex];
        targets.push({ ...target });
        availableTargets.splice(randomIndex, 1);
      }
      
      // 6. 选择箱子初始位置(确保与玩家和目标位置不同,且可达)
      const availableBoxes = availableTargets.filter(cell => 
        !targets.some(target => target.x === cell.x && target.y === cell.y)
      );
      
      while (boxes.length < boxCount && availableBoxes.length > 0) {
        const randomIndex = randomInt(0, availableBoxes.length - 1);
        const boxPos = availableBoxes[randomIndex];
        
        // 临时添加箱子
        boxes.push({ ...boxPos });
        
        // 检查所有目标是否可达(玩家能到达目标位置)
        const allTargetsReachable = targets.every(target => 
          isReachable(map, player, target, boxes, { width, height })
        );
        
        // 如果不可达,移除这个箱子
        if (!allTargetsReachable) {
          boxes.pop();
        }
        
        availableBoxes.splice(randomIndex, 1);
      }
      
      // 确保箱子数等于目标数(如果不够则减少目标数)
      if (boxes.length < targets.length) {
        targets = targets.slice(0, boxes.length);
      }
      
      return {
        map,
        player,
        boxes,
        targets,
        width,
        height
      };
    }
    
    // 初始化快速选择关卡按钮
    function initQuickLevelButtons() {
      quickLevelBtnsContainer.innerHTML = '';
      
      // 生成最近的5个关卡和一些里程碑关卡
      const quickLevels = [
        Math.max(1, gameState.currentLevel - 2),
        Math.max(1, gameState.currentLevel - 1),
        gameState.currentLevel,
        Math.min(GAME_CONFIG.MAX_LEVELS, gameState.currentLevel + 1),
        Math.min(GAME_CONFIG.MAX_LEVELS, gameState.currentLevel + 2),
        10, 50, 100, 200, 500, 1000
      ];
      
      // 去重并排序
      const uniqueLevels = [...new Set(quickLevels)].sort((a, b) => a - b);
      
      // 创建按钮
      uniqueLevels.forEach(level => {
        const btn = document.createElement('button');
        btn.className = `level-btn w-full py-2 rounded-lg btn-hover text-sm ${
          level === gameState.currentLevel ? 'bg-primary text-white' : 'bg-gray-200 text-gray-800'
        }`;
        btn.textContent = level;
        btn.dataset.level = level;
        
        btn.addEventListener('click', () => {
          levelInput.value = level;
          document.querySelectorAll('.level-btn').forEach(b => {
            b.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-gray-200 text-gray-800';
          });
          btn.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-primary text-white';
        });
        
        quickLevelBtnsContainer.appendChild(btn);
      });
    }
    
    // 初始化游戏
    function initGame(levelIndex = 1) {
      // 验证关卡号
      const level = Math.max(1, Math.min(GAME_CONFIG.MAX_LEVELS, levelIndex));
      gameState.currentLevel = level;
      
      // 生成关卡
      const { map, player, boxes, targets, width, height } = generateRandomMap(level);
      
      gameState = {
        currentLevel: level,
        moveCount: 0,
        map: JSON.parse(JSON.stringify(map)),
        player: { ...player },
        boxes: JSON.parse(JSON.stringify(boxes)),
        targets: JSON.parse(JSON.stringify(targets)),
        mapSize: { width, height },
        completedBoxes: calculateCompletedBoxes(boxes, targets)
      };
      
      updateUI();
      renderGameBoard();
      updateProgressBar();
    }
    
    // 计算已完成的箱子数
    function calculateCompletedBoxes(boxes, targets) {
      return boxes.filter(box => 
        targets.some(target => target.x === box.x && target.y === box.y)
      ).length;
    }
    
    // 更新UI显示
    function updateUI() {
      moveCountEl.textContent = gameState.moveCount;
      currentLevelEl.textContent = gameState.currentLevel;
      currentLevelDisplay.textContent = gameState.currentLevel;
      levelInput.value = gameState.currentLevel;
      
      // 更新箱子计数
      const totalBoxes = gameState.boxes.length;
      const completedBoxes = gameState.completedBoxes;
      boxCountEl.textContent = `${completedBoxes}/${totalBoxes}`;
      
      // 更新进度文本
      progressText.textContent = `${gameState.currentLevel}/${GAME_CONFIG.MAX_LEVELS}`;
    }
    
    // 更新进度条
    function updateProgressBar() {
      const progress = (gameState.currentLevel / GAME_CONFIG.MAX_LEVELS) * 100;
      levelProgressBar.style.setProperty('--progress', `${progress}%`);
      
      // 胜利模态框中的进度条
      successProgressBar.style.setProperty('--progress', `${progress}%`);
      successProgressText.textContent = `${gameState.currentLevel}/${GAME_CONFIG.MAX_LEVELS}`;
    }
    
    // 渲染游戏棋盘
    function renderGameBoard() {
      const { map, mapSize, player, boxes, targets } = gameState;
      const { width, height } = mapSize;
      
      // 设置网格尺寸
      gameBoard.style.gridTemplateRows = `repeat(${height}, minmax(0, 1fr))`;
      gameBoard.style.gridTemplateColumns = `repeat(${width}, minmax(0, 1fr))`;
      
      // 清空棋盘
      gameBoard.innerHTML = '';
      
      // 计算单元格大小(响应式)
      const maxWidth = window.innerWidth - 40;
      const cellSize = Math.min(60, Math.floor(maxWidth / width));
      gameBoard.style.gap = '0.5px';
      
      // 渲染每个单元格
      for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
          const cell = document.createElement('div');
          cell.className = 'cell aspect-square flex items-center justify-center cell-shadow';
          cell.style.width = `${cellSize}px`;
          cell.style.height = `${cellSize}px`;
          
          // 确定单元格类型
          let cellType = map[y][x];
          
          // 检查是否有箱子在目标上
          const hasBox = boxes.some(box => box.x === x && box.y === y);
          const isTarget = targets.some(target => target.x === x && target.y === y);
          const isPlayer = player.x === x && player.y === y;
          
          if (hasBox && isTarget) cellType = CELL_TYPES.BOX_ON_TARGET;
          else if (isPlayer && isTarget) cellType = CELL_TYPES.PLAYER_ON_TARGET;
          else if (hasBox) cellType = CELL_TYPES.BOX;
          else if (isTarget) cellType = CELL_TYPES.TARGET;
          else if (isPlayer) cellType = CELL_TYPES.PLAYER;
          
          // 设置单元格样式和内容
          switch(cellType) {
            case CELL_TYPES.EMPTY:
              cell.classList.add('bg-ground');
              break;
            case CELL_TYPES.WALL:
              cell.classList.add('bg-wall', 'rounded-sm');
              break;
            case CELL_TYPES.BOX:
              cell.classList.add('bg-ground');
              cell.innerHTML = '<div class="w-4/5 h-4/5 bg-box rounded-md shadow-md transform transition-transform"></div>';
              break;
            case CELL_TYPES.TARGET:
              cell.classList.add('bg-ground');
              cell.innerHTML = '<div class="w-4/5 h-4/5 border-2 border-dashed border-target rounded-md"></div>';
              break;
            case CELL_TYPES.PLAYER:
              cell.classList.add('bg-ground');
              cell.innerHTML = '<div class="w-3/5 h-3/5 bg-player rounded-full shadow-md transform transition-transform"></div>';
              break;
            case CELL_TYPES.BOX_ON_TARGET:
              cell.classList.add('bg-ground');
              cell.innerHTML = '<div class="w-4/5 h-4/5 bg-box rounded-md shadow-md transform transition-transform ring-2 ring-target ring-inset"></div>';
              break;
            case CELL_TYPES.PLAYER_ON_TARGET:
              cell.classList.add('bg-ground');
              cell.innerHTML = '<div class="w-3/5 h-3/5 bg-player rounded-full shadow-md transform transition-transform ring-2 ring-target ring-inset"></div>';
              break;
          }
          
          gameBoard.appendChild(cell);
        }
      }
    }
    
    // 检查移动是否有效
    function isValidMove(dx, dy) {
      const { x: px, y: py } = gameState.player;
      const nx = px + dx;
      const ny = py + dy;
      const { width, height } = gameState.mapSize;
      
      // 检查边界
      if (nx < 0 || nx >= width || ny < 0 || ny >= height) {
        return false;
      }
      
      // 检查墙壁
      if (gameState.map[ny][nx] === CELL_TYPES.WALL) {
        return false;
      }
      
      // 检查箱子
      const boxIndex = gameState.boxes.findIndex(box => box.x === nx && box.y === ny);
      if (boxIndex !== -1) {
        // 有箱子,检查箱子是否可以移动
        const boxNx = nx + dx;
        const boxNy = ny + dy;
        
        // 检查箱子移动边界
        if (boxNx < 0 || boxNx >= width || boxNy < 0 || boxNy >= height) {
          return false;
        }
        
        // 检查箱子移动位置是否是墙壁
        if (gameState.map[boxNy][boxNx] === CELL_TYPES.WALL) {
          return false;
        }
        
        // 检查箱子移动位置是否有其他箱子
        const isAnotherBox = gameState.boxes.some(box => box.x === boxNx && box.y === boxNy);
        if (isAnotherBox) {
          return false;
        }
        
        // 箱子可以移动
        return true;
      }
      
      // 没有箱子,移动有效
      return true;
    }
    
    // 执行移动
    function movePlayer(dx, dy) {
      if (!isValidMove(dx, dy)) {
        return false;
      }
      
      const { x: px, y: py } = gameState.player;
      const nx = px + dx;
      const ny = py + dy;
      
      // 检查是否需要推动箱子
      const boxIndex = gameState.boxes.findIndex(box => box.x === nx && box.y === ny);
      if (boxIndex !== -1) {
        // 移动箱子
        gameState.boxes[boxIndex].x += dx;
        gameState.boxes[boxIndex].y += dy;
        
        // 更新完成的箱子数
        gameState.completedBoxes = calculateCompletedBoxes(gameState.boxes, gameState.targets);
      }
      
      // 移动玩家
      gameState.player.x = nx;
      gameState.player.y = ny;
      
      // 增加步数
      gameState.moveCount++;
      
      // 更新UI
      updateUI();
      renderGameBoard();
      
      // 检查是否通关
      if (checkWin()) {
        setTimeout(showSuccessModal, 500);
      }
      
      return true;
    }
    
    // 检查是否通关
    function checkWin() {
      return gameState.completedBoxes === gameState.boxes.length && gameState.boxes.length > 0;
    }
    
    // 计算效率评级
    function calculateEfficiencyRating(moveCount, boxCount) {
      const baseMovesPerBox = 15; // 每个箱子的基准步数
      const efficiency = (boxCount * baseMovesPerBox) / moveCount;
      
      if (efficiency >= 1.2) return 'S';
      if (efficiency >= 1.0) return 'A';
      if (efficiency >= 0.8) return 'B';
      if (efficiency >= 0.6) return 'C';
      return 'D';
    }
    
    // 显示胜利模态框
    function showSuccessModal() {
      const level = gameState.currentLevel;
      const moves = gameState.moveCount;
      const boxCount = gameState.boxes.length;
      const rating = calculateEfficiencyRating(moves, boxCount);
      
      successLevelEl.textContent = level;
      successMovesEl.textContent = moves;
      efficiencyRatingEl.textContent = rating;
      
      // 设置评级颜色
      switch(rating) {
        case 'S': efficiencyRatingEl.className = 'font-bold text-purple-600'; break;
        case 'A': efficiencyRatingEl.className = 'font-bold text-primary'; break;
        case 'B': efficiencyRatingEl.className = 'font-bold text-secondary'; break;
        case 'C': efficiencyRatingEl.className = 'font-bold text-box'; break;
        case 'D': efficiencyRatingEl.className = 'font-bold text-red-500'; break;
      }
      
      // 更新进度条
      updateProgressBar();
      
      // 如果是最后一关,修改按钮文本
      if (level === GAME_CONFIG.MAX_LEVELS) {
        nextLevelBtn.textContent = '重新开始';
      } else {
        nextLevelBtn.textContent = '下一关';
      }
      
      successModal.classList.remove('hidden');
    }
    
    // 事件监听
    function setupEventListeners() {
      // 键盘控制
      document.addEventListener('keydown', (e) => {
        switch(e.key) {
          case 'ArrowUp':
            movePlayer(0, -1);
            break;
          case 'ArrowDown':
            movePlayer(0, 1);
            break;
          case 'ArrowLeft':
            movePlayer(-1, 0);
            break;
          case 'ArrowRight':
            movePlayer(1, 0);
            break;
          case 'r':
          case 'R':
            initGame(gameState.currentLevel);
            break;
        }
      });
      
      // 重置按钮
      resetBtn.addEventListener('click', () => {
        initGame(gameState.currentLevel);
      });
      
      // 关卡选择按钮
      levelSelectBtn.addEventListener('click', () => {
        initQuickLevelButtons();
        levelModal.classList.remove('hidden');
      });
      
      // 关闭模态框
      closeModalBtn.addEventListener('click', () => {
        levelModal.classList.add('hidden');
      });
      
      // 快速跳转按钮
      quickJumpBtn.addEventListener('click', () => {
        let level = parseInt(levelInput.value);
        level = Math.max(1, Math.min(GAME_CONFIG.MAX_LEVELS, level));
        levelInput.value = level;
        
        // 更新快速选择按钮状态
        document.querySelectorAll('.level-btn').forEach(btn => {
          if (parseInt(btn.dataset.level) === level) {
            btn.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-primary text-white';
          } else {
            btn.className = 'level-btn w-full py-2 rounded-lg btn-hover text-sm bg-gray-200 text-gray-800';
          }
        });
      });
      
      // 确认选择关卡
      confirmLevelBtn.addEventListener('click', () => {
        const level = parseInt(levelInput.value);
        if (!isNaN(level) && level >= 1 && level <= GAME_CONFIG.MAX_LEVELS) {
          levelModal.classList.add('hidden');
          initGame(level);
        } else {
          alert('请输入1-1000之间的有效关卡号');
        }
      });
      
      // 重新挑战
      replayLevelBtn.addEventListener('click', () => {
        successModal.classList.add('hidden');
        initGame(gameState.currentLevel);
      });
      
      // 下一关
      nextLevelBtn.addEventListener('click', () => {
        successModal.classList.add('hidden');
        let nextLevel = gameState.currentLevel + 1;
        if (nextLevel > GAME_CONFIG.MAX_LEVELS) {
          nextLevel = 1; // 回到第一关
        }
        initGame(nextLevel);
      });
      
      // 方向按钮(移动端)
      directionBtns.forEach(btn => {
        btn.addEventListener('click', () => {
          const direction = btn.dataset.direction;
          const { x, y } = DIRECTIONS[direction];
          movePlayer(x, y);
        });
      });
      
      // 点击空白处关闭模态框
      window.addEventListener('click', (e) => {
        if (e.target === levelModal) {
          levelModal.classList.add('hidden');
        }
        if (e.target === successModal) {
          successModal.classList.add('hidden');
        }
      });
      
      // 关卡输入框限制
      levelInput.addEventListener('input', () => {
        let value = parseInt(levelInput.value) || 1;
        value = Math.max(1, Math.min(GAME_CONFIG.MAX_LEVELS, value));
        levelInput.value = value;
      });
    }
    
    // 初始化游戏
    document.addEventListener('DOMContentLoaded', () => {
      setupEventListeners();
      initGame(1);
    });
  </script>
</body>
</html>
这家伙太懒了,什么也没留下。

最新回复 (0)
全部楼主

你可以在 登录注册 后,对此帖发表评论!

返回