/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Ball: The player-controlled ball
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballSize = 0;
	self.setSize = function (size) {
		ballSize = size;
		if (self.ballAsset) {
			self.removeChild(self.ballAsset);
		}
		self.ballAsset = self.attachAsset('ball', {
			width: ballSize,
			height: ballSize,
			color: 0x3a8cff,
			shape: 'ellipse',
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	self.radius = function () {
		return ballSize / 2;
	};
	return self;
});
// Finish: The goal area
var Finish = Container.expand(function () {
	var self = Container.call(this);
	var finishSize = 0;
	self.setSize = function (size) {
		finishSize = size;
		if (self.finishAsset) {
			self.removeChild(self.finishAsset);
		}
		self.finishAsset = self.attachAsset('finish', {
			width: finishSize,
			height: finishSize,
			color: 0x44de83,
			shape: 'ellipse',
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	return self;
});
// MazeCell: Represents a single cell in the maze grid
var MazeCell = Container.expand(function () {
	var self = Container.call(this);
	// Walls: {top, right, bottom, left}
	self.walls = [true, true, true, true];
	self.visited = false;
	self.xIndex = 0;
	self.yIndex = 0;
	self.size = 0;
	self.wallGraphics = [];
	// Draws the cell walls
	self.draw = function () {
		// Remove old wall graphics
		for (var i = 0; i < self.wallGraphics.length; i++) {
			self.removeChild(self.wallGraphics[i]);
		}
		self.wallGraphics = [];
		var s = self.size;
		var wallColor = 0x222222;
		var wallThickness = Math.max(8, Math.floor(s * 0.12));
		// Top wall
		if (self.walls[0]) {
			var topWall = LK.getAsset('wall', {
				width: s,
				height: wallThickness,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			topWall.x = 0;
			topWall.y = 0;
			self.addChild(topWall);
			self.wallGraphics.push(topWall);
		}
		// Right wall
		if (self.walls[1]) {
			var rightWall = LK.getAsset('wall', {
				width: wallThickness,
				height: s,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			rightWall.x = s - wallThickness;
			rightWall.y = 0;
			self.addChild(rightWall);
			self.wallGraphics.push(rightWall);
		}
		// Bottom wall
		if (self.walls[2]) {
			var bottomWall = LK.getAsset('wall', {
				width: s,
				height: wallThickness,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			bottomWall.x = 0;
			bottomWall.y = s - wallThickness;
			self.addChild(bottomWall);
			self.wallGraphics.push(bottomWall);
		}
		// Left wall
		if (self.walls[3]) {
			var leftWall = LK.getAsset('wall', {
				width: wallThickness,
				height: s,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			leftWall.x = 0;
			leftWall.y = 0;
			self.addChild(leftWall);
			self.wallGraphics.push(leftWall);
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xf7f7f7
});
/**** 
* Game Code
****/ 
// Maze parameters
var MAZE_COLS = 18;
var MAZE_ROWS = 24;
var MAZE_MARGIN = 40; // px margin around maze (reduce margin to fit bigger maze)
var mazeCellSize = 0;
var mazeOriginX = 0;
var mazeOriginY = 0;
var maze = [];
var mazeContainer = new Container();
game.addChild(mazeContainer);
// Ball and Finish
var ball = null;
var finish = null;
// Ball physics
var ballPos = {
	x: 0,
	y: 0
};
var ballVel = {
	x: 0,
	y: 0
};
var ballMaxSpeed = 32;
var ballAccel = 2.2;
var ballFriction = 0.96;
// Gyro state
var gyro = {
	x: 0,
	y: 0
};
// Timer
var startTime = 0;
var elapsedTime = 0;
// Final score text removed as per requirements
// Helper: Clamp
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val));
}
// Helper: Shuffle array
function shuffle(arr) {
	for (var i = arr.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}
	return arr;
}
// Maze generation: Recursive backtracker with bias for normal difficulty route
function generateMaze(cols, rows) {
	var grid = [];
	for (var y = 0; y < rows; y++) {
		var row = [];
		for (var x = 0; x < cols; x++) {
			var cell = new MazeCell();
			cell.xIndex = x;
			cell.yIndex = y;
			cell.size = mazeCellSize;
			cell.visited = false;
			row.push(cell);
		}
		grid.push(row);
	}
	function cellAt(x, y) {
		if (x < 0 || y < 0 || x >= cols || y >= rows) return null;
		return grid[y][x];
	}
	var stack = [];
	var current = grid[0][0];
	current.visited = true;
	var visitedCount = 1;
	var totalCells = cols * rows;
	// Bias: prefer to move generally toward the finish, but not always
	var finishX = cols - 1;
	var finishY = rows - 1;
	while (visitedCount < totalCells) {
		// Find unvisited neighbors
		var neighbors = [];
		var dirs = [[0, -1, 0],
		// top
		[1, 0, 1],
		// right
		[0, 1, 2],
		// bottom
		[-1, 0, 3] // left
		];
		for (var d = 0; d < 4; d++) {
			var nx = current.xIndex + dirs[d][0];
			var ny = current.yIndex + dirs[d][1];
			var neighbor = cellAt(nx, ny);
			if (neighbor && !neighbor.visited) {
				neighbors.push({
					cell: neighbor,
					dir: d
				});
			}
		}
		if (neighbors.length > 0) {
			// Bias: 60% chance to pick neighbor that is closer to finish, else random
			var pick;
			if (Math.random() < 0.6) {
				// Sort neighbors by distance to finish, pick the closest
				neighbors.sort(function (a, b) {
					var da = Math.abs(a.cell.xIndex - finishX) + Math.abs(a.cell.yIndex - finishY);
					var db = Math.abs(b.cell.xIndex - finishX) + Math.abs(b.cell.yIndex - finishY);
					return da - db;
				});
				// 50% chance to pick the closest, 50% chance to pick second closest (if exists)
				if (neighbors.length > 1 && Math.random() < 0.5) {
					pick = neighbors[1];
				} else {
					pick = neighbors[0];
				}
			} else {
				pick = neighbors[Math.floor(Math.random() * neighbors.length)];
			}
			// Remove wall between current and neighbor
			current.walls[pick.dir] = false;
			var opp = (pick.dir + 2) % 4;
			pick.cell.walls[opp] = false;
			stack.push(current);
			current = pick.cell;
			current.visited = true;
			visitedCount++;
		} else if (stack.length > 0) {
			current = stack.pop();
		}
	}
	// Draw all cells
	for (var y = 0; y < rows; y++) {
		for (var x = 0; x < cols; x++) {
			grid[y][x].draw();
		}
	}
	return grid;
}
// Place maze in center of screen, calculate cell size
function layoutMaze() {
	var availW = 2048 - MAZE_MARGIN * 2;
	var availH = 2732 - MAZE_MARGIN * 2;
	mazeCellSize = Math.floor(Math.min(availW / MAZE_COLS, availH / MAZE_ROWS));
	var mazeW = mazeCellSize * MAZE_COLS;
	var mazeH = mazeCellSize * MAZE_ROWS;
	mazeOriginX = Math.floor((2048 - mazeW) / 2);
	mazeOriginY = Math.floor((2732 - mazeH) / 2);
	mazeContainer.x = mazeOriginX;
	mazeContainer.y = mazeOriginY;
}
// Remove all children from mazeContainer
function clearMaze() {
	while (mazeContainer.children.length > 0) {
		mazeContainer.removeChild(mazeContainer.children[0]);
	}
}
// Place ball at start
function placeBall() {
	if (ball) {
		ball.destroy();
	}
	ball = new Ball();
	ball.setSize(Math.floor(mazeCellSize * 0.55));
	ballPos.x = mazeCellSize / 2;
	ballPos.y = mazeCellSize / 2;
	ball.x = ballPos.x;
	ball.y = ballPos.y;
	ballVel.x = 0;
	ballVel.y = 0;
	mazeContainer.addChild(ball);
}
// Place finish at bottom-right cell
function placeFinish() {
	if (finish) {
		finish.destroy();
	}
	finish = new Finish();
	finish.setSize(Math.floor(mazeCellSize * 0.55));
	// Pick a random cell in the maze that is not the start cell (0,0)
	var finishCellX = 0;
	var finishCellY = 0;
	while (finishCellX === 0 && finishCellY === 0) {
		finishCellX = Math.floor(Math.random() * MAZE_COLS);
		finishCellY = Math.floor(Math.random() * MAZE_ROWS);
	}
	var fx = finishCellX * mazeCellSize + mazeCellSize / 2;
	var fy = finishCellY * mazeCellSize + mazeCellSize / 2;
	finish.x = fx;
	finish.y = fy;
	mazeContainer.addChild(finish);
	// Store finish cell for win check
	finish.finishCellX = finishCellX;
	finish.finishCellY = finishCellY;
}
// Check collision between ball and maze walls
function resolveBallMazeCollision() {
	var r = ball.radius();
	var cx = Math.floor(ballPos.x / mazeCellSize);
	var cy = Math.floor(ballPos.y / mazeCellSize);
	// Clamp to maze bounds
	cx = clamp(cx, 0, MAZE_COLS - 1);
	cy = clamp(cy, 0, MAZE_ROWS - 1);
	var cell = maze[cy][cx];
	var px = ballPos.x - cx * mazeCellSize;
	var py = ballPos.y - cy * mazeCellSize;
	var s = mazeCellSize;
	var wallThickness = Math.max(8, Math.floor(s * 0.12));
	// Top wall
	if (cell.walls[0] && py - r < wallThickness) {
		ballPos.y = cy * mazeCellSize + wallThickness + r;
		ballVel.y = Math.max(0, ballVel.y);
	}
	// Right wall
	if (cell.walls[1] && px + r > s - wallThickness) {
		ballPos.x = cx * mazeCellSize + s - wallThickness - r;
		ballVel.x = Math.min(0, ballVel.x);
	}
	// Bottom wall
	if (cell.walls[2] && py + r > s - wallThickness) {
		ballPos.y = cy * mazeCellSize + s - wallThickness - r;
		ballVel.y = Math.min(0, ballVel.y);
	}
	// Left wall
	if (cell.walls[3] && px - r < wallThickness) {
		ballPos.x = cx * mazeCellSize + wallThickness + r;
		ballVel.x = Math.max(0, ballVel.x);
	}
	// Clamp to maze area
	ballPos.x = clamp(ballPos.x, r, MAZE_COLS * mazeCellSize - r);
	ballPos.y = clamp(ballPos.y, r, MAZE_ROWS * mazeCellSize - r);
}
// Check if ball reached finish
function checkBallFinish() {
	// Use the actual finish cell position
	var fx = finish.finishCellX * mazeCellSize + mazeCellSize / 2;
	var fy = finish.finishCellY * mazeCellSize + mazeCellSize / 2;
	var dx = ballPos.x - fx;
	var dy = ballPos.y - fy;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist < ball.radius() + finish.finishAsset.width / 2 - 6) {
		return true;
	}
	return false;
}
// Start new game
function startGame() {
	clearMaze();
	layoutMaze();
	maze = generateMaze(MAZE_COLS, MAZE_ROWS);
	// Add all cells to container
	for (var y = 0; y < MAZE_ROWS; y++) {
		for (var x = 0; x < MAZE_COLS; x++) {
			var cell = maze[y][x];
			cell.x = x * mazeCellSize;
			cell.y = y * mazeCellSize;
			mazeContainer.addChild(cell);
		}
	}
	placeFinish();
	placeBall();
	startTime = Date.now();
	elapsedTime = 0;
}
// Gyroscope/motion support
function handleDeviceMotion(event) {
	// event.accelerationIncludingGravity.{x,y,z}
	// On iOS, x is left/right, y is up/down, z is toward/away
	// On Android, axes may be swapped, so we allow both
	var ax = 0,
		ay = 0;
	if (event.accelerationIncludingGravity) {
		ax = event.accelerationIncludingGravity.x || 0;
		ay = event.accelerationIncludingGravity.y || 0;
	}
	// Heuristic: On portrait, invert y for natural tilt
	gyro.x = clamp(ax, -6, 6);
	gyro.y = clamp(-ay, -6, 6);
}
if (typeof window !== "undefined" && window.addEventListener) {
	window.addEventListener('devicemotion', handleDeviceMotion, true);
}
// Fallback: Touch drag to control ball if no gyro
var dragging = false;
var lastTouch = {
	x: 0,
	y: 0
};
game.down = function (x, y, obj) {
	// Only start drag if inside maze area
	var gx = x - mazeOriginX;
	var gy = y - mazeOriginY;
	if (gx >= 0 && gx < mazeCellSize * MAZE_COLS && gy >= 0 && gy < mazeCellSize * MAZE_ROWS) {
		dragging = true;
		lastTouch.x = x;
		lastTouch.y = y;
	}
};
game.up = function (x, y, obj) {
	dragging = false;
};
game.move = function (x, y, obj) {
	if (dragging) {
		var dx = x - lastTouch.x;
		var dy = y - lastTouch.y;
		// Simulate tilt by touch drag
		gyro.x = clamp(dx * 0.2, -6, 6);
		gyro.y = clamp(dy * 0.2, -6, 6);
		lastTouch.x = x;
		lastTouch.y = y;
	}
};
// Main update loop
game.update = function () {
	// Ball physics
	// Use gyro.x/gyro.y as acceleration
	ballVel.x += ballAccel * gyro.x * 0.18;
	ballVel.y += ballAccel * gyro.y * 0.18;
	// Friction
	ballVel.x *= ballFriction;
	ballVel.y *= ballFriction;
	// Clamp speed
	ballVel.x = clamp(ballVel.x, -ballMaxSpeed, ballMaxSpeed);
	ballVel.y = clamp(ballVel.y, -ballMaxSpeed, ballMaxSpeed);
	// Move ball
	ballPos.x += ballVel.x;
	ballPos.y += ballVel.y;
	resolveBallMazeCollision();
	ball.x = ballPos.x;
	ball.y = ballPos.y;
	// Timer
	elapsedTime = (Date.now() - startTime) / 1000;
	// Win condition
	if (checkBallFinish()) {
		LK.getSound('finish_reached').play();
		LK.effects.flashScreen(0x44de83, 800);
		LK.showYouWin();
	}
};
// Start game on load
startGame();
// Reset game on game over or win
LK.on('gameover', function () {
	startGame();
});
LK.on('youwin', function () {
	startGame();
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Ball: The player-controlled ball
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballSize = 0;
	self.setSize = function (size) {
		ballSize = size;
		if (self.ballAsset) {
			self.removeChild(self.ballAsset);
		}
		self.ballAsset = self.attachAsset('ball', {
			width: ballSize,
			height: ballSize,
			color: 0x3a8cff,
			shape: 'ellipse',
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	self.radius = function () {
		return ballSize / 2;
	};
	return self;
});
// Finish: The goal area
var Finish = Container.expand(function () {
	var self = Container.call(this);
	var finishSize = 0;
	self.setSize = function (size) {
		finishSize = size;
		if (self.finishAsset) {
			self.removeChild(self.finishAsset);
		}
		self.finishAsset = self.attachAsset('finish', {
			width: finishSize,
			height: finishSize,
			color: 0x44de83,
			shape: 'ellipse',
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	return self;
});
// MazeCell: Represents a single cell in the maze grid
var MazeCell = Container.expand(function () {
	var self = Container.call(this);
	// Walls: {top, right, bottom, left}
	self.walls = [true, true, true, true];
	self.visited = false;
	self.xIndex = 0;
	self.yIndex = 0;
	self.size = 0;
	self.wallGraphics = [];
	// Draws the cell walls
	self.draw = function () {
		// Remove old wall graphics
		for (var i = 0; i < self.wallGraphics.length; i++) {
			self.removeChild(self.wallGraphics[i]);
		}
		self.wallGraphics = [];
		var s = self.size;
		var wallColor = 0x222222;
		var wallThickness = Math.max(8, Math.floor(s * 0.12));
		// Top wall
		if (self.walls[0]) {
			var topWall = LK.getAsset('wall', {
				width: s,
				height: wallThickness,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			topWall.x = 0;
			topWall.y = 0;
			self.addChild(topWall);
			self.wallGraphics.push(topWall);
		}
		// Right wall
		if (self.walls[1]) {
			var rightWall = LK.getAsset('wall', {
				width: wallThickness,
				height: s,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			rightWall.x = s - wallThickness;
			rightWall.y = 0;
			self.addChild(rightWall);
			self.wallGraphics.push(rightWall);
		}
		// Bottom wall
		if (self.walls[2]) {
			var bottomWall = LK.getAsset('wall', {
				width: s,
				height: wallThickness,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			bottomWall.x = 0;
			bottomWall.y = s - wallThickness;
			self.addChild(bottomWall);
			self.wallGraphics.push(bottomWall);
		}
		// Left wall
		if (self.walls[3]) {
			var leftWall = LK.getAsset('wall', {
				width: wallThickness,
				height: s,
				color: wallColor,
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
			leftWall.x = 0;
			leftWall.y = 0;
			self.addChild(leftWall);
			self.wallGraphics.push(leftWall);
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xf7f7f7
});
/**** 
* Game Code
****/ 
// Maze parameters
var MAZE_COLS = 18;
var MAZE_ROWS = 24;
var MAZE_MARGIN = 40; // px margin around maze (reduce margin to fit bigger maze)
var mazeCellSize = 0;
var mazeOriginX = 0;
var mazeOriginY = 0;
var maze = [];
var mazeContainer = new Container();
game.addChild(mazeContainer);
// Ball and Finish
var ball = null;
var finish = null;
// Ball physics
var ballPos = {
	x: 0,
	y: 0
};
var ballVel = {
	x: 0,
	y: 0
};
var ballMaxSpeed = 32;
var ballAccel = 2.2;
var ballFriction = 0.96;
// Gyro state
var gyro = {
	x: 0,
	y: 0
};
// Timer
var startTime = 0;
var elapsedTime = 0;
// Final score text removed as per requirements
// Helper: Clamp
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val));
}
// Helper: Shuffle array
function shuffle(arr) {
	for (var i = arr.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}
	return arr;
}
// Maze generation: Recursive backtracker with bias for normal difficulty route
function generateMaze(cols, rows) {
	var grid = [];
	for (var y = 0; y < rows; y++) {
		var row = [];
		for (var x = 0; x < cols; x++) {
			var cell = new MazeCell();
			cell.xIndex = x;
			cell.yIndex = y;
			cell.size = mazeCellSize;
			cell.visited = false;
			row.push(cell);
		}
		grid.push(row);
	}
	function cellAt(x, y) {
		if (x < 0 || y < 0 || x >= cols || y >= rows) return null;
		return grid[y][x];
	}
	var stack = [];
	var current = grid[0][0];
	current.visited = true;
	var visitedCount = 1;
	var totalCells = cols * rows;
	// Bias: prefer to move generally toward the finish, but not always
	var finishX = cols - 1;
	var finishY = rows - 1;
	while (visitedCount < totalCells) {
		// Find unvisited neighbors
		var neighbors = [];
		var dirs = [[0, -1, 0],
		// top
		[1, 0, 1],
		// right
		[0, 1, 2],
		// bottom
		[-1, 0, 3] // left
		];
		for (var d = 0; d < 4; d++) {
			var nx = current.xIndex + dirs[d][0];
			var ny = current.yIndex + dirs[d][1];
			var neighbor = cellAt(nx, ny);
			if (neighbor && !neighbor.visited) {
				neighbors.push({
					cell: neighbor,
					dir: d
				});
			}
		}
		if (neighbors.length > 0) {
			// Bias: 60% chance to pick neighbor that is closer to finish, else random
			var pick;
			if (Math.random() < 0.6) {
				// Sort neighbors by distance to finish, pick the closest
				neighbors.sort(function (a, b) {
					var da = Math.abs(a.cell.xIndex - finishX) + Math.abs(a.cell.yIndex - finishY);
					var db = Math.abs(b.cell.xIndex - finishX) + Math.abs(b.cell.yIndex - finishY);
					return da - db;
				});
				// 50% chance to pick the closest, 50% chance to pick second closest (if exists)
				if (neighbors.length > 1 && Math.random() < 0.5) {
					pick = neighbors[1];
				} else {
					pick = neighbors[0];
				}
			} else {
				pick = neighbors[Math.floor(Math.random() * neighbors.length)];
			}
			// Remove wall between current and neighbor
			current.walls[pick.dir] = false;
			var opp = (pick.dir + 2) % 4;
			pick.cell.walls[opp] = false;
			stack.push(current);
			current = pick.cell;
			current.visited = true;
			visitedCount++;
		} else if (stack.length > 0) {
			current = stack.pop();
		}
	}
	// Draw all cells
	for (var y = 0; y < rows; y++) {
		for (var x = 0; x < cols; x++) {
			grid[y][x].draw();
		}
	}
	return grid;
}
// Place maze in center of screen, calculate cell size
function layoutMaze() {
	var availW = 2048 - MAZE_MARGIN * 2;
	var availH = 2732 - MAZE_MARGIN * 2;
	mazeCellSize = Math.floor(Math.min(availW / MAZE_COLS, availH / MAZE_ROWS));
	var mazeW = mazeCellSize * MAZE_COLS;
	var mazeH = mazeCellSize * MAZE_ROWS;
	mazeOriginX = Math.floor((2048 - mazeW) / 2);
	mazeOriginY = Math.floor((2732 - mazeH) / 2);
	mazeContainer.x = mazeOriginX;
	mazeContainer.y = mazeOriginY;
}
// Remove all children from mazeContainer
function clearMaze() {
	while (mazeContainer.children.length > 0) {
		mazeContainer.removeChild(mazeContainer.children[0]);
	}
}
// Place ball at start
function placeBall() {
	if (ball) {
		ball.destroy();
	}
	ball = new Ball();
	ball.setSize(Math.floor(mazeCellSize * 0.55));
	ballPos.x = mazeCellSize / 2;
	ballPos.y = mazeCellSize / 2;
	ball.x = ballPos.x;
	ball.y = ballPos.y;
	ballVel.x = 0;
	ballVel.y = 0;
	mazeContainer.addChild(ball);
}
// Place finish at bottom-right cell
function placeFinish() {
	if (finish) {
		finish.destroy();
	}
	finish = new Finish();
	finish.setSize(Math.floor(mazeCellSize * 0.55));
	// Pick a random cell in the maze that is not the start cell (0,0)
	var finishCellX = 0;
	var finishCellY = 0;
	while (finishCellX === 0 && finishCellY === 0) {
		finishCellX = Math.floor(Math.random() * MAZE_COLS);
		finishCellY = Math.floor(Math.random() * MAZE_ROWS);
	}
	var fx = finishCellX * mazeCellSize + mazeCellSize / 2;
	var fy = finishCellY * mazeCellSize + mazeCellSize / 2;
	finish.x = fx;
	finish.y = fy;
	mazeContainer.addChild(finish);
	// Store finish cell for win check
	finish.finishCellX = finishCellX;
	finish.finishCellY = finishCellY;
}
// Check collision between ball and maze walls
function resolveBallMazeCollision() {
	var r = ball.radius();
	var cx = Math.floor(ballPos.x / mazeCellSize);
	var cy = Math.floor(ballPos.y / mazeCellSize);
	// Clamp to maze bounds
	cx = clamp(cx, 0, MAZE_COLS - 1);
	cy = clamp(cy, 0, MAZE_ROWS - 1);
	var cell = maze[cy][cx];
	var px = ballPos.x - cx * mazeCellSize;
	var py = ballPos.y - cy * mazeCellSize;
	var s = mazeCellSize;
	var wallThickness = Math.max(8, Math.floor(s * 0.12));
	// Top wall
	if (cell.walls[0] && py - r < wallThickness) {
		ballPos.y = cy * mazeCellSize + wallThickness + r;
		ballVel.y = Math.max(0, ballVel.y);
	}
	// Right wall
	if (cell.walls[1] && px + r > s - wallThickness) {
		ballPos.x = cx * mazeCellSize + s - wallThickness - r;
		ballVel.x = Math.min(0, ballVel.x);
	}
	// Bottom wall
	if (cell.walls[2] && py + r > s - wallThickness) {
		ballPos.y = cy * mazeCellSize + s - wallThickness - r;
		ballVel.y = Math.min(0, ballVel.y);
	}
	// Left wall
	if (cell.walls[3] && px - r < wallThickness) {
		ballPos.x = cx * mazeCellSize + wallThickness + r;
		ballVel.x = Math.max(0, ballVel.x);
	}
	// Clamp to maze area
	ballPos.x = clamp(ballPos.x, r, MAZE_COLS * mazeCellSize - r);
	ballPos.y = clamp(ballPos.y, r, MAZE_ROWS * mazeCellSize - r);
}
// Check if ball reached finish
function checkBallFinish() {
	// Use the actual finish cell position
	var fx = finish.finishCellX * mazeCellSize + mazeCellSize / 2;
	var fy = finish.finishCellY * mazeCellSize + mazeCellSize / 2;
	var dx = ballPos.x - fx;
	var dy = ballPos.y - fy;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist < ball.radius() + finish.finishAsset.width / 2 - 6) {
		return true;
	}
	return false;
}
// Start new game
function startGame() {
	clearMaze();
	layoutMaze();
	maze = generateMaze(MAZE_COLS, MAZE_ROWS);
	// Add all cells to container
	for (var y = 0; y < MAZE_ROWS; y++) {
		for (var x = 0; x < MAZE_COLS; x++) {
			var cell = maze[y][x];
			cell.x = x * mazeCellSize;
			cell.y = y * mazeCellSize;
			mazeContainer.addChild(cell);
		}
	}
	placeFinish();
	placeBall();
	startTime = Date.now();
	elapsedTime = 0;
}
// Gyroscope/motion support
function handleDeviceMotion(event) {
	// event.accelerationIncludingGravity.{x,y,z}
	// On iOS, x is left/right, y is up/down, z is toward/away
	// On Android, axes may be swapped, so we allow both
	var ax = 0,
		ay = 0;
	if (event.accelerationIncludingGravity) {
		ax = event.accelerationIncludingGravity.x || 0;
		ay = event.accelerationIncludingGravity.y || 0;
	}
	// Heuristic: On portrait, invert y for natural tilt
	gyro.x = clamp(ax, -6, 6);
	gyro.y = clamp(-ay, -6, 6);
}
if (typeof window !== "undefined" && window.addEventListener) {
	window.addEventListener('devicemotion', handleDeviceMotion, true);
}
// Fallback: Touch drag to control ball if no gyro
var dragging = false;
var lastTouch = {
	x: 0,
	y: 0
};
game.down = function (x, y, obj) {
	// Only start drag if inside maze area
	var gx = x - mazeOriginX;
	var gy = y - mazeOriginY;
	if (gx >= 0 && gx < mazeCellSize * MAZE_COLS && gy >= 0 && gy < mazeCellSize * MAZE_ROWS) {
		dragging = true;
		lastTouch.x = x;
		lastTouch.y = y;
	}
};
game.up = function (x, y, obj) {
	dragging = false;
};
game.move = function (x, y, obj) {
	if (dragging) {
		var dx = x - lastTouch.x;
		var dy = y - lastTouch.y;
		// Simulate tilt by touch drag
		gyro.x = clamp(dx * 0.2, -6, 6);
		gyro.y = clamp(dy * 0.2, -6, 6);
		lastTouch.x = x;
		lastTouch.y = y;
	}
};
// Main update loop
game.update = function () {
	// Ball physics
	// Use gyro.x/gyro.y as acceleration
	ballVel.x += ballAccel * gyro.x * 0.18;
	ballVel.y += ballAccel * gyro.y * 0.18;
	// Friction
	ballVel.x *= ballFriction;
	ballVel.y *= ballFriction;
	// Clamp speed
	ballVel.x = clamp(ballVel.x, -ballMaxSpeed, ballMaxSpeed);
	ballVel.y = clamp(ballVel.y, -ballMaxSpeed, ballMaxSpeed);
	// Move ball
	ballPos.x += ballVel.x;
	ballPos.y += ballVel.y;
	resolveBallMazeCollision();
	ball.x = ballPos.x;
	ball.y = ballPos.y;
	// Timer
	elapsedTime = (Date.now() - startTime) / 1000;
	// Win condition
	if (checkBallFinish()) {
		LK.getSound('finish_reached').play();
		LK.effects.flashScreen(0x44de83, 800);
		LK.showYouWin();
	}
};
// Start game on load
startGame();
// Reset game on game over or win
LK.on('gameover', function () {
	startGame();
});
LK.on('youwin', function () {
	startGame();
});