User prompt
2x2lik hareketsiz kayalar sabit kalmalı. Hareket etmemeli.
User prompt
Please fix the bug: 'Timeout.tick error: grid[writeY][x].animateToGridPosition is not a function' in or related to this line: 'grid[writeY][x].animateToGridPosition(x, writeY, function () {' Line Number: 449 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
4. ve 5. satıra, soldan 2x2 ve sağdan 2x2 hareket ettirilemez duvar koy.
User prompt
Bombanın patlamasına efekt koy ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'colorIndex')' in or related to this line: 'if (grid[y][x].colorIndex === currentColor && !grid[y][x].isBomb && !currentIsBomb) {' Line Number: 214
User prompt
Aralara nadir gelen bomba koy. Bomba hareket ederse 3x3 alanındaki topları patlatsın. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Patlamaya ses efekti koy.
User prompt
Topların patlamasına patlama efekti koy. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Ball Blast Match
Initial prompt
Bana Candy Crush benzeri match3 bir oyun yap. Şeker yerine top koy.
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Ball = Container.expand(function (colorIndex) {
	var self = Container.call(this);
	self.colorIndex = colorIndex;
	self.gridX = 0;
	self.gridY = 0;
	self.isAnimating = false;
	var ballColors = ['redBall', 'blueBall', 'greenBall', 'yellowBall', 'purpleBall'];
	var ballGraphics = self.attachAsset(ballColors[colorIndex], {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.setGridPosition = function (gridX, gridY) {
		self.gridX = gridX;
		self.gridY = gridY;
		var targetX = gridOffsetX + gridX * cellSize + cellSize * 0.5;
		var targetY = gridOffsetY + gridY * cellSize + cellSize * 0.5;
		self.x = targetX;
		self.y = targetY;
	};
	self.animateToGridPosition = function (gridX, gridY, onComplete) {
		self.gridX = gridX;
		self.gridY = gridY;
		var targetX = gridOffsetX + gridX * cellSize + cellSize * 0.5;
		var targetY = gridOffsetY + gridY * cellSize + cellSize * 0.5;
		self.isAnimating = true;
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.isAnimating = false;
				if (onComplete) onComplete();
			}
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x222222
});
/**** 
* Game Code
****/ 
var gridSize = 8;
var cellSize = 200;
var gridOffsetX = (2048 - gridSize * cellSize) * 0.5;
var gridOffsetY = (2732 - gridSize * cellSize) * 0.5 - 200;
var grid = [];
var selectedBall = null;
var isProcessing = false;
var movesLeft = 30;
var targetScore = 5000;
var animatingBalls = 0;
// Create grid background
var background = game.attachAsset('gridBackground', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 * 0.5,
	y: gridOffsetY + 800
});
// Initialize UI
var scoreText = new Text2('Score: 0', {
	size: 80,
	fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var movesText = new Text2('Moves: ' + movesLeft, {
	size: 60,
	fill: 0xFFFFFF
});
movesText.anchor.set(1, 0);
movesText.x = -50;
movesText.y = 100;
LK.gui.topRight.addChild(movesText);
var targetText = new Text2('Target: ' + targetScore, {
	size: 60,
	fill: 0xFFFF00
});
targetText.anchor.set(0, 0);
targetText.x = 50;
targetText.y = 100;
LK.gui.topLeft.addChild(targetText);
// Initialize grid
function initializeGrid() {
	grid = [];
	for (var y = 0; y < gridSize; y++) {
		grid[y] = [];
		for (var x = 0; x < gridSize; x++) {
			var colorIndex = Math.floor(Math.random() * 5);
			var ball = new Ball(colorIndex);
			ball.setGridPosition(x, y);
			grid[y][x] = ball;
			game.addChild(ball);
		}
	}
	// Remove initial matches
	var hasMatches = true;
	while (hasMatches) {
		var matches = findMatches();
		if (matches.length > 0) {
			for (var i = 0; i < matches.length; i++) {
				var match = matches[i];
				var newColorIndex = Math.floor(Math.random() * 5);
				grid[match.y][match.x].colorIndex = newColorIndex;
				// Update ball graphics
				var ball = grid[match.y][match.x];
				ball.removeChildren();
				var ballColors = ['redBall', 'blueBall', 'greenBall', 'yellowBall', 'purpleBall'];
				ball.attachAsset(ballColors[newColorIndex], {
					anchorX: 0.5,
					anchorY: 0.5
				});
			}
		} else {
			hasMatches = false;
		}
	}
}
function getBallAt(x, y) {
	if (x < 0 || x >= gridSize || y < 0 || y >= gridSize) return null;
	return grid[y][x];
}
function isAdjacent(ball1, ball2) {
	var dx = Math.abs(ball1.gridX - ball2.gridX);
	var dy = Math.abs(ball1.gridY - ball2.gridY);
	return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapBalls(ball1, ball2) {
	var tempX = ball1.gridX;
	var tempY = ball1.gridY;
	// Update grid positions
	grid[ball1.gridY][ball1.gridX] = ball2;
	grid[ball2.gridY][ball2.gridX] = ball1;
	// Animate to new positions
	animatingBalls += 2;
	ball1.animateToGridPosition(ball2.gridX, ball2.gridY, function () {
		animatingBalls--;
	});
	ball2.animateToGridPosition(tempX, tempY, function () {
		animatingBalls--;
	});
}
function findMatches() {
	var matches = [];
	var checked = [];
	// Initialize checked array
	for (var y = 0; y < gridSize; y++) {
		checked[y] = [];
		for (var x = 0; x < gridSize; x++) {
			checked[y][x] = false;
		}
	}
	// Check horizontal matches
	for (var y = 0; y < gridSize; y++) {
		var count = 1;
		var currentColor = grid[y][0].colorIndex;
		for (var x = 1; x < gridSize; x++) {
			if (grid[y][x].colorIndex === currentColor) {
				count++;
			} else {
				if (count >= 3) {
					for (var i = x - count; i < x; i++) {
						if (!checked[y][i]) {
							matches.push({
								x: i,
								y: y
							});
							checked[y][i] = true;
						}
					}
				}
				count = 1;
				currentColor = grid[y][x].colorIndex;
			}
		}
		if (count >= 3) {
			for (var i = gridSize - count; i < gridSize; i++) {
				if (!checked[y][i]) {
					matches.push({
						x: i,
						y: y
					});
					checked[y][i] = true;
				}
			}
		}
	}
	// Check vertical matches
	for (var x = 0; x < gridSize; x++) {
		var count = 1;
		var currentColor = grid[0][x].colorIndex;
		for (var y = 1; y < gridSize; y++) {
			if (grid[y][x].colorIndex === currentColor) {
				count++;
			} else {
				if (count >= 3) {
					for (var i = y - count; i < y; i++) {
						if (!checked[i][x]) {
							matches.push({
								x: x,
								y: i
							});
							checked[i][x] = true;
						}
					}
				}
				count = 1;
				currentColor = grid[y][x].colorIndex;
			}
		}
		if (count >= 3) {
			for (var i = gridSize - count; i < gridSize; i++) {
				if (!checked[i][x]) {
					matches.push({
						x: x,
						y: i
					});
					checked[i][x] = true;
				}
			}
		}
	}
	return matches;
}
function removeMatches(matches) {
	var points = 0;
	if (matches.length >= 5) {
		points += 400;
	} else if (matches.length === 4) {
		points += 200;
	} else if (matches.length >= 3) {
		points += 100;
	}
	for (var i = 0; i < matches.length; i++) {
		var match = matches[i];
		var ball = grid[match.y][match.x];
		if (ball) {
			tween(ball, {
				alpha: 0,
				scaleX: 0,
				scaleY: 0
			}, {
				duration: 200,
				easing: tween.easeIn
			});
			ball.destroy();
			grid[match.y][match.x] = null;
		}
	}
	LK.setScore(LK.getScore() + points);
	scoreText.setText('Score: ' + LK.getScore());
	if (matches.length > 0) {
		LK.getSound('match').play();
	}
}
function dropBalls() {
	var dropsHappened = false;
	for (var x = 0; x < gridSize; x++) {
		var writeY = gridSize - 1;
		for (var y = gridSize - 1; y >= 0; y--) {
			if (grid[y][x] !== null) {
				if (y !== writeY) {
					grid[writeY][x] = grid[y][x];
					grid[y][x] = null;
					animatingBalls++;
					grid[writeY][x].animateToGridPosition(x, writeY, function () {
						animatingBalls--;
					});
					dropsHappened = true;
				}
				writeY--;
			}
		}
		// Fill empty spaces at top
		for (var y = writeY; y >= 0; y--) {
			var colorIndex = Math.floor(Math.random() * 5);
			var ball = new Ball(colorIndex);
			ball.setGridPosition(x, y - gridSize);
			grid[y][x] = ball;
			game.addChild(ball);
			animatingBalls++;
			ball.animateToGridPosition(x, y, function () {
				animatingBalls--;
			});
			dropsHappened = true;
		}
	}
	return dropsHappened;
}
function processMatches() {
	if (isProcessing || animatingBalls > 0) return;
	var matches = findMatches();
	if (matches.length > 0) {
		isProcessing = true;
		removeMatches(matches);
		LK.setTimeout(function () {
			dropBalls();
			LK.setTimeout(function () {
				isProcessing = false;
			}, 400);
		}, 300);
	}
}
function checkGameEnd() {
	if (movesLeft <= 0) {
		if (LK.getScore() >= targetScore) {
			LK.showYouWin();
		} else {
			LK.showGameOver();
		}
	}
}
game.down = function (x, y, obj) {
	if (isProcessing || animatingBalls > 0) return;
	// Convert to grid coordinates
	var gridX = Math.floor((x - gridOffsetX) / cellSize);
	var gridY = Math.floor((y - gridOffsetY) / cellSize);
	var clickedBall = getBallAt(gridX, gridY);
	if (!clickedBall) return;
	if (selectedBall === null) {
		selectedBall = clickedBall;
		tween(selectedBall, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 200,
			easing: tween.easeOut
		});
	} else if (selectedBall === clickedBall) {
		tween(selectedBall, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		selectedBall = null;
	} else if (isAdjacent(selectedBall, clickedBall)) {
		// Attempt swap
		var tempGrid = [];
		for (var ty = 0; ty < gridSize; ty++) {
			tempGrid[ty] = [];
			for (var tx = 0; tx < gridSize; tx++) {
				tempGrid[ty][tx] = grid[ty][tx];
			}
		}
		// Temporarily swap in grid
		tempGrid[selectedBall.gridY][selectedBall.gridX] = clickedBall;
		tempGrid[clickedBall.gridY][clickedBall.gridX] = selectedBall;
		// Check if this creates matches
		var tempMatches = [];
		// Simplified match check for the swapped positions
		var ball1Color = selectedBall.colorIndex;
		var ball2Color = clickedBall.colorIndex;
		var hasValidMatch = false;
		// Check around first ball's new position
		var newX1 = clickedBall.gridX;
		var newY1 = clickedBall.gridY;
		// Check horizontal
		var count = 1;
		for (var i = newX1 - 1; i >= 0 && getBallAt(i, newY1) && getBallAt(i, newY1).colorIndex === ball1Color; i--) count++;
		for (var i = newX1 + 1; i < gridSize && getBallAt(i, newY1) && getBallAt(i, newY1).colorIndex === ball1Color; i++) count++;
		if (count >= 3) hasValidMatch = true;
		// Check vertical
		count = 1;
		for (var i = newY1 - 1; i >= 0 && getBallAt(newX1, i) && getBallAt(newX1, i).colorIndex === ball1Color; i--) count++;
		for (var i = newY1 + 1; i < gridSize && getBallAt(newX1, i) && getBallAt(newX1, i).colorIndex === ball1Color; i++) count++;
		if (count >= 3) hasValidMatch = true;
		// Check around second ball's new position
		var newX2 = selectedBall.gridX;
		var newY2 = selectedBall.gridY;
		// Check horizontal
		count = 1;
		for (var i = newX2 - 1; i >= 0 && getBallAt(i, newY2) && getBallAt(i, newY2).colorIndex === ball2Color; i--) count++;
		for (var i = newX2 + 1; i < gridSize && getBallAt(i, newY2) && getBallAt(i, newY2).colorIndex === ball2Color; i++) count++;
		if (count >= 3) hasValidMatch = true;
		// Check vertical
		count = 1;
		for (var i = newY2 - 1; i >= 0 && getBallAt(newX2, i) && getBallAt(newX2, i).colorIndex === ball2Color; i--) count++;
		for (var i = newY2 + 1; i < gridSize && getBallAt(newX2, i) && getBallAt(newX2, i).colorIndex === ball2Color; i++) count++;
		if (count >= 3) hasValidMatch = true;
		if (hasValidMatch) {
			// Valid move
			movesLeft--;
			movesText.setText('Moves: ' + movesLeft);
			LK.getSound('swap').play();
			swapBalls(selectedBall, clickedBall);
			LK.setTimeout(function () {
				processMatches();
			}, 400);
		}
		tween(selectedBall, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		selectedBall = null;
	} else {
		tween(selectedBall, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
		selectedBall = clickedBall;
		tween(selectedBall, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 200,
			easing: tween.easeOut
		});
	}
};
game.update = function () {
	processMatches();
	checkGameEnd();
};
// Initialize the game
initializeGrid(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,439 @@
-/****
+/**** 
+* Plugins
+****/ 
+var tween = LK.import("@upit/tween.v1");
+
+/**** 
+* Classes
+****/ 
+var Ball = Container.expand(function (colorIndex) {
+	var self = Container.call(this);
+	self.colorIndex = colorIndex;
+	self.gridX = 0;
+	self.gridY = 0;
+	self.isAnimating = false;
+	var ballColors = ['redBall', 'blueBall', 'greenBall', 'yellowBall', 'purpleBall'];
+	var ballGraphics = self.attachAsset(ballColors[colorIndex], {
+		anchorX: 0.5,
+		anchorY: 0.5
+	});
+	self.setGridPosition = function (gridX, gridY) {
+		self.gridX = gridX;
+		self.gridY = gridY;
+		var targetX = gridOffsetX + gridX * cellSize + cellSize * 0.5;
+		var targetY = gridOffsetY + gridY * cellSize + cellSize * 0.5;
+		self.x = targetX;
+		self.y = targetY;
+	};
+	self.animateToGridPosition = function (gridX, gridY, onComplete) {
+		self.gridX = gridX;
+		self.gridY = gridY;
+		var targetX = gridOffsetX + gridX * cellSize + cellSize * 0.5;
+		var targetY = gridOffsetY + gridY * cellSize + cellSize * 0.5;
+		self.isAnimating = true;
+		tween(self, {
+			x: targetX,
+			y: targetY
+		}, {
+			duration: 300,
+			easing: tween.easeOut,
+			onFinish: function onFinish() {
+				self.isAnimating = false;
+				if (onComplete) onComplete();
+			}
+		});
+	};
+	return self;
+});
+
+/**** 
 * Initialize Game
-****/
+****/ 
 var game = new LK.Game({
-	backgroundColor: 0x000000
-});
\ No newline at end of file
+	backgroundColor: 0x222222
+});
+
+/**** 
+* Game Code
+****/ 
+var gridSize = 8;
+var cellSize = 200;
+var gridOffsetX = (2048 - gridSize * cellSize) * 0.5;
+var gridOffsetY = (2732 - gridSize * cellSize) * 0.5 - 200;
+var grid = [];
+var selectedBall = null;
+var isProcessing = false;
+var movesLeft = 30;
+var targetScore = 5000;
+var animatingBalls = 0;
+// Create grid background
+var background = game.attachAsset('gridBackground', {
+	anchorX: 0.5,
+	anchorY: 0.5,
+	x: 2048 * 0.5,
+	y: gridOffsetY + 800
+});
+// Initialize UI
+var scoreText = new Text2('Score: 0', {
+	size: 80,
+	fill: 0xFFFFFF
+});
+scoreText.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreText);
+var movesText = new Text2('Moves: ' + movesLeft, {
+	size: 60,
+	fill: 0xFFFFFF
+});
+movesText.anchor.set(1, 0);
+movesText.x = -50;
+movesText.y = 100;
+LK.gui.topRight.addChild(movesText);
+var targetText = new Text2('Target: ' + targetScore, {
+	size: 60,
+	fill: 0xFFFF00
+});
+targetText.anchor.set(0, 0);
+targetText.x = 50;
+targetText.y = 100;
+LK.gui.topLeft.addChild(targetText);
+// Initialize grid
+function initializeGrid() {
+	grid = [];
+	for (var y = 0; y < gridSize; y++) {
+		grid[y] = [];
+		for (var x = 0; x < gridSize; x++) {
+			var colorIndex = Math.floor(Math.random() * 5);
+			var ball = new Ball(colorIndex);
+			ball.setGridPosition(x, y);
+			grid[y][x] = ball;
+			game.addChild(ball);
+		}
+	}
+	// Remove initial matches
+	var hasMatches = true;
+	while (hasMatches) {
+		var matches = findMatches();
+		if (matches.length > 0) {
+			for (var i = 0; i < matches.length; i++) {
+				var match = matches[i];
+				var newColorIndex = Math.floor(Math.random() * 5);
+				grid[match.y][match.x].colorIndex = newColorIndex;
+				// Update ball graphics
+				var ball = grid[match.y][match.x];
+				ball.removeChildren();
+				var ballColors = ['redBall', 'blueBall', 'greenBall', 'yellowBall', 'purpleBall'];
+				ball.attachAsset(ballColors[newColorIndex], {
+					anchorX: 0.5,
+					anchorY: 0.5
+				});
+			}
+		} else {
+			hasMatches = false;
+		}
+	}
+}
+function getBallAt(x, y) {
+	if (x < 0 || x >= gridSize || y < 0 || y >= gridSize) return null;
+	return grid[y][x];
+}
+function isAdjacent(ball1, ball2) {
+	var dx = Math.abs(ball1.gridX - ball2.gridX);
+	var dy = Math.abs(ball1.gridY - ball2.gridY);
+	return dx === 1 && dy === 0 || dx === 0 && dy === 1;
+}
+function swapBalls(ball1, ball2) {
+	var tempX = ball1.gridX;
+	var tempY = ball1.gridY;
+	// Update grid positions
+	grid[ball1.gridY][ball1.gridX] = ball2;
+	grid[ball2.gridY][ball2.gridX] = ball1;
+	// Animate to new positions
+	animatingBalls += 2;
+	ball1.animateToGridPosition(ball2.gridX, ball2.gridY, function () {
+		animatingBalls--;
+	});
+	ball2.animateToGridPosition(tempX, tempY, function () {
+		animatingBalls--;
+	});
+}
+function findMatches() {
+	var matches = [];
+	var checked = [];
+	// Initialize checked array
+	for (var y = 0; y < gridSize; y++) {
+		checked[y] = [];
+		for (var x = 0; x < gridSize; x++) {
+			checked[y][x] = false;
+		}
+	}
+	// Check horizontal matches
+	for (var y = 0; y < gridSize; y++) {
+		var count = 1;
+		var currentColor = grid[y][0].colorIndex;
+		for (var x = 1; x < gridSize; x++) {
+			if (grid[y][x].colorIndex === currentColor) {
+				count++;
+			} else {
+				if (count >= 3) {
+					for (var i = x - count; i < x; i++) {
+						if (!checked[y][i]) {
+							matches.push({
+								x: i,
+								y: y
+							});
+							checked[y][i] = true;
+						}
+					}
+				}
+				count = 1;
+				currentColor = grid[y][x].colorIndex;
+			}
+		}
+		if (count >= 3) {
+			for (var i = gridSize - count; i < gridSize; i++) {
+				if (!checked[y][i]) {
+					matches.push({
+						x: i,
+						y: y
+					});
+					checked[y][i] = true;
+				}
+			}
+		}
+	}
+	// Check vertical matches
+	for (var x = 0; x < gridSize; x++) {
+		var count = 1;
+		var currentColor = grid[0][x].colorIndex;
+		for (var y = 1; y < gridSize; y++) {
+			if (grid[y][x].colorIndex === currentColor) {
+				count++;
+			} else {
+				if (count >= 3) {
+					for (var i = y - count; i < y; i++) {
+						if (!checked[i][x]) {
+							matches.push({
+								x: x,
+								y: i
+							});
+							checked[i][x] = true;
+						}
+					}
+				}
+				count = 1;
+				currentColor = grid[y][x].colorIndex;
+			}
+		}
+		if (count >= 3) {
+			for (var i = gridSize - count; i < gridSize; i++) {
+				if (!checked[i][x]) {
+					matches.push({
+						x: x,
+						y: i
+					});
+					checked[i][x] = true;
+				}
+			}
+		}
+	}
+	return matches;
+}
+function removeMatches(matches) {
+	var points = 0;
+	if (matches.length >= 5) {
+		points += 400;
+	} else if (matches.length === 4) {
+		points += 200;
+	} else if (matches.length >= 3) {
+		points += 100;
+	}
+	for (var i = 0; i < matches.length; i++) {
+		var match = matches[i];
+		var ball = grid[match.y][match.x];
+		if (ball) {
+			tween(ball, {
+				alpha: 0,
+				scaleX: 0,
+				scaleY: 0
+			}, {
+				duration: 200,
+				easing: tween.easeIn
+			});
+			ball.destroy();
+			grid[match.y][match.x] = null;
+		}
+	}
+	LK.setScore(LK.getScore() + points);
+	scoreText.setText('Score: ' + LK.getScore());
+	if (matches.length > 0) {
+		LK.getSound('match').play();
+	}
+}
+function dropBalls() {
+	var dropsHappened = false;
+	for (var x = 0; x < gridSize; x++) {
+		var writeY = gridSize - 1;
+		for (var y = gridSize - 1; y >= 0; y--) {
+			if (grid[y][x] !== null) {
+				if (y !== writeY) {
+					grid[writeY][x] = grid[y][x];
+					grid[y][x] = null;
+					animatingBalls++;
+					grid[writeY][x].animateToGridPosition(x, writeY, function () {
+						animatingBalls--;
+					});
+					dropsHappened = true;
+				}
+				writeY--;
+			}
+		}
+		// Fill empty spaces at top
+		for (var y = writeY; y >= 0; y--) {
+			var colorIndex = Math.floor(Math.random() * 5);
+			var ball = new Ball(colorIndex);
+			ball.setGridPosition(x, y - gridSize);
+			grid[y][x] = ball;
+			game.addChild(ball);
+			animatingBalls++;
+			ball.animateToGridPosition(x, y, function () {
+				animatingBalls--;
+			});
+			dropsHappened = true;
+		}
+	}
+	return dropsHappened;
+}
+function processMatches() {
+	if (isProcessing || animatingBalls > 0) return;
+	var matches = findMatches();
+	if (matches.length > 0) {
+		isProcessing = true;
+		removeMatches(matches);
+		LK.setTimeout(function () {
+			dropBalls();
+			LK.setTimeout(function () {
+				isProcessing = false;
+			}, 400);
+		}, 300);
+	}
+}
+function checkGameEnd() {
+	if (movesLeft <= 0) {
+		if (LK.getScore() >= targetScore) {
+			LK.showYouWin();
+		} else {
+			LK.showGameOver();
+		}
+	}
+}
+game.down = function (x, y, obj) {
+	if (isProcessing || animatingBalls > 0) return;
+	// Convert to grid coordinates
+	var gridX = Math.floor((x - gridOffsetX) / cellSize);
+	var gridY = Math.floor((y - gridOffsetY) / cellSize);
+	var clickedBall = getBallAt(gridX, gridY);
+	if (!clickedBall) return;
+	if (selectedBall === null) {
+		selectedBall = clickedBall;
+		tween(selectedBall, {
+			scaleX: 1.2,
+			scaleY: 1.2
+		}, {
+			duration: 200,
+			easing: tween.easeOut
+		});
+	} else if (selectedBall === clickedBall) {
+		tween(selectedBall, {
+			scaleX: 1,
+			scaleY: 1
+		}, {
+			duration: 200,
+			easing: tween.easeOut
+		});
+		selectedBall = null;
+	} else if (isAdjacent(selectedBall, clickedBall)) {
+		// Attempt swap
+		var tempGrid = [];
+		for (var ty = 0; ty < gridSize; ty++) {
+			tempGrid[ty] = [];
+			for (var tx = 0; tx < gridSize; tx++) {
+				tempGrid[ty][tx] = grid[ty][tx];
+			}
+		}
+		// Temporarily swap in grid
+		tempGrid[selectedBall.gridY][selectedBall.gridX] = clickedBall;
+		tempGrid[clickedBall.gridY][clickedBall.gridX] = selectedBall;
+		// Check if this creates matches
+		var tempMatches = [];
+		// Simplified match check for the swapped positions
+		var ball1Color = selectedBall.colorIndex;
+		var ball2Color = clickedBall.colorIndex;
+		var hasValidMatch = false;
+		// Check around first ball's new position
+		var newX1 = clickedBall.gridX;
+		var newY1 = clickedBall.gridY;
+		// Check horizontal
+		var count = 1;
+		for (var i = newX1 - 1; i >= 0 && getBallAt(i, newY1) && getBallAt(i, newY1).colorIndex === ball1Color; i--) count++;
+		for (var i = newX1 + 1; i < gridSize && getBallAt(i, newY1) && getBallAt(i, newY1).colorIndex === ball1Color; i++) count++;
+		if (count >= 3) hasValidMatch = true;
+		// Check vertical
+		count = 1;
+		for (var i = newY1 - 1; i >= 0 && getBallAt(newX1, i) && getBallAt(newX1, i).colorIndex === ball1Color; i--) count++;
+		for (var i = newY1 + 1; i < gridSize && getBallAt(newX1, i) && getBallAt(newX1, i).colorIndex === ball1Color; i++) count++;
+		if (count >= 3) hasValidMatch = true;
+		// Check around second ball's new position
+		var newX2 = selectedBall.gridX;
+		var newY2 = selectedBall.gridY;
+		// Check horizontal
+		count = 1;
+		for (var i = newX2 - 1; i >= 0 && getBallAt(i, newY2) && getBallAt(i, newY2).colorIndex === ball2Color; i--) count++;
+		for (var i = newX2 + 1; i < gridSize && getBallAt(i, newY2) && getBallAt(i, newY2).colorIndex === ball2Color; i++) count++;
+		if (count >= 3) hasValidMatch = true;
+		// Check vertical
+		count = 1;
+		for (var i = newY2 - 1; i >= 0 && getBallAt(newX2, i) && getBallAt(newX2, i).colorIndex === ball2Color; i--) count++;
+		for (var i = newY2 + 1; i < gridSize && getBallAt(newX2, i) && getBallAt(newX2, i).colorIndex === ball2Color; i++) count++;
+		if (count >= 3) hasValidMatch = true;
+		if (hasValidMatch) {
+			// Valid move
+			movesLeft--;
+			movesText.setText('Moves: ' + movesLeft);
+			LK.getSound('swap').play();
+			swapBalls(selectedBall, clickedBall);
+			LK.setTimeout(function () {
+				processMatches();
+			}, 400);
+		}
+		tween(selectedBall, {
+			scaleX: 1,
+			scaleY: 1
+		}, {
+			duration: 200,
+			easing: tween.easeOut
+		});
+		selectedBall = null;
+	} else {
+		tween(selectedBall, {
+			scaleX: 1,
+			scaleY: 1
+		}, {
+			duration: 200,
+			easing: tween.easeOut
+		});
+		selectedBall = clickedBall;
+		tween(selectedBall, {
+			scaleX: 1.2,
+			scaleY: 1.2
+		}, {
+			duration: 200,
+			easing: tween.easeOut
+		});
+	}
+};
+game.update = function () {
+	processMatches();
+	checkGameEnd();
+};
+// Initialize the game
+initializeGrid();
\ No newline at end of file
 dumb smiley blue face, perfect round. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 perfectly round, red angry face. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 perfectly round, yellow surprised face. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 perfectly round, pink clever poker face. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 perfectly round, green sad face. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 a bomb, perfectly round. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
 perfect square, concrete wall. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat