Download script.js from CommanderLazarus/ufo-maze-runner: direct link, hf CLI and curl.
- Browser
- Download file 9.44 kB
-
https://huggingface.co/spaces/CommanderLazarus/ufo-maze-runner/resolve/main/script.js
- Command line
-
hf download hf://spaces/CommanderLazarus/ufo-maze-runner/script.js
-
curl -L -o script.js https://huggingface.co/spaces/CommanderLazarus/ufo-maze-runner/resolve/main/script.js
9.44 kB
| document.addEventListener('DOMContentLoaded', () => { | |
| const canvas = document.getElementById('maze-canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const timeDisplay = document.getElementById('time'); | |
| const movesDisplay = document.getElementById('moves'); | |
| const difficultySelect = document.getElementById('difficulty'); | |
| const startBtn = document.getElementById('start-btn'); | |
| const upBtn = document.getElementById('up-btn'); | |
| const downBtn = document.getElementById('down-btn'); | |
| const leftBtn = document.getElementById('left-btn'); | |
| const rightBtn = document.getElementById('right-btn'); | |
| // Set canvas size | |
| function resizeCanvas() { | |
| const container = document.getElementById('maze-container'); | |
| const size = Math.min(container.offsetWidth, container.offsetHeight); | |
| canvas.width = size; | |
| canvas.height = size; | |
| } | |
| // Game variables | |
| let maze = []; | |
| let cellSize = 0; | |
| let orientationEnabled = false; | |
| let ufo = { x: 0, y: 0 }; | |
| let exit = { x: 0, y: 0 }; | |
| let moves = 0; | |
| let time = 0; | |
| let timer = null; | |
| let gameRunning = false; | |
| let mazeSize = 25; | |
| // Handle device orientation | |
| function handleOrientation(event) { | |
| if (!gameRunning) return; | |
| const tiltThreshold = 15; // degrees | |
| const beta = event.beta; // front-to-back tilt | |
| const gamma = event.gamma; // left-to-right tilt | |
| if (beta > tiltThreshold) { | |
| moveUfo(0, 1); // tilt forward = move down | |
| } else if (beta < -tiltThreshold) { | |
| moveUfo(0, -1); // tilt backward = move up | |
| } | |
| if (gamma > tiltThreshold) { | |
| moveUfo(1, 0); // tilt right = move right | |
| } else if (gamma < -tiltThreshold) { | |
| moveUfo(-1, 0); // tilt left = move left | |
| } | |
| } | |
| // Initialize game | |
| function initGame() { | |
| resizeCanvas(); | |
| window.addEventListener('resize', resizeCanvas); | |
| // Add device orientation listener | |
| if (window.DeviceOrientationEvent) { | |
| window.addEventListener('deviceorientation', handleOrientation); | |
| } | |
| // Set maze size based on difficulty | |
| switch(difficultySelect.value) { | |
| case 'easy': mazeSize = 15; break; | |
| case 'medium': mazeSize = 25; break; | |
| case 'hard': mazeSize = 35; break; | |
| } | |
| // Generate maze | |
| generateMaze(); | |
| drawMaze(); | |
| // Set up keyboard controls | |
| document.addEventListener('keydown', handleKeyPress); | |
| upBtn.addEventListener('click', () => moveUfo(0, -1)); | |
| downBtn.addEventListener('click', () => moveUfo(0, 1)); | |
| leftBtn.addEventListener('click', () => moveUfo(-1, 0)); | |
| rightBtn.addEventListener('click', () => moveUfo(1, 0)); | |
| // Start button | |
| startBtn.addEventListener('click', startGame); | |
| } | |
| // Generate maze using depth-first search | |
| function generateMaze() { | |
| // Initialize maze grid | |
| maze = Array(mazeSize).fill().map(() => Array(mazeSize).fill(1)); | |
| // Start position (top-left corner) | |
| ufo = { x: 0, y: 0 }; | |
| maze[ufo.y][ufo.x] = 0; | |
| // Exit position (bottom-right corner) | |
| exit = { x: mazeSize - 1, y: mazeSize - 1 }; | |
| // Generate paths | |
| const stack = [{ x: ufo.x, y: ufo.y }]; | |
| const directions = [ | |
| { dx: 1, dy: 0 }, | |
| { dx: -1, dy: 0 }, | |
| { dx: 0, dy: 1 }, | |
| { dx: 0, dy: -1 }, | |
| { dx: 1, dy: 1 }, | |
| { dx: -1, dy: -1 }, | |
| { dx: 1, dy: -1 }, | |
| { dx: -1, dy: 1 } | |
| ]; | |
| while (stack.length > 0) { | |
| const current = stack[stack.length - 1]; | |
| const neighbors = []; | |
| // Find unvisited neighbors | |
| for (const dir of directions) { | |
| // For diagonal directions, make paths longer to prevent too many walls | |
| const step = (Math.abs(dir.dx) + Math.abs(dir.dy) === 2) ? 3 : 2; | |
| const nx = current.x + dir.dx * step; | |
| const ny = current.y + dir.dy * step; | |
| if (nx >= 0 && nx < mazeSize && ny >= 0 && ny < mazeSize && maze[ny][nx] === 1) { | |
| neighbors.push({ x: nx, y: ny, dir }); | |
| } | |
| } | |
| if (neighbors.length > 0) { | |
| const next = neighbors[Math.floor(Math.random() * neighbors.length)]; | |
| // Carve out the path | |
| for (let i = 1; i <= (Math.abs(next.dir.dx) + Math.abs(next.dir.dy) === 2 ? 3 : 2); i++) { | |
| const pathX = current.x + next.dir.dx * i; | |
| const pathY = current.y + next.dir.dy * i; | |
| if (pathX >= 0 && pathX < mazeSize && pathY >= 0 && pathY < mazeSize) { | |
| maze[pathY][pathX] = 0; | |
| } | |
| } | |
| stack.push({ x: next.x, y: next.y }); | |
| } else { | |
| stack.pop(); | |
| } | |
| } | |
| // Ensure exit is reachable | |
| maze[exit.y][exit.x] = 0; | |
| } | |
| // Draw maze on canvas | |
| function drawMaze() { | |
| cellSize = canvas.width / mazeSize; | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Draw walls | |
| ctx.fillStyle = '#374151'; | |
| ctx.shadowColor = 'rgba(0, 0, 0, 0.3)'; | |
| ctx.shadowBlur = 5; | |
| ctx.shadowOffsetX = 2; | |
| ctx.shadowOffsetY = 2; | |
| for (let y = 0; y < mazeSize; y++) { | |
| for (let x = 0; x < mazeSize; x++) { | |
| if (maze[y][x] === 1) { | |
| ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); | |
| } | |
| } | |
| } | |
| // Draw exit | |
| ctx.fillStyle = '#10B981'; | |
| ctx.shadowColor = 'rgba(16, 185, 129, 0.5)'; | |
| ctx.shadowBlur = 10; | |
| ctx.fillRect(exit.x * cellSize, exit.y * cellSize, cellSize, cellSize); | |
| // Draw UFO | |
| drawUfo(); | |
| } | |
| // Draw UFO | |
| function drawUfo() { | |
| const centerX = ufo.x * cellSize + cellSize / 2; | |
| const centerY = ufo.y * cellSize + cellSize / 2; | |
| const radius = cellSize * 0.3; | |
| // UFO body | |
| ctx.beginPath(); | |
| ctx.ellipse(centerX, centerY, radius, radius * 0.6, 0, 0, Math.PI * 2); | |
| ctx.fillStyle = '#7C3AED'; | |
| ctx.shadowColor = 'rgba(124, 58, 237, 0.5)'; | |
| ctx.shadowBlur = 10; | |
| ctx.fill(); | |
| // UFO dome | |
| ctx.beginPath(); | |
| ctx.ellipse(centerX, centerY - radius * 0.2, radius * 0.7, radius * 0.4, 0, 0, Math.PI * 2); | |
| ctx.fillStyle = 'rgba(167, 139, 250, 0.7)'; | |
| ctx.fill(); | |
| // UFO lights | |
| ctx.beginPath(); | |
| for (let i = 0; i < 5; i++) { | |
| const lightX = centerX - radius * 0.6 + i * radius * 0.3; | |
| ctx.arc(lightX, centerY + radius * 0.3, radius * 0.1, 0, Math.PI * 2); | |
| } | |
| ctx.fillStyle = '#F59E0B'; | |
| ctx.shadowColor = 'rgba(245, 158, 11, 0.5)'; | |
| ctx.shadowBlur = 5; | |
| ctx.fill(); | |
| } | |
| // Handle keyboard input | |
| function handleKeyPress(e) { | |
| if (!gameRunning) return; | |
| switch(e.key) { | |
| case 'ArrowUp': moveUfo(0, -1); break; | |
| case 'ArrowDown': moveUfo(0, 1); break; | |
| case 'ArrowLeft': moveUfo(-1, 0); break; | |
| case 'ArrowRight': moveUfo(1, 0); break; | |
| } | |
| } | |
| // Move UFO | |
| function moveUfo(dx, dy) { | |
| if (!gameRunning || (orientationEnabled && dx === 0 && dy === 0)) return; | |
| const newX = ufo.x + dx; | |
| const newY = ufo.y + dy; | |
| // Check if move is valid | |
| if (newX >= 0 && newX < mazeSize && newY >= 0 && newY < mazeSize && maze[newY][newX] === 0) { | |
| ufo.x = newX; | |
| ufo.y = newY; | |
| moves++; | |
| movesDisplay.textContent = moves; | |
| drawMaze(); | |
| // Check if reached exit | |
| if (ufo.x === exit.x && ufo.y === exit.y) { | |
| endGame(true); | |
| } | |
| } | |
| } | |
| // Toggle tilt controls | |
| document.getElementById('tilt-control').addEventListener('change', function() { | |
| orientationEnabled = this.checked; | |
| if (orientationEnabled && !gameRunning) { | |
| alert('Tilt controls enabled! Tilt your device to move the UFO.'); | |
| } | |
| }); | |
| // Start game | |
| function startGame() { | |
| if (gameRunning) return; | |
| // Reset game state | |
| moves = 0; | |
| time = 0; | |
| movesDisplay.textContent = moves; | |
| timeDisplay.textContent = '00:00'; | |
| // Generate new maze | |
| generateMaze(); | |
| drawMaze(); | |
| // Start timer | |
| gameRunning = true; | |
| timer = setInterval(() => { | |
| time++; | |
| const minutes = Math.floor(time / 60).toString().padStart(2, '0'); | |
| const seconds = (time % 60).toString().padStart(2, '0'); | |
| timeDisplay.textContent = `${minutes}:${seconds}`; | |
| }, 1000); | |
| startBtn.textContent = 'Restart Game'; | |
| } | |
| // End game | |
| function endGame(win) { | |
| gameRunning = false; | |
| clearInterval(timer); | |
| if (win) { | |
| setTimeout(() => { | |
| alert(`Congratulations! You escaped the maze in ${time} seconds with ${moves} moves!`); | |
| }, 100); | |
| } | |
| } | |
| // Initialize the game | |
| initGame(); | |
| }); |