s.type === wall || s.type === gate)) return;\n\n p.x = nx;\n p.y = ny;\n}\n\nonInput(\"w\", () => tryMovePlayer(0, -1));\nonInput(\"s\", () => tryMovePlayer(0, 1));\nonInput(\"a\", () => tryMovePlayer(-1, 0));\nonInput(\"d\", () => tryMovePlayer(1, 0));\n\nfunction tryMoveGate() {\n if (gameOver) return;\n\n const p = getFirst(player);\n const g = getFirst(gate);\n if (!p || !g) return;\n\n const w = width();\n const h = height();\n\n function isFree(x, y) {\n if (x < 0 || x >= w || y < 0 || y >= h) return false;\n const tile = getTile(x, y);\n return !tile.some(s => s.type === wall || s.type === gate);\n }\n\n let dx = g.x - p.x;\n let dy = g.y - p.y;\n if (dx > 1) dx = 1;\n if (dx < -1) dx = -1;\n if (dy > 1) dy = 1;\n if (dy < -1) dy = -1;\n\n const candidates = [];\n\n if (dx !== 0 || dy !== 0) {\n candidates.push({ x: g.x + dx, y: g.y + dy });\n }\n\n const slips = [];\n if (dx !== 0) {\n slips.push({ x: g.x, y: g.y + 1 });\n slips.push({ x: g.x, y: g.y - 1 });\n }\n if (dy !== 0) {\n slips.push({ x: g.x + 1, y: g.y });\n slips.push({ x: g.x - 1, y: g.y });\n }\n if (dx === 0 && dy === 0) {\n slips.push(\n { x: g.x + 1, y: g.y },\n { x: g.x - 1, y: g.y },\n { x: g.x, y: g.y + 1 },\n { x: g.x, y: g.y - 1 },\n );\n }\n\n for (let i = slips.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [slips[i], slips[j]] = [slips[j], slips[i]];\n }\n\n candidates.push(...slips);\n\n for (const m of candidates) {\n if (isFree(m.x, m.y)) {\n g.x = m.x;\n g.y = m.y;\n break;\n }\n }\n}\n\nfunction gameStep() {\n if (gameOver) return;\n\n tryMoveGate();\n\n const p = getFirst(player);\n if (!p) return;\n\n getTile(p.x, p.y).forEach(sprite => {\n if (sprite.type === core) {\n sprite.remove();\n hasCore = true;\n clearText();\n addText(\"CORE ACTIVE\", { y: 1, color: color`2` });\n }\n });\n\n if (hasCore) {\n const neighbors = [\n ...getTile(p.x + 1, p.y),\n ...getTile(p.x - 1, p.y),\n ...getTile(p.x, p.y + 1),\n ...getTile(p.x, p.y - 1)\n ];\n if (neighbors.some(s => s.type === gate)) {\n clearText();\n addText(\"WARP COMPLETE\", { y: 4, color: color`3` });\n\n gameOver = true;\n\n setTimeout(() => {\n if (currentLevel < levels.length - 1) {\n currentLevel += 1;\n startLevel(currentLevel);\n } else {\n clearText();\n addText(\"YOU WIN!\", { y: 4, color: color`4` });\n }\n }, 1000);\n }\n }\n}\n\nconst TICK_MS = 150;\nsetInterval(gameStep, TICK_MS);\n\nafterInput(() => {});\n"],"gameName":[0,"Chase The Gate"],"authorName":[0,"Sabhya Aggarwal"],"filename":[0,"Chase-the-Gate"],"isLoggedIn":[0,false],"hearted":[0,false],"data-astro-cid-d4jrbbcn":[0,true]} Gate"],"authorName":[0,"Sabhya Aggarwal"],"filename":[0,"Chase-the-Gate"],"isLoggedIn":[0,false],"hearted":[0,false],"data-astro-cid-d4jrbbcn":[0,true]}" client="load" opts="{"name":"DesktopPlayer","value":true}","value":true}" await-children="">