<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://new.pvzhe.wiki/w/%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90?action=history&amp;feed=atom</id>
	<title>微件:推箱子 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://new.pvzhe.wiki/w/%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90?action=history&amp;feed=atom"/>
	<link rel="alternate" type="text/html" href="https://new.pvzhe.wiki/w/%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90?action=history"/>
	<updated>2026-07-26T17:26:32Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://new.pvzhe.wiki/index.php?title=%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90&amp;diff=9977&amp;oldid=prev</id>
		<title>2026年7月19日 (日) 05:30 愤怒的郎朗</title>
		<link rel="alternate" type="text/html" href="https://new.pvzhe.wiki/index.php?title=%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90&amp;diff=9977&amp;oldid=prev"/>
		<updated>2026-07-19T05:30:18Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://new.pvzhe.wiki/index.php?title=%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90&amp;amp;diff=9977&amp;amp;oldid=9975&quot;&gt;显示更改&lt;/a&gt;</summary>
		<author><name>愤怒的郎朗</name></author>
	</entry>
	<entry>
		<id>https://new.pvzhe.wiki/index.php?title=%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90&amp;diff=9975&amp;oldid=prev</id>
		<title>愤怒的郎朗：​创建页面，内容为“&lt;includeonly&gt; &lt;div class=&quot;tuixiangzi-widget&quot;&gt; &lt;!DOCTYPE html&gt; &lt;html lang=&quot;zh&quot;&gt; &lt;head&gt;     &lt;meta charset=&quot;UTF-8&quot;&gt;     &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0, user-scalable=no&quot;&gt;     &lt;title&gt;推箱子 📦&lt;/title&gt;     &lt;style&gt;         * { margin: 0; padding: 0; box-sizing: border-box; }         body {             display: flex;             justify-content: center;             align-items: center;             min-height: 100vh;…”</title>
		<link rel="alternate" type="text/html" href="https://new.pvzhe.wiki/index.php?title=%E5%BE%AE%E4%BB%B6:%E6%8E%A8%E7%AE%B1%E5%AD%90&amp;diff=9975&amp;oldid=prev"/>
		<updated>2026-07-19T05:25:13Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“&amp;lt;includeonly&amp;gt; &amp;lt;div class=&amp;quot;tuixiangzi-widget&amp;quot;&amp;gt; &amp;lt;!DOCTYPE html&amp;gt; &amp;lt;html lang=&amp;quot;zh&amp;quot;&amp;gt; &amp;lt;head&amp;gt;     &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;     &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0, user-scalable=no&amp;quot;&amp;gt;     &amp;lt;title&amp;gt;推箱子 📦&amp;lt;/title&amp;gt;     &amp;lt;style&amp;gt;         * { margin: 0; padding: 0; box-sizing: border-box; }         body {             display: flex;             justify-content: center;             align-items: center;             min-height: 100vh;…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;includeonly&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;tuixiangzi-widget&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;zh&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0, user-scalable=no&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;推箱子 📦&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
        * { margin: 0; padding: 0; box-sizing: border-box; }&lt;br /&gt;
        body {&lt;br /&gt;
            display: flex;&lt;br /&gt;
            justify-content: center;&lt;br /&gt;
            align-items: center;&lt;br /&gt;
            min-height: 100vh;&lt;br /&gt;
            background: #0f0e17;&lt;br /&gt;
            font-family: &amp;#039;Arial&amp;#039;, sans-serif;&lt;br /&gt;
        }&lt;br /&gt;
        .container {&lt;br /&gt;
            background: #1a1a2e;&lt;br /&gt;
            padding: 25px 30px 30px;&lt;br /&gt;
            border-radius: 40px;&lt;br /&gt;
            box-shadow: 0 20px 40px rgba(0,0,0,0.7);&lt;br /&gt;
            text-align: center;&lt;br /&gt;
        }&lt;br /&gt;
        canvas {&lt;br /&gt;
            display: block;&lt;br /&gt;
            margin: 0 auto;&lt;br /&gt;
            background: #0a0a1a;&lt;br /&gt;
            border-radius: 20px;&lt;br /&gt;
            border: 3px solid #2d2d44;&lt;br /&gt;
            max-width: 100%;&lt;br /&gt;
            height: auto;&lt;br /&gt;
            touch-action: none;&lt;br /&gt;
        }&lt;br /&gt;
        .info {&lt;br /&gt;
            display: flex;&lt;br /&gt;
            justify-content: space-between;&lt;br /&gt;
            align-items: center;&lt;br /&gt;
            margin-top: 15px;&lt;br /&gt;
            color: #e0e0e0;&lt;br /&gt;
            font-weight: bold;&lt;br /&gt;
            font-size: 18px;&lt;br /&gt;
            flex-wrap: wrap;&lt;br /&gt;
            gap: 12px;&lt;br /&gt;
        }&lt;br /&gt;
        .stat-box {&lt;br /&gt;
            background: #0a0a1a;&lt;br /&gt;
            padding: 6px 20px;&lt;br /&gt;
            border-radius: 30px;&lt;br /&gt;
            border: 2px solid #4a4a6a;&lt;br /&gt;
        }&lt;br /&gt;
        .stat-box.level { border-color: #fbbf24; color: #fbbf24; }&lt;br /&gt;
        .stat-box.moves { border-color: #60a5fa; color: #60a5fa; }&lt;br /&gt;
        button {&lt;br /&gt;
            background: #7c3aed;&lt;br /&gt;
            border: none;&lt;br /&gt;
            padding: 8px 28px;&lt;br /&gt;
            border-radius: 50px;&lt;br /&gt;
            font-size: 16px;&lt;br /&gt;
            font-weight: bold;&lt;br /&gt;
            color: white;&lt;br /&gt;
            cursor: pointer;&lt;br /&gt;
            transition: 0.1s;&lt;br /&gt;
            box-shadow: 0 4px 0 #5b21b6;&lt;br /&gt;
        }&lt;br /&gt;
        button:active { transform: translateY(4px); box-shadow: none; }&lt;br /&gt;
        .hint { color: #5a4a7a; font-size: 13px; margin-top: 6px; }&lt;br /&gt;
        .controls-hint {&lt;br /&gt;
            display: flex;&lt;br /&gt;
            gap: 10px;&lt;br /&gt;
            justify-content: center;&lt;br /&gt;
            color: #6b6b8a;&lt;br /&gt;
            font-size: 13px;&lt;br /&gt;
            margin-top: 4px;&lt;br /&gt;
        }&lt;br /&gt;
        .controls-hint span { background: #1a1a2e; padding: 2px 12px; border-radius: 10px; }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;canvas id=&amp;quot;gameCanvas&amp;quot; width=&amp;quot;400&amp;quot; height=&amp;quot;400&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;info&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;stat-box level&amp;quot;&amp;gt;📦 关卡 &amp;lt;span id=&amp;quot;levelDisplay&amp;quot;&amp;gt;1&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;stat-box moves&amp;quot;&amp;gt;🚶 步数 &amp;lt;span id=&amp;quot;movesDisplay&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;button id=&amp;quot;restartBtn&amp;quot;&amp;gt;🔄 重新开始&amp;lt;/button&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;hint&amp;quot;&amp;gt;🎯 将所有箱子推到 &amp;lt;span style=&amp;quot;color:#fbbf24;&amp;quot;&amp;gt;★&amp;lt;/span&amp;gt; 目标位置&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;controls-hint&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;span&amp;gt;⬆&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;⬇&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;⬅&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;➡&amp;lt;/span&amp;gt;&lt;br /&gt;
        &amp;lt;span style=&amp;quot;color:#4a4a6a;&amp;quot;&amp;gt;或滑动屏幕&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
    (function() {&lt;br /&gt;
        const canvas = document.getElementById(&amp;#039;gameCanvas&amp;#039;);&lt;br /&gt;
        const ctx = canvas.getContext(&amp;#039;2d&amp;#039;);&lt;br /&gt;
        const levelSpan = document.getElementById(&amp;#039;levelDisplay&amp;#039;);&lt;br /&gt;
        const movesSpan = document.getElementById(&amp;#039;movesDisplay&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
        const CELL = 40;&lt;br /&gt;
        const COLS = 10;&lt;br /&gt;
        const ROWS = 10;&lt;br /&gt;
        const W = COLS * CELL;&lt;br /&gt;
        const H = ROWS * CELL;&lt;br /&gt;
&lt;br /&gt;
        // 边缘边界（箱子不能出现在这个范围内）&lt;br /&gt;
        const EDGE_MARGIN = 2; // 距离边界至少2格&lt;br /&gt;
&lt;br /&gt;
        // 游戏状态&lt;br /&gt;
        let level = 1;&lt;br /&gt;
        let moves = 0;&lt;br /&gt;
        let gameOver = false;&lt;br /&gt;
        let player = { x: 1, y: 1 };&lt;br /&gt;
        let boxes = [];&lt;br /&gt;
        let targets = [];&lt;br /&gt;
        let walls = [];&lt;br /&gt;
        let animationId = null;&lt;br /&gt;
&lt;br /&gt;
        // ---- 检查位置是否在内部区域（不在边缘） ----&lt;br /&gt;
        function isInsideArea(x, y) {&lt;br /&gt;
            return x &amp;gt;= EDGE_MARGIN &amp;amp;&amp;amp; x &amp;lt; COLS - EDGE_MARGIN &amp;amp;&amp;amp;&lt;br /&gt;
                   y &amp;gt;= EDGE_MARGIN &amp;amp;&amp;amp; y &amp;lt; ROWS - EDGE_MARGIN;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 检查一个位置是否可通行 ----&lt;br /&gt;
        function isWalkable(x, y) {&lt;br /&gt;
            if (x &amp;lt; 0 || x &amp;gt;= COLS || y &amp;lt; 0 || y &amp;gt;= ROWS) return false;&lt;br /&gt;
            if (walls.some(w =&amp;gt; w.x === x &amp;amp;&amp;amp; w.y === y)) return false;&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 检查箱子是否在死角 ----&lt;br /&gt;
        function isBoxInDeadEnd(bx, by) {&lt;br /&gt;
            const dirs = [[0, -1], [0, 1], [-1, 0], [1, 0]];&lt;br /&gt;
            let blockedDirections = 0;&lt;br /&gt;
&lt;br /&gt;
            for (const [dx, dy] of dirs) {&lt;br /&gt;
                const nx = bx + dx;&lt;br /&gt;
                const ny = by + dy;&lt;br /&gt;
                if (!isWalkable(nx, ny)) {&lt;br /&gt;
                    blockedDirections++;&lt;br /&gt;
                } else {&lt;br /&gt;
                    const nx2 = bx + dx * 2;&lt;br /&gt;
                    const ny2 = by + dy * 2;&lt;br /&gt;
                    if (!isWalkable(nx2, ny2) || boxes.some(b =&amp;gt; b.x === nx2 &amp;amp;&amp;amp; b.y === ny2)) {&lt;br /&gt;
                        blockedDirections++;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            return blockedDirections &amp;gt;= 3;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 检查箱子是否可到达目标 ----&lt;br /&gt;
        function canBoxReachTarget(boxesList, targetsList) {&lt;br /&gt;
            for (const box of boxesList) {&lt;br /&gt;
                if (targetsList.some(t =&amp;gt; t.x === box.x &amp;amp;&amp;amp; t.y === box.y)) continue;&lt;br /&gt;
                if (isBoxInDeadEnd(box.x, box.y)) return false;&lt;br /&gt;
&lt;br /&gt;
                let hasReachableTarget = false;&lt;br /&gt;
                for (const target of targetsList) {&lt;br /&gt;
                    const dist = Math.abs(box.x - target.x) + Math.abs(box.y - target.y);&lt;br /&gt;
                    if (dist &amp;lt; 6) {&lt;br /&gt;
                        hasReachableTarget = true;&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                if (!hasReachableTarget) return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 生成关卡 ----&lt;br /&gt;
        function generateLevel(lvl) {&lt;br /&gt;
            let attempts = 0;&lt;br /&gt;
            let valid = false;&lt;br /&gt;
&lt;br /&gt;
            while (!valid &amp;amp;&amp;amp; attempts &amp;lt; 100) {&lt;br /&gt;
                attempts++;&lt;br /&gt;
                walls = [];&lt;br /&gt;
                boxes = [];&lt;br /&gt;
                targets = [];&lt;br /&gt;
&lt;br /&gt;
                // 基础边界墙&lt;br /&gt;
                for (let i = 0; i &amp;lt; COLS; i++) {&lt;br /&gt;
                    walls.push({ x: i, y: 0 });&lt;br /&gt;
                    walls.push({ x: i, y: ROWS - 1 });&lt;br /&gt;
                }&lt;br /&gt;
                for (let i = 0; i &amp;lt; ROWS; i++) {&lt;br /&gt;
                    walls.push({ x: 0, y: i });&lt;br /&gt;
                    walls.push({ x: COLS - 1, y: i });&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                // 生成内部障碍物（只在内部区域）&lt;br /&gt;
                const numWalls = 3 + (lvl % 4);&lt;br /&gt;
                for (let i = 0; i &amp;lt; numWalls; i++) {&lt;br /&gt;
                    let wx, wy;&lt;br /&gt;
                    let attempts2 = 0;&lt;br /&gt;
                    do {&lt;br /&gt;
                        wx = EDGE_MARGIN + 1 + Math.floor(Math.random() * (COLS - EDGE_MARGIN * 2 - 2));&lt;br /&gt;
                        wy = EDGE_MARGIN + 1 + Math.floor(Math.random() * (ROWS - EDGE_MARGIN * 2 - 2));&lt;br /&gt;
                        attempts2++;&lt;br /&gt;
                    } while (attempts2 &amp;lt; 30 &amp;amp;&amp;amp; (&lt;br /&gt;
                        (wx === 1 &amp;amp;&amp;amp; wy === 1) ||&lt;br /&gt;
                        walls.some(w =&amp;gt; w.x === wx &amp;amp;&amp;amp; w.y === wy)&lt;br /&gt;
                    ));&lt;br /&gt;
                    if (attempts2 &amp;lt; 30) {&lt;br /&gt;
                        walls.push({ x: wx, y: wy });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                // 生成目标和箱子（都在内部区域）&lt;br /&gt;
                const numBoxes = Math.min(3 + Math.floor(lvl / 2), 4);&lt;br /&gt;
&lt;br /&gt;
                // 先生成目标位置&lt;br /&gt;
                for (let i = 0; i &amp;lt; numBoxes; i++) {&lt;br /&gt;
                    let tx, ty;&lt;br /&gt;
                    let attempts2 = 0;&lt;br /&gt;
                    do {&lt;br /&gt;
                        tx = EDGE_MARGIN + Math.floor(Math.random() * (COLS - EDGE_MARGIN * 2));&lt;br /&gt;
                        ty = EDGE_MARGIN + Math.floor(Math.random() * (ROWS - EDGE_MARGIN * 2));&lt;br /&gt;
                        attempts2++;&lt;br /&gt;
                    } while (attempts2 &amp;lt; 80 &amp;amp;&amp;amp; (&lt;br /&gt;
                        (tx === 1 &amp;amp;&amp;amp; ty === 1) ||&lt;br /&gt;
                        walls.some(w =&amp;gt; w.x === tx &amp;amp;&amp;amp; w.y === ty) ||&lt;br /&gt;
                        targets.some(t =&amp;gt; t.x === tx &amp;amp;&amp;amp; t.y === ty) ||&lt;br /&gt;
                        !isInsideArea(tx, ty) ||&lt;br /&gt;
                        (isWalkable(tx - 1, ty) + isWalkable(tx + 1, ty) +&lt;br /&gt;
                         isWalkable(tx, ty - 1) + isWalkable(tx, ty + 1) &amp;lt; 2)&lt;br /&gt;
                    ));&lt;br /&gt;
                    if (attempts2 &amp;lt; 80) {&lt;br /&gt;
                        targets.push({ x: tx, y: ty });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (targets.length &amp;lt; numBoxes) continue;&lt;br /&gt;
&lt;br /&gt;
                // 生成箱子（在目标周围）&lt;br /&gt;
                for (let i = 0; i &amp;lt; targets.length; i++) {&lt;br /&gt;
                    let bx, by;&lt;br /&gt;
                    let found = false;&lt;br /&gt;
                    const target = targets[i];&lt;br /&gt;
&lt;br /&gt;
                    // 在目标周围4个方向寻找&lt;br /&gt;
                    const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]];&lt;br /&gt;
                    for (let j = dirs.length - 1; j &amp;gt; 0; j--) {&lt;br /&gt;
                        const k = Math.floor(Math.random() * (j + 1));&lt;br /&gt;
                        [dirs[j], dirs[k]] = [dirs[k], dirs[j]];&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    for (const [dx, dy] of dirs) {&lt;br /&gt;
                        const nx = target.x + dx;&lt;br /&gt;
                        const ny = target.y + dy;&lt;br /&gt;
                        if (isInsideArea(nx, ny) &amp;amp;&amp;amp;&lt;br /&gt;
                            isWalkable(nx, ny) &amp;amp;&amp;amp;&lt;br /&gt;
                            !boxes.some(b =&amp;gt; b.x === nx &amp;amp;&amp;amp; b.y === ny) &amp;amp;&amp;amp;&lt;br /&gt;
                            !targets.some(t =&amp;gt; t.x === nx &amp;amp;&amp;amp; t.y === ny) &amp;amp;&amp;amp;&lt;br /&gt;
                            !(nx === 1 &amp;amp;&amp;amp; ny === 1) &amp;amp;&amp;amp;&lt;br /&gt;
                            !isBoxInDeadEnd(nx, ny)) {&lt;br /&gt;
                            bx = nx;&lt;br /&gt;
                            by = ny;&lt;br /&gt;
                            found = true;&lt;br /&gt;
                            break;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    // 如果没找到，扩大搜索范围&lt;br /&gt;
                    if (!found) {&lt;br /&gt;
                        for (let dx = -3; dx &amp;lt;= 3; dx++) {&lt;br /&gt;
                            for (let dy = -3; dy &amp;lt;= 3; dy++) {&lt;br /&gt;
                                if (dx === 0 &amp;amp;&amp;amp; dy === 0) continue;&lt;br /&gt;
                                const nx = target.x + dx;&lt;br /&gt;
                                const ny = target.y + dy;&lt;br /&gt;
                                if (isInsideArea(nx, ny) &amp;amp;&amp;amp;&lt;br /&gt;
                                    isWalkable(nx, ny) &amp;amp;&amp;amp;&lt;br /&gt;
                                    !boxes.some(b =&amp;gt; b.x === nx &amp;amp;&amp;amp; b.y === ny) &amp;amp;&amp;amp;&lt;br /&gt;
                                    !targets.some(t =&amp;gt; t.x === nx &amp;amp;&amp;amp; t.y === ny) &amp;amp;&amp;amp;&lt;br /&gt;
                                    !(nx === 1 &amp;amp;&amp;amp; ny === 1) &amp;amp;&amp;amp;&lt;br /&gt;
                                    !isBoxInDeadEnd(nx, ny)) {&lt;br /&gt;
                                    bx = nx;&lt;br /&gt;
                                    by = ny;&lt;br /&gt;
                                    found = true;&lt;br /&gt;
                                    break;&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
                            if (found) break;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    if (found) {&lt;br /&gt;
                        boxes.push({ x: bx, y: by });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                if (boxes.length &amp;lt; targets.length) continue;&lt;br /&gt;
&lt;br /&gt;
                // 检查所有箱子是否在内部区域&lt;br /&gt;
                let allInside = true;&lt;br /&gt;
                for (const box of boxes) {&lt;br /&gt;
                    if (!isInsideArea(box.x, box.y)) {&lt;br /&gt;
                        allInside = false;&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                if (!allInside) continue;&lt;br /&gt;
&lt;br /&gt;
                // 检查箱子是否在死角&lt;br /&gt;
                let hasDeadEnd = false;&lt;br /&gt;
                for (const box of boxes) {&lt;br /&gt;
                    if (isBoxInDeadEnd(box.x, box.y)) {&lt;br /&gt;
                        hasDeadEnd = true;&lt;br /&gt;
                        break;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                if (hasDeadEnd) continue;&lt;br /&gt;
&lt;br /&gt;
                // 检查箱子是否可到达目标&lt;br /&gt;
                if (!canBoxReachTarget(boxes, targets)) continue;&lt;br /&gt;
&lt;br /&gt;
                valid = true;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 保底方案：使用预设关卡&lt;br /&gt;
            if (!valid) {&lt;br /&gt;
                walls = [];&lt;br /&gt;
                boxes = [];&lt;br /&gt;
                targets = [];&lt;br /&gt;
                for (let i = 0; i &amp;lt; COLS; i++) {&lt;br /&gt;
                    walls.push({ x: i, y: 0 });&lt;br /&gt;
                    walls.push({ x: i, y: ROWS - 1 });&lt;br /&gt;
                }&lt;br /&gt;
                for (let i = 0; i &amp;lt; ROWS; i++) {&lt;br /&gt;
                    walls.push({ x: 0, y: i });&lt;br /&gt;
                    walls.push({ x: COLS - 1, y: i });&lt;br /&gt;
                }&lt;br /&gt;
                // 添加一些内部墙&lt;br /&gt;
                const presetWalls = [[3, 2], [6, 2], [2, 5], [7, 5], [4, 7]];&lt;br /&gt;
                for (const [wx, wy] of presetWalls) {&lt;br /&gt;
                    if (isInsideArea(wx, wy)) {&lt;br /&gt;
                        walls.push({ x: wx, y: wy });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                // 预设箱子和目标（都在内部区域）&lt;br /&gt;
                const presetBoxes = [[3, 3], [5, 4], [4, 6]];&lt;br /&gt;
                const presetTargets = [[6, 3], [3, 5], [7, 6]];&lt;br /&gt;
                for (const [bx, by] of presetBoxes) {&lt;br /&gt;
                    if (isInsideArea(bx, by) &amp;amp;&amp;amp; isWalkable(bx, by) &amp;amp;&amp;amp;&lt;br /&gt;
                        !boxes.some(b =&amp;gt; b.x === bx &amp;amp;&amp;amp; b.y === by) &amp;amp;&amp;amp;&lt;br /&gt;
                        !targets.some(t =&amp;gt; t.x === bx &amp;amp;&amp;amp; t.y === by)) {&lt;br /&gt;
                        boxes.push({ x: bx, y: by });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                for (const [tx, ty] of presetTargets) {&lt;br /&gt;
                    if (isInsideArea(tx, ty) &amp;amp;&amp;amp; isWalkable(tx, ty) &amp;amp;&amp;amp;&lt;br /&gt;
                        !targets.some(t =&amp;gt; t.x === tx &amp;amp;&amp;amp; t.y === ty)) {&lt;br /&gt;
                        targets.push({ x: tx, y: ty });&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 确保玩家在(1,1)且该位置未被占用&lt;br /&gt;
            player.x = 1;&lt;br /&gt;
            player.y = 1;&lt;br /&gt;
            for (const box of boxes) {&lt;br /&gt;
                if (box.x === 1 &amp;amp;&amp;amp; box.y === 1) {&lt;br /&gt;
                    for (let dx = -1; dx &amp;lt;= 1; dx++) {&lt;br /&gt;
                        for (let dy = -1; dy &amp;lt;= 1; dy++) {&lt;br /&gt;
                            const nx = 1 + dx;&lt;br /&gt;
                            const ny = 1 + dy;&lt;br /&gt;
                            if (isInsideArea(nx, ny) &amp;amp;&amp;amp; isWalkable(nx, ny) &amp;amp;&amp;amp;&lt;br /&gt;
                                !boxes.some(b =&amp;gt; b.x === nx &amp;amp;&amp;amp; b.y === ny) &amp;amp;&amp;amp;&lt;br /&gt;
                                !targets.some(t =&amp;gt; t.x === nx &amp;amp;&amp;amp; t.y === ny)) {&lt;br /&gt;
                                box.x = nx;&lt;br /&gt;
                                box.y = ny;&lt;br /&gt;
                                break;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            moves = 0;&lt;br /&gt;
            gameOver = false;&lt;br /&gt;
            updateUI();&lt;br /&gt;
            draw();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function updateUI() {&lt;br /&gt;
            levelSpan.textContent = level;&lt;br /&gt;
            movesSpan.textContent = moves;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 检查是否胜利 ----&lt;br /&gt;
        function checkWin() {&lt;br /&gt;
            for (const box of boxes) {&lt;br /&gt;
                const onTarget = targets.some(t =&amp;gt; t.x === box.x &amp;amp;&amp;amp; t.y === box.y);&lt;br /&gt;
                if (!onTarget) return false;&lt;br /&gt;
            }&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 移动 ----&lt;br /&gt;
        function movePlayer(dx, dy) {&lt;br /&gt;
            if (gameOver) return;&lt;br /&gt;
&lt;br /&gt;
            const newX = player.x + dx;&lt;br /&gt;
            const newY = player.y + dy;&lt;br /&gt;
&lt;br /&gt;
            if (walls.some(w =&amp;gt; w.x === newX &amp;amp;&amp;amp; w.y === newY)) return;&lt;br /&gt;
&lt;br /&gt;
            const boxIndex = boxes.findIndex(b =&amp;gt; b.x === newX &amp;amp;&amp;amp; b.y === newY);&lt;br /&gt;
            if (boxIndex !== -1) {&lt;br /&gt;
                const boxNewX = newX + dx;&lt;br /&gt;
                const boxNewY = newY + dy;&lt;br /&gt;
                if (walls.some(w =&amp;gt; w.x === boxNewX &amp;amp;&amp;amp; w.y === boxNewY)) return;&lt;br /&gt;
                if (boxes.some(b =&amp;gt; b.x === boxNewX &amp;amp;&amp;amp; b.y === boxNewY)) return;&lt;br /&gt;
                boxes[boxIndex].x = boxNewX;&lt;br /&gt;
                boxes[boxIndex].y = boxNewY;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            player.x = newX;&lt;br /&gt;
            player.y = newY;&lt;br /&gt;
            moves++;&lt;br /&gt;
            updateUI();&lt;br /&gt;
            draw();&lt;br /&gt;
&lt;br /&gt;
            if (checkWin()) {&lt;br /&gt;
                gameOver = true;&lt;br /&gt;
                setTimeout(() =&amp;gt; {&lt;br /&gt;
                    level++;&lt;br /&gt;
                    generateLevel(level);&lt;br /&gt;
                }, 1000);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 绘制 ----&lt;br /&gt;
        function draw() {&lt;br /&gt;
            ctx.clearRect(0, 0, W, H);&lt;br /&gt;
&lt;br /&gt;
            // 绘制网格&lt;br /&gt;
            for (let r = 0; r &amp;lt; ROWS; r++) {&lt;br /&gt;
                for (let c = 0; c &amp;lt; COLS; c++) {&lt;br /&gt;
                    ctx.fillStyle = (r + c) % 2 === 0 ? &amp;#039;#0f0f23&amp;#039; : &amp;#039;#14142e&amp;#039;;&lt;br /&gt;
                    ctx.fillRect(c * CELL, r * CELL, CELL, CELL);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 绘制墙壁&lt;br /&gt;
            for (const wall of walls) {&lt;br /&gt;
                ctx.fillStyle = &amp;#039;#2d2d4a&amp;#039;;&lt;br /&gt;
                ctx.shadowColor = &amp;#039;#4a4a6a&amp;#039;;&lt;br /&gt;
                ctx.shadowBlur = 5;&lt;br /&gt;
                ctx.fillRect(wall.x * CELL + 1, wall.y * CELL + 1, CELL - 2, CELL - 2);&lt;br /&gt;
            }&lt;br /&gt;
            ctx.shadowBlur = 0;&lt;br /&gt;
&lt;br /&gt;
            // 绘制目标&lt;br /&gt;
            for (const target of targets) {&lt;br /&gt;
                ctx.fillStyle = &amp;#039;rgba(251, 191, 36, 0.15)&amp;#039;;&lt;br /&gt;
                ctx.fillRect(target.x * CELL + 2, target.y * CELL + 2, CELL - 4, CELL - 4);&lt;br /&gt;
                ctx.fillStyle = &amp;#039;#fbbf24&amp;#039;;&lt;br /&gt;
                ctx.font = &amp;#039;20px Arial&amp;#039;;&lt;br /&gt;
                ctx.textAlign = &amp;#039;center&amp;#039;;&lt;br /&gt;
                ctx.textBaseline = &amp;#039;middle&amp;#039;;&lt;br /&gt;
                ctx.fillText(&amp;#039;★&amp;#039;, target.x * CELL + CELL/2, target.y * CELL + CELL/2 + 1);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 绘制箱子&lt;br /&gt;
            for (const box of boxes) {&lt;br /&gt;
                const onTarget = targets.some(t =&amp;gt; t.x === box.x &amp;amp;&amp;amp; t.y === box.y);&lt;br /&gt;
                ctx.fillStyle = onTarget ? &amp;#039;#2cb67d&amp;#039; : &amp;#039;#f25f4c&amp;#039;;&lt;br /&gt;
                ctx.shadowColor = onTarget ? &amp;#039;#2cb67d&amp;#039; : &amp;#039;#f25f4c&amp;#039;;&lt;br /&gt;
                ctx.shadowBlur = 15;&lt;br /&gt;
                ctx.fillRect(box.x * CELL + 3, box.y * CELL + 3, CELL - 6, CELL - 6);&lt;br /&gt;
                ctx.shadowBlur = 0;&lt;br /&gt;
                ctx.fillStyle = onTarget ? &amp;#039;rgba(255,255,255,0.2)&amp;#039; : &amp;#039;rgba(255,255,255,0.15)&amp;#039;;&lt;br /&gt;
                ctx.fillRect(box.x * CELL + 6, box.y * CELL + 6, CELL - 12, 4);&lt;br /&gt;
                ctx.fillRect(box.x * CELL + 6, box.y * CELL + CELL - 10, CELL - 12, 4);&lt;br /&gt;
                ctx.fillRect(box.x * CELL + 6, box.y * CELL + 6, 4, CELL - 12);&lt;br /&gt;
                ctx.fillRect(box.x * CELL + CELL - 10, box.y * CELL + 6, 4, CELL - 12);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 绘制玩家&lt;br /&gt;
            ctx.fillStyle = &amp;#039;#60a5fa&amp;#039;;&lt;br /&gt;
            ctx.shadowColor = &amp;#039;#60a5fa&amp;#039;;&lt;br /&gt;
            ctx.shadowBlur = 20;&lt;br /&gt;
            ctx.beginPath();&lt;br /&gt;
            ctx.arc(player.x * CELL + CELL/2, player.y * CELL + CELL/2, CELL * 0.35, 0, 2*Math.PI);&lt;br /&gt;
            ctx.fill();&lt;br /&gt;
            ctx.shadowBlur = 0;&lt;br /&gt;
            ctx.fillStyle = &amp;#039;white&amp;#039;;&lt;br /&gt;
            ctx.beginPath();&lt;br /&gt;
            ctx.arc(player.x * CELL + CELL/2 - 5, player.y * CELL + CELL/2 - 4, 4, 0, 2*Math.PI);&lt;br /&gt;
            ctx.fill();&lt;br /&gt;
            ctx.beginPath();&lt;br /&gt;
            ctx.arc(player.x * CELL + CELL/2 + 5, player.y * CELL + CELL/2 - 4, 4, 0, 2*Math.PI);&lt;br /&gt;
            ctx.fill();&lt;br /&gt;
            ctx.fillStyle = &amp;#039;#0a0a1a&amp;#039;;&lt;br /&gt;
            ctx.beginPath();&lt;br /&gt;
            ctx.arc(player.x * CELL + CELL/2 - 6, player.y * CELL + CELL/2 - 5, 2, 0, 2*Math.PI);&lt;br /&gt;
            ctx.fill();&lt;br /&gt;
            ctx.beginPath();&lt;br /&gt;
            ctx.arc(player.x * CELL + CELL/2 + 4, player.y * CELL + CELL/2 - 5, 2, 0, 2*Math.PI);&lt;br /&gt;
            ctx.fill();&lt;br /&gt;
&lt;br /&gt;
            // 胜利信息&lt;br /&gt;
            if (gameOver) {&lt;br /&gt;
                ctx.fillStyle = &amp;#039;rgba(0,0,0,0.4)&amp;#039;;&lt;br /&gt;
                ctx.fillRect(0, 0, W, H);&lt;br /&gt;
                ctx.fillStyle = &amp;#039;#fbbf24&amp;#039;;&lt;br /&gt;
                ctx.font = &amp;#039;bold 28px Arial&amp;#039;;&lt;br /&gt;
                ctx.textAlign = &amp;#039;center&amp;#039;;&lt;br /&gt;
                ctx.textBaseline = &amp;#039;middle&amp;#039;;&lt;br /&gt;
                ctx.fillText(&amp;#039;🎉 过关！&amp;#039;, W/2, H/2 - 10);&lt;br /&gt;
                ctx.fillStyle = &amp;#039;#e0e0e0&amp;#039;;&lt;br /&gt;
                ctx.font = &amp;#039;16px Arial&amp;#039;;&lt;br /&gt;
                ctx.fillText(`进入第 ${level + 1} 关`, W/2, H/2 + 35);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 显示剩余箱子&lt;br /&gt;
            ctx.fillStyle = &amp;#039;rgba(255,255,255,0.08)&amp;#039;;&lt;br /&gt;
            ctx.font = &amp;#039;12px Arial&amp;#039;;&lt;br /&gt;
            ctx.textAlign = &amp;#039;left&amp;#039;;&lt;br /&gt;
            ctx.textBaseline = &amp;#039;bottom&amp;#039;;&lt;br /&gt;
            const remaining = boxes.filter(b =&amp;gt; !targets.some(t =&amp;gt; t.x === b.x &amp;amp;&amp;amp; t.y === b.y)).length;&lt;br /&gt;
            ctx.fillText(`📦 ${remaining} / ${boxes.length}`, 8, H - 6);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function gameLoop() {&lt;br /&gt;
            draw();&lt;br /&gt;
            animationId = requestAnimationFrame(gameLoop);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // ---- 事件绑定 ----&lt;br /&gt;
        document.addEventListener(&amp;#039;keydown&amp;#039;, (e) =&amp;gt; {&lt;br /&gt;
            const key = e.key;&lt;br /&gt;
            if (key === &amp;#039;ArrowUp&amp;#039;) { e.preventDefault(); movePlayer(0, -1); }&lt;br /&gt;
            else if (key === &amp;#039;ArrowDown&amp;#039;) { e.preventDefault(); movePlayer(0, 1); }&lt;br /&gt;
            else if (key === &amp;#039;ArrowLeft&amp;#039;) { e.preventDefault(); movePlayer(-1, 0); }&lt;br /&gt;
            else if (key === &amp;#039;ArrowRight&amp;#039;) { e.preventDefault(); movePlayer(1, 0); }&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        let touchStartX = 0, touchStartY = 0;&lt;br /&gt;
        canvas.addEventListener(&amp;#039;touchstart&amp;#039;, (e) =&amp;gt; {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            const touch = e.touches[0];&lt;br /&gt;
            touchStartX = touch.clientX;&lt;br /&gt;
            touchStartY = touch.clientY;&lt;br /&gt;
        }, { passive: false });&lt;br /&gt;
&lt;br /&gt;
        canvas.addEventListener(&amp;#039;touchmove&amp;#039;, (e) =&amp;gt; {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            if (!touchStartX || !touchStartY) return;&lt;br /&gt;
            const touch = e.touches[0];&lt;br /&gt;
            const dx = touch.clientX - touchStartX;&lt;br /&gt;
            const dy = touch.clientY - touchStartY;&lt;br /&gt;
            if (Math.abs(dx) &amp;lt; 15 &amp;amp;&amp;amp; Math.abs(dy) &amp;lt; 15) return;&lt;br /&gt;
            if (Math.abs(dx) &amp;gt; Math.abs(dy)) {&lt;br /&gt;
                movePlayer(dx &amp;gt; 0 ? 1 : -1, 0);&lt;br /&gt;
            } else {&lt;br /&gt;
                movePlayer(0, dy &amp;gt; 0 ? 1 : -1);&lt;br /&gt;
            }&lt;br /&gt;
            touchStartX = touch.clientX;&lt;br /&gt;
            touchStartY = touch.clientY;&lt;br /&gt;
        }, { passive: false });&lt;br /&gt;
&lt;br /&gt;
        canvas.addEventListener(&amp;#039;touchend&amp;#039;, (e) =&amp;gt; {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            touchStartX = 0;&lt;br /&gt;
            touchStartY = 0;&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        document.getElementById(&amp;#039;restartBtn&amp;#039;).addEventListener(&amp;#039;click&amp;#039;, () =&amp;gt; {&lt;br /&gt;
            generateLevel(level);&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        // 启动&lt;br /&gt;
        generateLevel(1);&lt;br /&gt;
        gameLoop();&lt;br /&gt;
    })();&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/includeonly&amp;gt;&lt;/div&gt;</summary>
		<author><name>愤怒的郎朗</name></author>
	</entry>
</feed>