/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Tile = Container.expand(function (value, gridX, gridY) {
	var self = Container.call(this);
	self.value = value;
	self.gridX = gridX;
	self.gridY = gridY;
	self.hasMerged = false;
	// Get the appropriate asset based on value
	var assetName = 'tile' + value;
	var tileGraphics = self.attachAsset(assetName, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Add text for the number
	self.numberText = new Text2(value.toString(), {
		size: value >= 1000 ? 36 : value >= 100 ? 42 : 48,
		fill: value <= 4 ? "#776e65" : "#f9f6f2"
	});
	self.numberText.anchor.set(0.5, 0.5);
	self.addChild(self.numberText);
	self.updatePosition = function () {
		var targetX = gridStartX + self.gridX * (tileSize + tileGap);
		var targetY = gridStartY + self.gridY * (tileSize + tileGap);
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: 150,
			easing: tween.easeOut
		});
	};
	self.setValue = function (newValue) {
		self.value = newValue;
		// Remove old text and create new one with correct size
		self.removeChild(self.numberText);
		self.numberText = new Text2(newValue.toString(), {
			size: newValue >= 1000 ? 36 : newValue >= 100 ? 42 : 48,
			fill: newValue <= 4 ? "#776e65" : "#f9f6f2"
		});
		self.numberText.anchor.set(0.5, 0.5);
		self.addChild(self.numberText);
		// Update graphics
		self.removeChild(tileGraphics);
		assetName = 'tile' + newValue;
		tileGraphics = self.attachAsset(assetName, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		self.addChildAt(tileGraphics, 0);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xfaf8ef
});
/**** 
* Game Code
****/ 
// Game constants
var gridSize = 4;
var tileSize = 120;
var tileGap = 10;
var gridStartX = (2048 - (gridSize * tileSize + (gridSize - 1) * tileGap)) / 2;
var gridStartY = (2732 - (gridSize * tileSize + (gridSize - 1) * tileGap)) / 2;
// Game state
var grid = [];
var tiles = [];
var isMoving = false;
var gameWon = false;
var gameOver = false;
// Initialize grid
for (var i = 0; i < gridSize; i++) {
	grid[i] = [];
	for (var j = 0; j < gridSize; j++) {
		grid[i][j] = null;
	}
}
// Create grid background
var gridContainer = game.addChild(new Container());
for (var i = 0; i < gridSize; i++) {
	for (var j = 0; j < gridSize; j++) {
		var cell = gridContainer.attachAsset('gridCell', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: gridStartX + j * (tileSize + tileGap),
			y: gridStartY + i * (tileSize + tileGap)
		});
	}
}
// Score display
var scoreTxt = new Text2('0', {
	size: 80,
	fill: 0x776E65
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 100;
// Add initial tiles
function addRandomTile() {
	var emptyCells = [];
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (grid[i][j] === null) {
				emptyCells.push({
					x: j,
					y: i
				});
			}
		}
	}
	if (emptyCells.length > 0) {
		var randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
		var value = Math.random() < 0.9 ? 2 : 4;
		var tile = new Tile(value, randomCell.x, randomCell.y);
		tile.x = gridStartX + randomCell.x * (tileSize + tileGap);
		tile.y = gridStartY + randomCell.y * (tileSize + tileGap);
		grid[randomCell.y][randomCell.x] = tile;
		tiles.push(tile);
		game.addChild(tile);
		// Scale animation for new tile
		tile.scaleX = 0.1;
		tile.scaleY = 0.1;
		tween(tile, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.bounceOut
		});
	}
}
function checkGameWon() {
	for (var i = 0; i < tiles.length; i++) {
		if (tiles[i].value >= 2048 && !gameWon) {
			gameWon = true;
			LK.showYouWin();
			return true;
		}
	}
	return false;
}
function checkGameOver() {
	// Check if grid is full
	var fullGrid = true;
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (grid[i][j] === null) {
				fullGrid = false;
				break;
			}
		}
		if (!fullGrid) break;
	}
	if (!fullGrid) return false;
	// Check for possible moves
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			var currentValue = grid[i][j].value;
			// Check right
			if (j < gridSize - 1 && grid[i][j + 1].value === currentValue) {
				return false;
			}
			// Check down
			if (i < gridSize - 1 && grid[i + 1][j].value === currentValue) {
				return false;
			}
		}
	}
	gameOver = true;
	LK.showGameOver();
	return true;
}
function moveTiles(direction) {
	if (isMoving || gameOver || gameWon) return false;
	var moved = false;
	var score = 0;
	// Reset merge flags
	for (var i = 0; i < tiles.length; i++) {
		tiles[i].hasMerged = false;
	}
	// Create new grid state
	var newGrid = [];
	for (var i = 0; i < gridSize; i++) {
		newGrid[i] = [];
		for (var j = 0; j < gridSize; j++) {
			newGrid[i][j] = null;
		}
	}
	if (direction === 'left') {
		for (var i = 0; i < gridSize; i++) {
			var row = [];
			// Collect non-null tiles
			for (var j = 0; j < gridSize; j++) {
				if (grid[i][j] !== null) {
					row.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < row.length - 1; k++) {
				if (row[k].value === row[k + 1].value && !row[k].hasMerged && !row[k + 1].hasMerged) {
					row[k].setValue(row[k].value * 2);
					row[k].hasMerged = true;
					score += row[k].value;
					// Remove merged tile
					game.removeChild(row[k + 1]);
					tiles.splice(tiles.indexOf(row[k + 1]), 1);
					row.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < row.length; k++) {
				if (row[k].gridX !== k || row[k].gridY !== i) {
					moved = true;
				}
				row[k].gridX = k;
				row[k].gridY = i;
				newGrid[i][k] = row[k];
				row[k].updatePosition();
			}
		}
	} else if (direction === 'right') {
		for (var i = 0; i < gridSize; i++) {
			var row = [];
			// Collect non-null tiles
			for (var j = gridSize - 1; j >= 0; j--) {
				if (grid[i][j] !== null) {
					row.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < row.length - 1; k++) {
				if (row[k].value === row[k + 1].value && !row[k].hasMerged && !row[k + 1].hasMerged) {
					row[k].setValue(row[k].value * 2);
					row[k].hasMerged = true;
					score += row[k].value;
					// Remove merged tile
					game.removeChild(row[k + 1]);
					tiles.splice(tiles.indexOf(row[k + 1]), 1);
					row.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < row.length; k++) {
				var newX = gridSize - 1 - k;
				if (row[k].gridX !== newX || row[k].gridY !== i) {
					moved = true;
				}
				row[k].gridX = newX;
				row[k].gridY = i;
				newGrid[i][newX] = row[k];
				row[k].updatePosition();
			}
		}
	} else if (direction === 'up') {
		for (var j = 0; j < gridSize; j++) {
			var column = [];
			// Collect non-null tiles
			for (var i = 0; i < gridSize; i++) {
				if (grid[i][j] !== null) {
					column.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < column.length - 1; k++) {
				if (column[k].value === column[k + 1].value && !column[k].hasMerged && !column[k + 1].hasMerged) {
					column[k].setValue(column[k].value * 2);
					column[k].hasMerged = true;
					score += column[k].value;
					// Remove merged tile
					game.removeChild(column[k + 1]);
					tiles.splice(tiles.indexOf(column[k + 1]), 1);
					column.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < column.length; k++) {
				if (column[k].gridX !== j || column[k].gridY !== k) {
					moved = true;
				}
				column[k].gridX = j;
				column[k].gridY = k;
				newGrid[k][j] = column[k];
				column[k].updatePosition();
			}
		}
	} else if (direction === 'down') {
		for (var j = 0; j < gridSize; j++) {
			var column = [];
			// Collect non-null tiles
			for (var i = gridSize - 1; i >= 0; i--) {
				if (grid[i][j] !== null) {
					column.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < column.length - 1; k++) {
				if (column[k].value === column[k + 1].value && !column[k].hasMerged && !column[k + 1].hasMerged) {
					column[k].setValue(column[k].value * 2);
					column[k].hasMerged = true;
					score += column[k].value;
					// Remove merged tile
					game.removeChild(column[k + 1]);
					tiles.splice(tiles.indexOf(column[k + 1]), 1);
					column.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < column.length; k++) {
				var newY = gridSize - 1 - k;
				if (column[k].gridX !== j || column[k].gridY !== newY) {
					moved = true;
				}
				column[k].gridX = j;
				column[k].gridY = newY;
				newGrid[newY][j] = column[k];
				column[k].updatePosition();
			}
		}
	}
	grid = newGrid;
	if (moved) {
		LK.setScore(LK.getScore() + score);
		scoreTxt.setText(LK.getScore());
		LK.getSound('move').play();
		isMoving = true;
		LK.setTimeout(function () {
			addRandomTile();
			isMoving = false;
			if (!checkGameWon()) {
				checkGameOver();
			}
		}, 200);
	}
	return moved;
}
// Touch controls
var startX = 0;
var startY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
	startX = x;
	startY = y;
	isDragging = true;
};
game.up = function (x, y, obj) {
	if (!isDragging) return;
	var deltaX = x - startX;
	var deltaY = y - startY;
	var minSwipeDistance = 50;
	if (Math.abs(deltaX) > minSwipeDistance || Math.abs(deltaY) > minSwipeDistance) {
		if (Math.abs(deltaX) > Math.abs(deltaY)) {
			// Horizontal swipe
			if (deltaX > 0) {
				moveTiles('right');
			} else {
				moveTiles('left');
			}
		} else {
			// Vertical swipe
			if (deltaY > 0) {
				moveTiles('down');
			} else {
				moveTiles('up');
			}
		}
	}
	isDragging = false;
};
// Add initial tiles
addRandomTile();
addRandomTile();
game.update = function () {
	scoreTxt.setText(LK.getScore());
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
var Tile = Container.expand(function (value, gridX, gridY) {
	var self = Container.call(this);
	self.value = value;
	self.gridX = gridX;
	self.gridY = gridY;
	self.hasMerged = false;
	// Get the appropriate asset based on value
	var assetName = 'tile' + value;
	var tileGraphics = self.attachAsset(assetName, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Add text for the number
	self.numberText = new Text2(value.toString(), {
		size: value >= 1000 ? 36 : value >= 100 ? 42 : 48,
		fill: value <= 4 ? "#776e65" : "#f9f6f2"
	});
	self.numberText.anchor.set(0.5, 0.5);
	self.addChild(self.numberText);
	self.updatePosition = function () {
		var targetX = gridStartX + self.gridX * (tileSize + tileGap);
		var targetY = gridStartY + self.gridY * (tileSize + tileGap);
		tween(self, {
			x: targetX,
			y: targetY
		}, {
			duration: 150,
			easing: tween.easeOut
		});
	};
	self.setValue = function (newValue) {
		self.value = newValue;
		// Remove old text and create new one with correct size
		self.removeChild(self.numberText);
		self.numberText = new Text2(newValue.toString(), {
			size: newValue >= 1000 ? 36 : newValue >= 100 ? 42 : 48,
			fill: newValue <= 4 ? "#776e65" : "#f9f6f2"
		});
		self.numberText.anchor.set(0.5, 0.5);
		self.addChild(self.numberText);
		// Update graphics
		self.removeChild(tileGraphics);
		assetName = 'tile' + newValue;
		tileGraphics = self.attachAsset(assetName, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		self.addChildAt(tileGraphics, 0);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xfaf8ef
});
/**** 
* Game Code
****/ 
// Game constants
var gridSize = 4;
var tileSize = 120;
var tileGap = 10;
var gridStartX = (2048 - (gridSize * tileSize + (gridSize - 1) * tileGap)) / 2;
var gridStartY = (2732 - (gridSize * tileSize + (gridSize - 1) * tileGap)) / 2;
// Game state
var grid = [];
var tiles = [];
var isMoving = false;
var gameWon = false;
var gameOver = false;
// Initialize grid
for (var i = 0; i < gridSize; i++) {
	grid[i] = [];
	for (var j = 0; j < gridSize; j++) {
		grid[i][j] = null;
	}
}
// Create grid background
var gridContainer = game.addChild(new Container());
for (var i = 0; i < gridSize; i++) {
	for (var j = 0; j < gridSize; j++) {
		var cell = gridContainer.attachAsset('gridCell', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: gridStartX + j * (tileSize + tileGap),
			y: gridStartY + i * (tileSize + tileGap)
		});
	}
}
// Score display
var scoreTxt = new Text2('0', {
	size: 80,
	fill: 0x776E65
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 100;
// Add initial tiles
function addRandomTile() {
	var emptyCells = [];
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (grid[i][j] === null) {
				emptyCells.push({
					x: j,
					y: i
				});
			}
		}
	}
	if (emptyCells.length > 0) {
		var randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
		var value = Math.random() < 0.9 ? 2 : 4;
		var tile = new Tile(value, randomCell.x, randomCell.y);
		tile.x = gridStartX + randomCell.x * (tileSize + tileGap);
		tile.y = gridStartY + randomCell.y * (tileSize + tileGap);
		grid[randomCell.y][randomCell.x] = tile;
		tiles.push(tile);
		game.addChild(tile);
		// Scale animation for new tile
		tile.scaleX = 0.1;
		tile.scaleY = 0.1;
		tween(tile, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.bounceOut
		});
	}
}
function checkGameWon() {
	for (var i = 0; i < tiles.length; i++) {
		if (tiles[i].value >= 2048 && !gameWon) {
			gameWon = true;
			LK.showYouWin();
			return true;
		}
	}
	return false;
}
function checkGameOver() {
	// Check if grid is full
	var fullGrid = true;
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (grid[i][j] === null) {
				fullGrid = false;
				break;
			}
		}
		if (!fullGrid) break;
	}
	if (!fullGrid) return false;
	// Check for possible moves
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			var currentValue = grid[i][j].value;
			// Check right
			if (j < gridSize - 1 && grid[i][j + 1].value === currentValue) {
				return false;
			}
			// Check down
			if (i < gridSize - 1 && grid[i + 1][j].value === currentValue) {
				return false;
			}
		}
	}
	gameOver = true;
	LK.showGameOver();
	return true;
}
function moveTiles(direction) {
	if (isMoving || gameOver || gameWon) return false;
	var moved = false;
	var score = 0;
	// Reset merge flags
	for (var i = 0; i < tiles.length; i++) {
		tiles[i].hasMerged = false;
	}
	// Create new grid state
	var newGrid = [];
	for (var i = 0; i < gridSize; i++) {
		newGrid[i] = [];
		for (var j = 0; j < gridSize; j++) {
			newGrid[i][j] = null;
		}
	}
	if (direction === 'left') {
		for (var i = 0; i < gridSize; i++) {
			var row = [];
			// Collect non-null tiles
			for (var j = 0; j < gridSize; j++) {
				if (grid[i][j] !== null) {
					row.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < row.length - 1; k++) {
				if (row[k].value === row[k + 1].value && !row[k].hasMerged && !row[k + 1].hasMerged) {
					row[k].setValue(row[k].value * 2);
					row[k].hasMerged = true;
					score += row[k].value;
					// Remove merged tile
					game.removeChild(row[k + 1]);
					tiles.splice(tiles.indexOf(row[k + 1]), 1);
					row.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < row.length; k++) {
				if (row[k].gridX !== k || row[k].gridY !== i) {
					moved = true;
				}
				row[k].gridX = k;
				row[k].gridY = i;
				newGrid[i][k] = row[k];
				row[k].updatePosition();
			}
		}
	} else if (direction === 'right') {
		for (var i = 0; i < gridSize; i++) {
			var row = [];
			// Collect non-null tiles
			for (var j = gridSize - 1; j >= 0; j--) {
				if (grid[i][j] !== null) {
					row.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < row.length - 1; k++) {
				if (row[k].value === row[k + 1].value && !row[k].hasMerged && !row[k + 1].hasMerged) {
					row[k].setValue(row[k].value * 2);
					row[k].hasMerged = true;
					score += row[k].value;
					// Remove merged tile
					game.removeChild(row[k + 1]);
					tiles.splice(tiles.indexOf(row[k + 1]), 1);
					row.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < row.length; k++) {
				var newX = gridSize - 1 - k;
				if (row[k].gridX !== newX || row[k].gridY !== i) {
					moved = true;
				}
				row[k].gridX = newX;
				row[k].gridY = i;
				newGrid[i][newX] = row[k];
				row[k].updatePosition();
			}
		}
	} else if (direction === 'up') {
		for (var j = 0; j < gridSize; j++) {
			var column = [];
			// Collect non-null tiles
			for (var i = 0; i < gridSize; i++) {
				if (grid[i][j] !== null) {
					column.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < column.length - 1; k++) {
				if (column[k].value === column[k + 1].value && !column[k].hasMerged && !column[k + 1].hasMerged) {
					column[k].setValue(column[k].value * 2);
					column[k].hasMerged = true;
					score += column[k].value;
					// Remove merged tile
					game.removeChild(column[k + 1]);
					tiles.splice(tiles.indexOf(column[k + 1]), 1);
					column.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < column.length; k++) {
				if (column[k].gridX !== j || column[k].gridY !== k) {
					moved = true;
				}
				column[k].gridX = j;
				column[k].gridY = k;
				newGrid[k][j] = column[k];
				column[k].updatePosition();
			}
		}
	} else if (direction === 'down') {
		for (var j = 0; j < gridSize; j++) {
			var column = [];
			// Collect non-null tiles
			for (var i = gridSize - 1; i >= 0; i--) {
				if (grid[i][j] !== null) {
					column.push(grid[i][j]);
				}
			}
			// Merge tiles
			for (var k = 0; k < column.length - 1; k++) {
				if (column[k].value === column[k + 1].value && !column[k].hasMerged && !column[k + 1].hasMerged) {
					column[k].setValue(column[k].value * 2);
					column[k].hasMerged = true;
					score += column[k].value;
					// Remove merged tile
					game.removeChild(column[k + 1]);
					tiles.splice(tiles.indexOf(column[k + 1]), 1);
					column.splice(k + 1, 1);
					LK.getSound('merge').play();
				}
			}
			// Place tiles in new positions
			for (var k = 0; k < column.length; k++) {
				var newY = gridSize - 1 - k;
				if (column[k].gridX !== j || column[k].gridY !== newY) {
					moved = true;
				}
				column[k].gridX = j;
				column[k].gridY = newY;
				newGrid[newY][j] = column[k];
				column[k].updatePosition();
			}
		}
	}
	grid = newGrid;
	if (moved) {
		LK.setScore(LK.getScore() + score);
		scoreTxt.setText(LK.getScore());
		LK.getSound('move').play();
		isMoving = true;
		LK.setTimeout(function () {
			addRandomTile();
			isMoving = false;
			if (!checkGameWon()) {
				checkGameOver();
			}
		}, 200);
	}
	return moved;
}
// Touch controls
var startX = 0;
var startY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
	startX = x;
	startY = y;
	isDragging = true;
};
game.up = function (x, y, obj) {
	if (!isDragging) return;
	var deltaX = x - startX;
	var deltaY = y - startY;
	var minSwipeDistance = 50;
	if (Math.abs(deltaX) > minSwipeDistance || Math.abs(deltaY) > minSwipeDistance) {
		if (Math.abs(deltaX) > Math.abs(deltaY)) {
			// Horizontal swipe
			if (deltaX > 0) {
				moveTiles('right');
			} else {
				moveTiles('left');
			}
		} else {
			// Vertical swipe
			if (deltaY > 0) {
				moveTiles('down');
			} else {
				moveTiles('up');
			}
		}
	}
	isDragging = false;
};
// Add initial tiles
addRandomTile();
addRandomTile();
game.update = function () {
	scoreTxt.setText(LK.getScore());
};