/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Card class: represents a single card in the memory game
var Card = Container.expand(function () {
	var self = Container.call(this);
	// Card properties
	self.symbol = null; // Symbol or id for matching
	self.isFaceUp = false;
	self.isMatched = false;
	self.index = -1; // Position in the grid
	// Card dimensions (will be set in game code)
	self.cardWidth = 0;
	self.cardHeight = 0;
	// Face-down asset (back of card)
	var backAssetId;
	var frontAssetId = 'cardFront';
	if (typeof currentLevel !== "undefined" && currentLevel > 45) {
		backAssetId = 'CardBack8';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 35) {
		backAssetId = 'Cardback7';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 25) {
		backAssetId = 'CardBack6';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 20) {
		backAssetId = 'CardBack5';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 15) {
		backAssetId = 'CardBack4';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 10) {
		backAssetId = 'CardBack3';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 5) {
		backAssetId = 'CardBack2';
	} else {
		backAssetId = 'cardBack';
	}
	var back = self.attachAsset(backAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Face-up asset (front of card, shows symbol)
	var front = self.attachAsset(frontAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Symbol text (shows symbol when face up)
	var symbolText = new Text2('', {
		size: 90,
		fill: 0x222222
	});
	symbolText.anchor.set(0.5, 0.5);
	front.addChild(symbolText);
	// Set card size
	self.setSize = function (w, h) {
		self.cardWidth = w;
		self.cardHeight = h;
		back.width = w;
		back.height = h;
		front.width = w;
		front.height = h;
	};
	// Set the symbol for this card
	self.setSymbol = function (symbol) {
		self.symbol = symbol;
		symbolText.setText(symbol);
	};
	// Flip the card to face up (with animation)
	self.flipUp = function (_onFinish) {
		if (self.isFaceUp || self.isMatched) {
			return;
		}
		self.isFaceUp = true;
		// Animate flip: scaleX 1 -> 0, swap, 0 -> 1
		tween(self, {
			scaleX: 0
		}, {
			duration: 120,
			easing: tween.cubicIn,
			onFinish: function onFinish() {
				back.visible = false;
				front.visible = true;
				tween(self, {
					scaleX: 1
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (_onFinish) {
							_onFinish();
						}
					}
				});
			}
		});
	};
	// Flip the card to face down (with animation)
	self.flipDown = function (_onFinish2) {
		if (!self.isFaceUp || self.isMatched) {
			return;
		}
		self.isFaceUp = false;
		// Animate flip: scaleX 1 -> 0, swap, 0 -> 1
		tween(self, {
			scaleX: 0
		}, {
			duration: 120,
			easing: tween.cubicIn,
			onFinish: function onFinish() {
				front.visible = false;
				back.visible = true;
				tween(self, {
					scaleX: 1
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (_onFinish2) {
							_onFinish2();
						}
					}
				});
			}
		});
	};
	// Instantly show face up (no animation)
	self.showFaceUp = function () {
		self.isFaceUp = true;
		self.scaleX = 1;
		back.visible = false;
		front.visible = true;
	};
	// Instantly show face down (no animation)
	self.showFaceDown = function () {
		self.isFaceUp = false;
		self.scaleX = 1;
		front.visible = false;
		back.visible = true;
	};
	// Mark as matched (disable interaction, highlight)
	self.setMatched = function () {
		self.isMatched = true;
		// Subtle highlight
		tween(self, {
			tint: 0xA0FFA0
		}, {
			duration: 300,
			easing: tween.linear
		});
	};
	// Handle tap/click
	self.down = function (x, y, obj) {
		if (self.isFaceUp || self.isMatched || game.lockInput) {
			return;
		}
		game.onCardTapped(self);
	};
	// Initialize: show face down
	self.showFaceDown();
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x2e3a4f // Deep blue background
});
/**** 
* Game Code
****/ 
// --- Card symbols (use simple emojis for MVP) ---
// Tween plugin for card flip and reveal animations
var cardSymbols = ["๐", "๐", "๐", "๐", "๐", "๐", "๐", "๐", "๐ฅ", "๐ฅ", "๐", "๐", "๐", "๐", "๐ฅฅ", "๐
", "๐ฅญ", "๐โ๐ฉ"];
var cardSymbols2 = ["๐ถ", "๐ฑ", "๐ญ", "๐ฐ", "๐ฆ", "๐ป", "๐ผ", "๐จ", "๐ฏ", "๐ฆ", "๐ฎ", "๐ท", "๐ธ", "๐ต", "๐", "๐ง", "๐ฆ", "๐ฆโโฌ", "๐ฅ", "๐ฆ", "๐ฆ
", "๐ฆ", "๐ฆ", "๐บ", "๐ฆ", "๐", "๐ท", "๐ฆ"];
var cardSymbols3 = ["๐", "๐", "๐", "๐", "๐", "๐๏ธ", "๐", "๐", "๐", "๐", "๐ป", "๐", "๐", "๐", "๐ต", "๐๏ธ", "๐ด", "๐ฒ", "๐บ", "๐ค", "โต๏ธ", "๐ถ", "๐ฉ๏ธ", "โ๏ธ", "๐ฐ๏ธ", "๐", "๐", "๐ธ"];
var cardSymbols4 = ["๐งฐ", "๐ช", "๐ง", "๐จ", "โ๏ธ", "๐ ๏ธ", "โ๏ธ", "๐ช", "๐ช", "๐ฉ", "โ๏ธ", "๐ชค", "๐งฑ", "๐งฒ", "๐ซ", "๐ฃ", "๐งจ", "๐ช", "๐ช", "๐ก๏ธ", "โ๏ธ", "๐ก๏ธ", "๐ชฆ", "๐", "๐ช", "๐", "๐", "๐", "๐ฌ", "โ๏ธ", "๐ช", "๐น", "๐ฅ", "๐ฅ", "๐ท", "๐บ", "๐ธ", "๐น", "๐ฅ", "๐ฅ"];
// --- Game settings ---
var maxLevel = 50;
var currentLevel = 1;
// Level configuration: grid size per level (increase difficulty)
function getLevelConfig(level) {
	// Level 1-5: 4x4, 6-10: 5x4, 11-15: 6x5, 16-20: 6x6, 21-25: 7x6
	if (level <= 5) {
		return {
			cols: 4,
			rows: 4
		};
	}
	if (level <= 10) {
		return {
			cols: 5,
			rows: 4
		};
	}
	if (level <= 15) {
		return {
			cols: 6,
			rows: 5
		};
	}
	if (level <= 20) {
		return {
			cols: 6,
			rows: 6
		};
	}
	if (level <= 35) {
		return {
			cols: 8,
			rows: 6
		};
	}
	if (level <= 45) {
		return {
			cols: 8,
			rows: 7
		};
	}
	if (level < 50) {
		return {
			cols: 8,
			rows: 7
		};
	}
	if (level >= 50) {
		return {
			cols: 10,
			rows: 8
		};
	}
	return {
		cols: 9,
		rows: 7
	};
}
var gridCols = getLevelConfig(currentLevel).cols;
var gridRows = getLevelConfig(currentLevel).rows;
var totalPairs = gridCols * gridRows / 2;
var cardSpacing = 36; // px between cards
// --- Card assets (simple colored rectangles) ---
// --- Game state ---
var cards = []; // All card objects
var firstCard = null;
var secondCard = null;
var lockInput = false; // Prevent input during animations
var moves = 0;
var matchesFound = 0;
var timer = null;
var elapsedTime = 0; // in seconds
var timerText = null;
var movesText = null;
// --- GUI: Moves, Timer, Level ---
var levelText = new Text2('Level: 1', {
	size: 80,
	fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
timerText = new Text2('Time: 0s', {
	size: 80,
	fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// Position GUI elements (timer right, avoid top-left 100x100)
// Align level indicator to top middle using LK.gui.top
levelText.x = -10;
levelText.y = 20;
timerText.x = 500;
// --- Timer for random swap after level 35 ---
var randomSwapTimer = null;
var randomSwapTimer10s = null;
var randomSwapTimer5s = null;
var randomSwapTimer2s = null;
// --- Swap queue for level 50+ to prevent overlapping swaps ---
var swapQueue = [];
var swapInProgress = false;
// Helper: Queue a swap (for level 50+)
function queueCardSwap(cardA, cardB) {
	swapQueue.push({
		cardA: cardA,
		cardB: cardB
	});
	processSwapQueue();
}
// Helper: Process swap queue (for level 50+)
function processSwapQueue() {
	if (swapInProgress || swapQueue.length === 0) {
		return;
	}
	swapInProgress = true;
	var swap = swapQueue.shift();
	var cardA = swap.cardA;
	var cardB = swap.cardB;
	var tempSymbol = cardA.symbol;
	var tempIndex = cardA.index;
	cardA.setSymbol(cardB.symbol);
	cardB.setSymbol(tempSymbol);
	// Swap index property as well
	cardA.index = cardB.index;
	cardB.index = tempIndex;
	var tempX = cardA.x;
	var tempY = cardA.y;
	var swapsDone = 0;
	function onSwapDone() {
		swapsDone++;
		if (swapsDone === 2) {
			swapInProgress = false;
			// Snap to grid to avoid drift
			cardA.x = Math.round(cardA.x);
			cardA.y = Math.round(cardA.y);
			cardB.x = Math.round(cardB.x);
			cardB.y = Math.round(cardB.y);
			processSwapQueue();
		}
	}
	tween(cardA, {
		x: cardB.x,
		y: cardB.y
	}, {
		duration: 1200,
		easing: tween.cubicInOut,
		onFinish: onSwapDone
	});
	tween(cardB, {
		x: tempX,
		y: tempY
	}, {
		duration: 1200,
		easing: tween.cubicInOut,
		onFinish: onSwapDone
	});
}
// --- Helper: Shuffle array (Fisher-Yates) ---
function shuffleArray(arr) {
	for (var i = arr.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}
// --- Layout cards ---
function layoutCards() {
	// Remove old cards if any
	for (var i = 0; i < cards.length; i++) {
		cards[i].destroy();
	}
	cards = [];
	// Prepare symbols (duplicate and shuffle)
	var symbols = [];
	var useSymbols;
	if (currentLevel === 9 || currentLevel === 41) {
		useSymbols = cardSymbols3;
	} else {
		useSymbols = currentLevel >= 50 ? cardSymbols4 : currentLevel > 45 ? cardSymbols3 : currentLevel > 20 ? cardSymbols2 : cardSymbols;
	}
	for (var i = 0; i < totalPairs; i++) {
		symbols.push(useSymbols[i]);
		symbols.push(useSymbols[i]);
	}
	shuffleArray(symbols);
	// Card size: fit grid to 2048x2732 with spacing
	var availableWidth = 2048 - cardSpacing * (gridCols + 1);
	var availableHeight = 1800 - cardSpacing * (gridRows + 1); // leave space for GUI
	var cardWidth = Math.floor(availableWidth / gridCols);
	var cardHeight = Math.floor(availableHeight / gridRows);
	// Center grid
	var gridPixelWidth = cardWidth * gridCols + cardSpacing * (gridCols - 1);
	var gridPixelHeight = cardHeight * gridRows + cardSpacing * (gridRows - 1);
	var startX = Math.floor((2048 - gridPixelWidth) / 2) + cardWidth / 2;
	var startY = 350 + cardHeight / 2; // leave space for GUI
	// Create cards
	for (var row = 0; row < gridRows; row++) {
		for (var col = 0; col < gridCols; col++) {
			var idx = row * gridCols + col;
			var card = new Card();
			card.setSize(cardWidth, cardHeight);
			card.setSymbol(symbols[idx]);
			card.index = idx;
			card.x = startX + col * (cardWidth + cardSpacing);
			card.y = startY + row * (cardHeight + cardSpacing);
			card.showFaceDown();
			game.addChild(card);
			cards.push(card);
		}
	}
}
// --- Reset game state ---
function resetGame() {
	firstCard = null;
	secondCard = null;
	lockInput = false;
	moves = 0;
	matchesFound = 0;
	if (currentLevel === 16) {
		elapsedTime = 150;
	} else if (currentLevel === 21) {
		elapsedTime = 150;
	} else if (currentLevel === 26) {
		elapsedTime = 200;
	} else if (currentLevel === 31) {
		elapsedTime = 200;
	} else if (currentLevel === 36) {
		elapsedTime = 250;
	} else if (currentLevel === 41) {
		elapsedTime = 250;
	} else if (currentLevel === 46) {
		elapsedTime = 300;
	} else if (currentLevel === 50) {
		elapsedTime = 500;
	} else if (currentLevel === 1) {
		elapsedTime = 100;
	} else if (currentLevel === 6 || currentLevel === 11) {
		elapsedTime = 120;
	} else {
		elapsedTime = 120;
	}
	if (typeof levelText !== "undefined") {
		// At level 6, display Level: 2 instead of Level: 6
		if (currentLevel === 6) {
			levelText.setText('Level: 2');
		} else if (currentLevel === 11) {
			levelText.setText('Level: 3');
		} else if (currentLevel === 16) {
			levelText.setText('Level: 4');
		} else if (currentLevel === 21) {
			levelText.setText('Level: 5');
		} else if (currentLevel === 26) {
			levelText.setText('Level: 6');
		} else if (currentLevel === 31) {
			levelText.setText('Level: 7');
		} else if (currentLevel === 36) {
			levelText.setText('Level: 8');
		} else if (currentLevel === 41) {
			levelText.setText('Level: 9');
		} else if (currentLevel === 46) {
			levelText.setText('Level: 10');
		} else if (currentLevel === 50) {
			levelText.setText('Final Level');
		} else if (currentLevel === 26) {
			levelText.setText('Level: 6');
		} else if (currentLevel === 21) {
			levelText.setText('Level: 5');
		} else if (currentLevel === 16) {
			levelText.setText('Level: 4');
		} else {
			levelText.setText('Level: ' + currentLevel);
		}
	}
	// Update grid size for this level
	var config = getLevelConfig(currentLevel);
	gridCols = config.cols;
	gridRows = config.rows;
	totalPairs = gridCols * gridRows / 2;
	timerText.setText('Time: ' + elapsedTime + 's');
	layoutCards();
	// Play lastlevelmusic at level 50
	if (currentLevel === 50) {
		LK.playMusic('lastlevelmusic');
	}
	if (timer) {
		LK.clearInterval(timer);
	}
	timer = LK.setInterval(function () {
		elapsedTime--;
		if (elapsedTime <= 0) {
			elapsedTime = 0;
			timerText.setText('Time: 0s');
			LK.clearInterval(timer);
			LK.showGameOver(); // You lose if timer gets to 0
			return;
		} else {
			timerText.setText('Time: ' + elapsedTime + 's');
		}
	}, 1000);
	// --- Timer-based random swap after level 35 ---
	if (typeof randomSwapTimer !== "undefined" && randomSwapTimer) {
		LK.clearInterval(randomSwapTimer);
		randomSwapTimer = null;
	}
	if (currentLevel >= 50) {
		// At level 50, swap every 2s, 5s, 10s, and 20s using the swap queue
		swapQueue = [];
		swapInProgress = false;
		randomSwapTimer = LK.setInterval(function () {
			// 20s swap
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 20000); // 20 seconds
		// Add a second timer for 10s swap
		if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
			LK.clearInterval(randomSwapTimer10s);
			randomSwapTimer10s = null;
		}
		randomSwapTimer10s = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 10000); // 10 seconds
		// Add a third timer for 5s swap
		if (typeof randomSwapTimer5s !== "undefined" && randomSwapTimer5s) {
			LK.clearInterval(randomSwapTimer5s);
			randomSwapTimer5s = null;
		}
		randomSwapTimer5s = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 5000); // 5 seconds
		// Add a fourth timer for 2s swap
		if (typeof randomSwapTimer2s !== "undefined" && randomSwapTimer2s) {
			LK.clearInterval(randomSwapTimer2s);
			randomSwapTimer2s = null;
		}
		randomSwapTimer2s = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 2000); // 2 seconds
	} else if (currentLevel > 40) {
		// Only 20s swap
		randomSwapTimer = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				var tempSymbol = cardA.symbol;
				var tempIndex = cardA.index;
				cardA.setSymbol(cardB.symbol);
				cardB.setSymbol(tempSymbol);
				// Swap index property as well
				cardA.index = cardB.index;
				cardB.index = tempIndex;
				var tempX = cardA.x;
				var tempY = cardA.y;
				tween(cardA, {
					x: cardB.x,
					y: cardB.y
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
				tween(cardB, {
					x: tempX,
					y: tempY
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
			}
		}, 20000); // 20 seconds
		// Clear 10s timer if it exists
		if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
			LK.clearInterval(randomSwapTimer10s);
			randomSwapTimer10s = null;
		}
	} else {
		randomSwapTimer = null;
		if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
			LK.clearInterval(randomSwapTimer10s);
			randomSwapTimer10s = null;
		}
	}
}
// --- Card tap handler ---
game.onCardTapped = function (card) {
	if (lockInput || card.isFaceUp || card.isMatched) {
		return;
	}
	if (!firstCard) {
		firstCard = card;
		LK.getSound('cardchose').play();
		card.flipUp();
	} else if (!secondCard && card !== firstCard) {
		secondCard = card;
		lockInput = true;
		LK.getSound('cardchose').play();
		card.flipUp(function () {
			// Check for match after both are face up
			LK.setTimeout(function () {
				checkMatch();
			}, 150);
		});
	}
};
// --- Check for match ---
function checkMatch() {
	moves++;
	// After level 40, swap 2 random cards every 2 moves; after level 30, every 4 moves; after level 25, every 5 moves; after level 20, every 10 moves
	var shouldSwap = false;
	if (currentLevel >= 50 && moves % 1 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 40 && moves % 2 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 30 && moves % 4 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 25 && moves % 5 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 20 && moves % 10 === 0 && cards.length > 1) {
		shouldSwap = true;
	}
	if (shouldSwap) {
		// Find all cards that are not matched and not currently face up
		var swappable = [];
		for (var i = 0; i < cards.length; i++) {
			if (!cards[i].isMatched && !cards[i].isFaceUp) {
				swappable.push(cards[i]);
			}
		}
		if (swappable.length >= 2) {
			var idx1 = Math.floor(Math.random() * swappable.length);
			var idx2 = idx1;
			while (idx2 === idx1) {
				idx2 = Math.floor(Math.random() * swappable.length);
			}
			var cardA = swappable[idx1];
			var cardB = swappable[idx2];
			if (currentLevel >= 50) {
				queueCardSwap(cardA, cardB);
			} else {
				// Old behavior for lower levels
				var tempSymbol = cardA.symbol;
				var tempIndex = cardA.index;
				cardA.setSymbol(cardB.symbol);
				cardB.setSymbol(tempSymbol);
				// Swap index property as well
				cardA.index = cardB.index;
				cardB.index = tempIndex;
				var tempX = cardA.x;
				var tempY = cardA.y;
				tween(cardA, {
					x: cardB.x,
					y: cardB.y
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
				tween(cardB, {
					x: tempX,
					y: tempY
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
			}
		}
	}
	if (firstCard && secondCard && firstCard.symbol === secondCard.symbol) {
		// Match!
		LK.getSound('cardmatch').play();
		firstCard.setMatched();
		secondCard.setMatched();
		matchesFound++;
		// Subtle scale animation for matched cards, then disappear
		if (firstCard && secondCard) {
			var matched1 = firstCard;
			var matched2 = secondCard;
			if (matched1) {
				tween(matched1, {
					scaleX: 1.15,
					scaleY: 1.15
				}, {
					duration: 80,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (matched1) {
							tween(matched1, {
								scaleX: 0,
								scaleY: 0,
								alpha: 0
							}, {
								duration: 120,
								onFinish: function onFinish() {
									if (matched1) {
										matched1.destroy();
									}
								}
							});
						}
					}
				});
			}
			if (matched2) {
				tween(matched2, {
					scaleX: 1.15,
					scaleY: 1.15
				}, {
					duration: 80,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (matched2) {
							tween(matched2, {
								scaleX: 0,
								scaleY: 0,
								alpha: 0
							}, {
								duration: 120,
								onFinish: function onFinish() {
									if (matched2) {
										matched2.destroy();
									}
								}
							});
						}
					}
				});
			}
		}
		// Check for win
		if (matchesFound === totalPairs) {
			LK.clearInterval(timer);
			LK.setScore(moves); // Use moves as score (lower is better)
			if (currentLevel < maxLevel) {
				// Play level completed sound
				LK.getSound('levelcompleted').play();
				// Show "Level Completed" text in the center of the screen
				var levelCompletedText = new Text2('Level Completed!', {
					size: 180,
					fill: 0xFFD700,
					font: "Impact"
				});
				levelCompletedText.anchor.set(0.5, 0.5);
				levelCompletedText.x = 2048 / 2;
				levelCompletedText.y = 2732 / 2;
				game.addChild(levelCompletedText);
				if (currentLevel === 1) {
					currentLevel = 6;
				} else if (currentLevel === 6) {
					currentLevel = 11;
				} else if (currentLevel === 11) {
					currentLevel = 16;
				} else if (currentLevel === 16) {
					currentLevel = 21;
				} else if (currentLevel === 21) {
					currentLevel = 26;
				} else if (currentLevel === 26) {
					currentLevel = 31;
				} else if (currentLevel === 31) {
					currentLevel = 36;
				} else if (currentLevel === 36) {
					currentLevel = 41;
				} else if (currentLevel === 41) {
					currentLevel = 46;
				} else if (currentLevel === 46) {
					currentLevel = 50;
				} else {
					currentLevel++;
				}
				// Short delay before next level, remove text before reset
				LK.setTimeout(function () {
					if (levelCompletedText && typeof levelCompletedText.destroy === "function") {
						levelCompletedText.destroy();
					}
					resetGame();
				}, 1200);
			} else {
				LK.showYouWin();
			}
		}
		// Reset selection
		firstCard = null;
		secondCard = null;
		lockInput = false;
	} else {
		// Not a match: flip both back after short delay
		LK.setTimeout(function () {
			if (firstCard && typeof firstCard.flipDown === "function") {
				firstCard.flipDown();
			}
			if (secondCard && typeof secondCard.flipDown === "function") {
				secondCard.flipDown(function () {
					firstCard = null;
					secondCard = null;
					lockInput = false;
				});
			} else {
				// If secondCard is missing, still reset state after delay
				firstCard = null;
				secondCard = null;
				lockInput = false;
			}
		}, 250);
	}
}
// --- Game update (not used for logic, but required) ---
game.update = function () {
	// Movement-based card swap: if two cards are dragged/moved to each other's position, swap their symbol and index
	// (Assuming you have a drag/move system, e.g. for future features or mobile drag-to-swap)
	// This is a defensive implementation: checks for cards that overlap and are not already matched or face up
	for (var i = 0; i < cards.length; i++) {
		var cardA = cards[i];
		if (cardA.isMatched || cardA.isFaceUp) continue;
		for (var j = i + 1; j < cards.length; j++) {
			var cardB = cards[j];
			if (cardB.isMatched || cardB.isFaceUp) continue;
			// If cardA and cardB overlap (bounding box collision)
			if (Math.abs(cardA.x - cardB.x) < (cardA.cardWidth + cardB.cardWidth) / 2 && Math.abs(cardA.y - cardB.y) < (cardA.cardHeight + cardB.cardHeight) / 2) {
				// Only swap if not already swapped this frame
				if (!cardA._swappedThisFrame && !cardB._swappedThisFrame) {
					// Swap symbol and index
					var tempSymbol = cardA.symbol;
					var tempIndex = cardA.index;
					cardA.setSymbol(cardB.symbol);
					cardB.setSymbol(tempSymbol);
					cardA.index = cardB.index;
					cardB.index = tempIndex;
					cardA._swappedThisFrame = true;
					cardB._swappedThisFrame = true;
				}
			}
		}
	}
	// Reset swap flags for next frame
	for (var i = 0; i < cards.length; i++) {
		cards[i]._swappedThisFrame = false;
	}
};
// --- DEV Button: Center bottom, always visible, go to next level ---
// (Hidden for production, but function remains for later update test)
var devBtn = new Text2('DEV', {
	size: 90,
	fill: 0xFF00FF,
	font: "Impact"
});
devBtn.anchor.set(0.5, 1);
// Place DEV button slightly left of center
devBtn.x = -120;
devBtn.y = -50;
// LK.gui.bottom.addChild(devBtn); // HIDDEN: do not add to GUI, but keep logic for later test
devBtn.visible = false; // Hide from view
// DEV button handler: go to next level immediately (max 25)
devBtn.down = function (x, y, obj) {
	if (matchesFound === totalPairs) {
		// Already won, do nothing
		return;
	}
	// Replicate the level pass logic from checkMatch()
	if (currentLevel < maxLevel) {
		// Play level completed sound
		LK.getSound('levelcompleted').play();
		// Show "Level Completed" text in the center of the screen
		var levelCompletedText = new Text2('Level Completed!', {
			size: 180,
			fill: 0xFFD700,
			font: "Impact"
		});
		levelCompletedText.anchor.set(0.5, 0.5);
		levelCompletedText.x = 2048 / 2;
		levelCompletedText.y = 2732 / 2;
		game.addChild(levelCompletedText);
		if (currentLevel === 1) {
			currentLevel = 6;
		} else if (currentLevel === 6) {
			currentLevel = 11;
		} else if (currentLevel === 11) {
			currentLevel = 16;
		} else if (currentLevel === 16) {
			currentLevel = 21;
		} else if (currentLevel === 21) {
			currentLevel = 26;
		} else if (currentLevel === 26) {
			levelText.setText('Level: 6');
			currentLevel = 31;
		} else if (currentLevel === 31) {
			levelText.setText('Level: 7');
			currentLevel = 36;
		} else if (currentLevel === 36) {
			levelText.setText('Level: 8');
			levelText.setText('Level: 8');
			currentLevel = 41;
		} else if (currentLevel === 41) {
			levelText.setText('Level: 9');
			currentLevel = 46;
		} else if (currentLevel === 46) {
			levelText.setText('Level: 10');
			currentLevel = 50;
		} else if (currentLevel === 50) {
			levelText.setText('Final Level');
			currentLevel = 50;
		} else {
			currentLevel++;
		}
		LK.setTimeout(function () {
			if (levelCompletedText && typeof levelCompletedText.destroy === "function") {
				levelCompletedText.destroy();
			}
			resetGame();
		}, 1200);
	} else {
		LK.showYouWin();
	}
};
// --- Reveal Button: Center bottom, always visible, reveals all cards ---
// (Hidden for production, but function remains for later update test)
var revealBtn = new Text2('Reveal', {
	size: 90,
	fill: 0x00CCFF,
	font: "Impact"
});
revealBtn.anchor.set(0.5, 1);
// Place Reveal button slightly right of center
revealBtn.x = 120;
revealBtn.y = -50;
// LK.gui.bottom.addChild(revealBtn); // HIDDEN: do not add to GUI, but keep logic for later test
revealBtn.visible = false; // Hide from view
// Reveal button handler: toggle all cards between revealed and hidden
var revealState = false; // false = hidden, true = revealed
revealBtn.down = function (x, y, obj) {
	revealState = !revealState;
	if (revealState) {
		// Reveal all cards (that are not matched)
		for (var i = 0; i < cards.length; i++) {
			var card = cards[i];
			if (!card.isFaceUp && !card.isMatched) {
				card.flipUp();
			}
		}
		revealBtn.setText('Hide');
	} else {
		// Hide all cards (that are not matched)
		for (var i = 0; i < cards.length; i++) {
			var card = cards[i];
			if (card.isFaceUp && !card.isMatched) {
				card.flipDown();
			}
		}
		revealBtn.setText('Reveal');
	}
};
// --- Start game ---
LK.playMusic('gamemusic');
resetGame();
// --- Game over handler (reset on game over) ---
game.onGameOver = function () {
	if (timer) {
		LK.clearInterval(timer);
	}
	if (typeof randomSwapTimer !== "undefined" && randomSwapTimer) {
		LK.clearInterval(randomSwapTimer);
		randomSwapTimer = null;
	}
	if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
		LK.clearInterval(randomSwapTimer10s);
		randomSwapTimer10s = null;
	}
	if (typeof randomSwapTimer5s !== "undefined" && randomSwapTimer5s) {
		LK.clearInterval(randomSwapTimer5s);
		randomSwapTimer5s = null;
	}
	if (typeof randomSwapTimer2s !== "undefined" && randomSwapTimer2s) {
		LK.clearInterval(randomSwapTimer2s);
		randomSwapTimer2s = null;
	}
	currentLevel = 1;
	LK.stopMusic();
	resetGame();
};
// --- Win handler (reset on win) ---
game.onYouWin = function () {
	if (timer) {
		LK.clearInterval(timer);
	}
	if (typeof randomSwapTimer !== "undefined" && randomSwapTimer) {
		LK.clearInterval(randomSwapTimer);
		randomSwapTimer = null;
	}
	if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
		LK.clearInterval(randomSwapTimer10s);
		randomSwapTimer10s = null;
	}
	if (typeof randomSwapTimer5s !== "undefined" && randomSwapTimer5s) {
		LK.clearInterval(randomSwapTimer5s);
		randomSwapTimer5s = null;
	}
	if (typeof randomSwapTimer2s !== "undefined" && randomSwapTimer2s) {
		LK.clearInterval(randomSwapTimer2s);
		randomSwapTimer2s = null;
	}
	currentLevel = 1;
	LK.stopMusic();
	// Game will reset automatically by LK
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Card class: represents a single card in the memory game
var Card = Container.expand(function () {
	var self = Container.call(this);
	// Card properties
	self.symbol = null; // Symbol or id for matching
	self.isFaceUp = false;
	self.isMatched = false;
	self.index = -1; // Position in the grid
	// Card dimensions (will be set in game code)
	self.cardWidth = 0;
	self.cardHeight = 0;
	// Face-down asset (back of card)
	var backAssetId;
	var frontAssetId = 'cardFront';
	if (typeof currentLevel !== "undefined" && currentLevel > 45) {
		backAssetId = 'CardBack8';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 35) {
		backAssetId = 'Cardback7';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 25) {
		backAssetId = 'CardBack6';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 20) {
		backAssetId = 'CardBack5';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 15) {
		backAssetId = 'CardBack4';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 10) {
		backAssetId = 'CardBack3';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 5) {
		backAssetId = 'CardBack2';
	} else {
		backAssetId = 'cardBack';
	}
	var back = self.attachAsset(backAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Face-up asset (front of card, shows symbol)
	var front = self.attachAsset(frontAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Symbol text (shows symbol when face up)
	var symbolText = new Text2('', {
		size: 90,
		fill: 0x222222
	});
	symbolText.anchor.set(0.5, 0.5);
	front.addChild(symbolText);
	// Set card size
	self.setSize = function (w, h) {
		self.cardWidth = w;
		self.cardHeight = h;
		back.width = w;
		back.height = h;
		front.width = w;
		front.height = h;
	};
	// Set the symbol for this card
	self.setSymbol = function (symbol) {
		self.symbol = symbol;
		symbolText.setText(symbol);
	};
	// Flip the card to face up (with animation)
	self.flipUp = function (_onFinish) {
		if (self.isFaceUp || self.isMatched) {
			return;
		}
		self.isFaceUp = true;
		// Animate flip: scaleX 1 -> 0, swap, 0 -> 1
		tween(self, {
			scaleX: 0
		}, {
			duration: 120,
			easing: tween.cubicIn,
			onFinish: function onFinish() {
				back.visible = false;
				front.visible = true;
				tween(self, {
					scaleX: 1
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (_onFinish) {
							_onFinish();
						}
					}
				});
			}
		});
	};
	// Flip the card to face down (with animation)
	self.flipDown = function (_onFinish2) {
		if (!self.isFaceUp || self.isMatched) {
			return;
		}
		self.isFaceUp = false;
		// Animate flip: scaleX 1 -> 0, swap, 0 -> 1
		tween(self, {
			scaleX: 0
		}, {
			duration: 120,
			easing: tween.cubicIn,
			onFinish: function onFinish() {
				front.visible = false;
				back.visible = true;
				tween(self, {
					scaleX: 1
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (_onFinish2) {
							_onFinish2();
						}
					}
				});
			}
		});
	};
	// Instantly show face up (no animation)
	self.showFaceUp = function () {
		self.isFaceUp = true;
		self.scaleX = 1;
		back.visible = false;
		front.visible = true;
	};
	// Instantly show face down (no animation)
	self.showFaceDown = function () {
		self.isFaceUp = false;
		self.scaleX = 1;
		front.visible = false;
		back.visible = true;
	};
	// Mark as matched (disable interaction, highlight)
	self.setMatched = function () {
		self.isMatched = true;
		// Subtle highlight
		tween(self, {
			tint: 0xA0FFA0
		}, {
			duration: 300,
			easing: tween.linear
		});
	};
	// Handle tap/click
	self.down = function (x, y, obj) {
		if (self.isFaceUp || self.isMatched || game.lockInput) {
			return;
		}
		game.onCardTapped(self);
	};
	// Initialize: show face down
	self.showFaceDown();
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x2e3a4f // Deep blue background
});
/**** 
* Game Code
****/ 
// --- Card symbols (use simple emojis for MVP) ---
// Tween plugin for card flip and reveal animations
var cardSymbols = ["๐", "๐", "๐", "๐", "๐", "๐", "๐", "๐", "๐ฅ", "๐ฅ", "๐", "๐", "๐", "๐", "๐ฅฅ", "๐
", "๐ฅญ", "๐โ๐ฉ"];
var cardSymbols2 = ["๐ถ", "๐ฑ", "๐ญ", "๐ฐ", "๐ฆ", "๐ป", "๐ผ", "๐จ", "๐ฏ", "๐ฆ", "๐ฎ", "๐ท", "๐ธ", "๐ต", "๐", "๐ง", "๐ฆ", "๐ฆโโฌ", "๐ฅ", "๐ฆ", "๐ฆ
", "๐ฆ", "๐ฆ", "๐บ", "๐ฆ", "๐", "๐ท", "๐ฆ"];
var cardSymbols3 = ["๐", "๐", "๐", "๐", "๐", "๐๏ธ", "๐", "๐", "๐", "๐", "๐ป", "๐", "๐", "๐", "๐ต", "๐๏ธ", "๐ด", "๐ฒ", "๐บ", "๐ค", "โต๏ธ", "๐ถ", "๐ฉ๏ธ", "โ๏ธ", "๐ฐ๏ธ", "๐", "๐", "๐ธ"];
var cardSymbols4 = ["๐งฐ", "๐ช", "๐ง", "๐จ", "โ๏ธ", "๐ ๏ธ", "โ๏ธ", "๐ช", "๐ช", "๐ฉ", "โ๏ธ", "๐ชค", "๐งฑ", "๐งฒ", "๐ซ", "๐ฃ", "๐งจ", "๐ช", "๐ช", "๐ก๏ธ", "โ๏ธ", "๐ก๏ธ", "๐ชฆ", "๐", "๐ช", "๐", "๐", "๐", "๐ฌ", "โ๏ธ", "๐ช", "๐น", "๐ฅ", "๐ฅ", "๐ท", "๐บ", "๐ธ", "๐น", "๐ฅ", "๐ฅ"];
// --- Game settings ---
var maxLevel = 50;
var currentLevel = 1;
// Level configuration: grid size per level (increase difficulty)
function getLevelConfig(level) {
	// Level 1-5: 4x4, 6-10: 5x4, 11-15: 6x5, 16-20: 6x6, 21-25: 7x6
	if (level <= 5) {
		return {
			cols: 4,
			rows: 4
		};
	}
	if (level <= 10) {
		return {
			cols: 5,
			rows: 4
		};
	}
	if (level <= 15) {
		return {
			cols: 6,
			rows: 5
		};
	}
	if (level <= 20) {
		return {
			cols: 6,
			rows: 6
		};
	}
	if (level <= 35) {
		return {
			cols: 8,
			rows: 6
		};
	}
	if (level <= 45) {
		return {
			cols: 8,
			rows: 7
		};
	}
	if (level < 50) {
		return {
			cols: 8,
			rows: 7
		};
	}
	if (level >= 50) {
		return {
			cols: 10,
			rows: 8
		};
	}
	return {
		cols: 9,
		rows: 7
	};
}
var gridCols = getLevelConfig(currentLevel).cols;
var gridRows = getLevelConfig(currentLevel).rows;
var totalPairs = gridCols * gridRows / 2;
var cardSpacing = 36; // px between cards
// --- Card assets (simple colored rectangles) ---
// --- Game state ---
var cards = []; // All card objects
var firstCard = null;
var secondCard = null;
var lockInput = false; // Prevent input during animations
var moves = 0;
var matchesFound = 0;
var timer = null;
var elapsedTime = 0; // in seconds
var timerText = null;
var movesText = null;
// --- GUI: Moves, Timer, Level ---
var levelText = new Text2('Level: 1', {
	size: 80,
	fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
timerText = new Text2('Time: 0s', {
	size: 80,
	fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// Position GUI elements (timer right, avoid top-left 100x100)
// Align level indicator to top middle using LK.gui.top
levelText.x = -10;
levelText.y = 20;
timerText.x = 500;
// --- Timer for random swap after level 35 ---
var randomSwapTimer = null;
var randomSwapTimer10s = null;
var randomSwapTimer5s = null;
var randomSwapTimer2s = null;
// --- Swap queue for level 50+ to prevent overlapping swaps ---
var swapQueue = [];
var swapInProgress = false;
// Helper: Queue a swap (for level 50+)
function queueCardSwap(cardA, cardB) {
	swapQueue.push({
		cardA: cardA,
		cardB: cardB
	});
	processSwapQueue();
}
// Helper: Process swap queue (for level 50+)
function processSwapQueue() {
	if (swapInProgress || swapQueue.length === 0) {
		return;
	}
	swapInProgress = true;
	var swap = swapQueue.shift();
	var cardA = swap.cardA;
	var cardB = swap.cardB;
	var tempSymbol = cardA.symbol;
	var tempIndex = cardA.index;
	cardA.setSymbol(cardB.symbol);
	cardB.setSymbol(tempSymbol);
	// Swap index property as well
	cardA.index = cardB.index;
	cardB.index = tempIndex;
	var tempX = cardA.x;
	var tempY = cardA.y;
	var swapsDone = 0;
	function onSwapDone() {
		swapsDone++;
		if (swapsDone === 2) {
			swapInProgress = false;
			// Snap to grid to avoid drift
			cardA.x = Math.round(cardA.x);
			cardA.y = Math.round(cardA.y);
			cardB.x = Math.round(cardB.x);
			cardB.y = Math.round(cardB.y);
			processSwapQueue();
		}
	}
	tween(cardA, {
		x: cardB.x,
		y: cardB.y
	}, {
		duration: 1200,
		easing: tween.cubicInOut,
		onFinish: onSwapDone
	});
	tween(cardB, {
		x: tempX,
		y: tempY
	}, {
		duration: 1200,
		easing: tween.cubicInOut,
		onFinish: onSwapDone
	});
}
// --- Helper: Shuffle array (Fisher-Yates) ---
function shuffleArray(arr) {
	for (var i = arr.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}
// --- Layout cards ---
function layoutCards() {
	// Remove old cards if any
	for (var i = 0; i < cards.length; i++) {
		cards[i].destroy();
	}
	cards = [];
	// Prepare symbols (duplicate and shuffle)
	var symbols = [];
	var useSymbols;
	if (currentLevel === 9 || currentLevel === 41) {
		useSymbols = cardSymbols3;
	} else {
		useSymbols = currentLevel >= 50 ? cardSymbols4 : currentLevel > 45 ? cardSymbols3 : currentLevel > 20 ? cardSymbols2 : cardSymbols;
	}
	for (var i = 0; i < totalPairs; i++) {
		symbols.push(useSymbols[i]);
		symbols.push(useSymbols[i]);
	}
	shuffleArray(symbols);
	// Card size: fit grid to 2048x2732 with spacing
	var availableWidth = 2048 - cardSpacing * (gridCols + 1);
	var availableHeight = 1800 - cardSpacing * (gridRows + 1); // leave space for GUI
	var cardWidth = Math.floor(availableWidth / gridCols);
	var cardHeight = Math.floor(availableHeight / gridRows);
	// Center grid
	var gridPixelWidth = cardWidth * gridCols + cardSpacing * (gridCols - 1);
	var gridPixelHeight = cardHeight * gridRows + cardSpacing * (gridRows - 1);
	var startX = Math.floor((2048 - gridPixelWidth) / 2) + cardWidth / 2;
	var startY = 350 + cardHeight / 2; // leave space for GUI
	// Create cards
	for (var row = 0; row < gridRows; row++) {
		for (var col = 0; col < gridCols; col++) {
			var idx = row * gridCols + col;
			var card = new Card();
			card.setSize(cardWidth, cardHeight);
			card.setSymbol(symbols[idx]);
			card.index = idx;
			card.x = startX + col * (cardWidth + cardSpacing);
			card.y = startY + row * (cardHeight + cardSpacing);
			card.showFaceDown();
			game.addChild(card);
			cards.push(card);
		}
	}
}
// --- Reset game state ---
function resetGame() {
	firstCard = null;
	secondCard = null;
	lockInput = false;
	moves = 0;
	matchesFound = 0;
	if (currentLevel === 16) {
		elapsedTime = 150;
	} else if (currentLevel === 21) {
		elapsedTime = 150;
	} else if (currentLevel === 26) {
		elapsedTime = 200;
	} else if (currentLevel === 31) {
		elapsedTime = 200;
	} else if (currentLevel === 36) {
		elapsedTime = 250;
	} else if (currentLevel === 41) {
		elapsedTime = 250;
	} else if (currentLevel === 46) {
		elapsedTime = 300;
	} else if (currentLevel === 50) {
		elapsedTime = 500;
	} else if (currentLevel === 1) {
		elapsedTime = 100;
	} else if (currentLevel === 6 || currentLevel === 11) {
		elapsedTime = 120;
	} else {
		elapsedTime = 120;
	}
	if (typeof levelText !== "undefined") {
		// At level 6, display Level: 2 instead of Level: 6
		if (currentLevel === 6) {
			levelText.setText('Level: 2');
		} else if (currentLevel === 11) {
			levelText.setText('Level: 3');
		} else if (currentLevel === 16) {
			levelText.setText('Level: 4');
		} else if (currentLevel === 21) {
			levelText.setText('Level: 5');
		} else if (currentLevel === 26) {
			levelText.setText('Level: 6');
		} else if (currentLevel === 31) {
			levelText.setText('Level: 7');
		} else if (currentLevel === 36) {
			levelText.setText('Level: 8');
		} else if (currentLevel === 41) {
			levelText.setText('Level: 9');
		} else if (currentLevel === 46) {
			levelText.setText('Level: 10');
		} else if (currentLevel === 50) {
			levelText.setText('Final Level');
		} else if (currentLevel === 26) {
			levelText.setText('Level: 6');
		} else if (currentLevel === 21) {
			levelText.setText('Level: 5');
		} else if (currentLevel === 16) {
			levelText.setText('Level: 4');
		} else {
			levelText.setText('Level: ' + currentLevel);
		}
	}
	// Update grid size for this level
	var config = getLevelConfig(currentLevel);
	gridCols = config.cols;
	gridRows = config.rows;
	totalPairs = gridCols * gridRows / 2;
	timerText.setText('Time: ' + elapsedTime + 's');
	layoutCards();
	// Play lastlevelmusic at level 50
	if (currentLevel === 50) {
		LK.playMusic('lastlevelmusic');
	}
	if (timer) {
		LK.clearInterval(timer);
	}
	timer = LK.setInterval(function () {
		elapsedTime--;
		if (elapsedTime <= 0) {
			elapsedTime = 0;
			timerText.setText('Time: 0s');
			LK.clearInterval(timer);
			LK.showGameOver(); // You lose if timer gets to 0
			return;
		} else {
			timerText.setText('Time: ' + elapsedTime + 's');
		}
	}, 1000);
	// --- Timer-based random swap after level 35 ---
	if (typeof randomSwapTimer !== "undefined" && randomSwapTimer) {
		LK.clearInterval(randomSwapTimer);
		randomSwapTimer = null;
	}
	if (currentLevel >= 50) {
		// At level 50, swap every 2s, 5s, 10s, and 20s using the swap queue
		swapQueue = [];
		swapInProgress = false;
		randomSwapTimer = LK.setInterval(function () {
			// 20s swap
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 20000); // 20 seconds
		// Add a second timer for 10s swap
		if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
			LK.clearInterval(randomSwapTimer10s);
			randomSwapTimer10s = null;
		}
		randomSwapTimer10s = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 10000); // 10 seconds
		// Add a third timer for 5s swap
		if (typeof randomSwapTimer5s !== "undefined" && randomSwapTimer5s) {
			LK.clearInterval(randomSwapTimer5s);
			randomSwapTimer5s = null;
		}
		randomSwapTimer5s = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 5000); // 5 seconds
		// Add a fourth timer for 2s swap
		if (typeof randomSwapTimer2s !== "undefined" && randomSwapTimer2s) {
			LK.clearInterval(randomSwapTimer2s);
			randomSwapTimer2s = null;
		}
		randomSwapTimer2s = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				queueCardSwap(cardA, cardB);
			}
		}, 2000); // 2 seconds
	} else if (currentLevel > 40) {
		// Only 20s swap
		randomSwapTimer = LK.setInterval(function () {
			var swappable = [];
			for (var i = 0; i < cards.length; i++) {
				if (!cards[i].isMatched && !cards[i].isFaceUp) {
					swappable.push(cards[i]);
				}
			}
			if (swappable.length >= 2) {
				var idx1 = Math.floor(Math.random() * swappable.length);
				var idx2 = idx1;
				while (idx2 === idx1) {
					idx2 = Math.floor(Math.random() * swappable.length);
				}
				var cardA = swappable[idx1];
				var cardB = swappable[idx2];
				var tempSymbol = cardA.symbol;
				var tempIndex = cardA.index;
				cardA.setSymbol(cardB.symbol);
				cardB.setSymbol(tempSymbol);
				// Swap index property as well
				cardA.index = cardB.index;
				cardB.index = tempIndex;
				var tempX = cardA.x;
				var tempY = cardA.y;
				tween(cardA, {
					x: cardB.x,
					y: cardB.y
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
				tween(cardB, {
					x: tempX,
					y: tempY
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
			}
		}, 20000); // 20 seconds
		// Clear 10s timer if it exists
		if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
			LK.clearInterval(randomSwapTimer10s);
			randomSwapTimer10s = null;
		}
	} else {
		randomSwapTimer = null;
		if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
			LK.clearInterval(randomSwapTimer10s);
			randomSwapTimer10s = null;
		}
	}
}
// --- Card tap handler ---
game.onCardTapped = function (card) {
	if (lockInput || card.isFaceUp || card.isMatched) {
		return;
	}
	if (!firstCard) {
		firstCard = card;
		LK.getSound('cardchose').play();
		card.flipUp();
	} else if (!secondCard && card !== firstCard) {
		secondCard = card;
		lockInput = true;
		LK.getSound('cardchose').play();
		card.flipUp(function () {
			// Check for match after both are face up
			LK.setTimeout(function () {
				checkMatch();
			}, 150);
		});
	}
};
// --- Check for match ---
function checkMatch() {
	moves++;
	// After level 40, swap 2 random cards every 2 moves; after level 30, every 4 moves; after level 25, every 5 moves; after level 20, every 10 moves
	var shouldSwap = false;
	if (currentLevel >= 50 && moves % 1 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 40 && moves % 2 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 30 && moves % 4 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 25 && moves % 5 === 0 && cards.length > 1) {
		shouldSwap = true;
	} else if (currentLevel > 20 && moves % 10 === 0 && cards.length > 1) {
		shouldSwap = true;
	}
	if (shouldSwap) {
		// Find all cards that are not matched and not currently face up
		var swappable = [];
		for (var i = 0; i < cards.length; i++) {
			if (!cards[i].isMatched && !cards[i].isFaceUp) {
				swappable.push(cards[i]);
			}
		}
		if (swappable.length >= 2) {
			var idx1 = Math.floor(Math.random() * swappable.length);
			var idx2 = idx1;
			while (idx2 === idx1) {
				idx2 = Math.floor(Math.random() * swappable.length);
			}
			var cardA = swappable[idx1];
			var cardB = swappable[idx2];
			if (currentLevel >= 50) {
				queueCardSwap(cardA, cardB);
			} else {
				// Old behavior for lower levels
				var tempSymbol = cardA.symbol;
				var tempIndex = cardA.index;
				cardA.setSymbol(cardB.symbol);
				cardB.setSymbol(tempSymbol);
				// Swap index property as well
				cardA.index = cardB.index;
				cardB.index = tempIndex;
				var tempX = cardA.x;
				var tempY = cardA.y;
				tween(cardA, {
					x: cardB.x,
					y: cardB.y
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
				tween(cardB, {
					x: tempX,
					y: tempY
				}, {
					duration: 1200,
					easing: tween.cubicInOut
				});
			}
		}
	}
	if (firstCard && secondCard && firstCard.symbol === secondCard.symbol) {
		// Match!
		LK.getSound('cardmatch').play();
		firstCard.setMatched();
		secondCard.setMatched();
		matchesFound++;
		// Subtle scale animation for matched cards, then disappear
		if (firstCard && secondCard) {
			var matched1 = firstCard;
			var matched2 = secondCard;
			if (matched1) {
				tween(matched1, {
					scaleX: 1.15,
					scaleY: 1.15
				}, {
					duration: 80,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (matched1) {
							tween(matched1, {
								scaleX: 0,
								scaleY: 0,
								alpha: 0
							}, {
								duration: 120,
								onFinish: function onFinish() {
									if (matched1) {
										matched1.destroy();
									}
								}
							});
						}
					}
				});
			}
			if (matched2) {
				tween(matched2, {
					scaleX: 1.15,
					scaleY: 1.15
				}, {
					duration: 80,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (matched2) {
							tween(matched2, {
								scaleX: 0,
								scaleY: 0,
								alpha: 0
							}, {
								duration: 120,
								onFinish: function onFinish() {
									if (matched2) {
										matched2.destroy();
									}
								}
							});
						}
					}
				});
			}
		}
		// Check for win
		if (matchesFound === totalPairs) {
			LK.clearInterval(timer);
			LK.setScore(moves); // Use moves as score (lower is better)
			if (currentLevel < maxLevel) {
				// Play level completed sound
				LK.getSound('levelcompleted').play();
				// Show "Level Completed" text in the center of the screen
				var levelCompletedText = new Text2('Level Completed!', {
					size: 180,
					fill: 0xFFD700,
					font: "Impact"
				});
				levelCompletedText.anchor.set(0.5, 0.5);
				levelCompletedText.x = 2048 / 2;
				levelCompletedText.y = 2732 / 2;
				game.addChild(levelCompletedText);
				if (currentLevel === 1) {
					currentLevel = 6;
				} else if (currentLevel === 6) {
					currentLevel = 11;
				} else if (currentLevel === 11) {
					currentLevel = 16;
				} else if (currentLevel === 16) {
					currentLevel = 21;
				} else if (currentLevel === 21) {
					currentLevel = 26;
				} else if (currentLevel === 26) {
					currentLevel = 31;
				} else if (currentLevel === 31) {
					currentLevel = 36;
				} else if (currentLevel === 36) {
					currentLevel = 41;
				} else if (currentLevel === 41) {
					currentLevel = 46;
				} else if (currentLevel === 46) {
					currentLevel = 50;
				} else {
					currentLevel++;
				}
				// Short delay before next level, remove text before reset
				LK.setTimeout(function () {
					if (levelCompletedText && typeof levelCompletedText.destroy === "function") {
						levelCompletedText.destroy();
					}
					resetGame();
				}, 1200);
			} else {
				LK.showYouWin();
			}
		}
		// Reset selection
		firstCard = null;
		secondCard = null;
		lockInput = false;
	} else {
		// Not a match: flip both back after short delay
		LK.setTimeout(function () {
			if (firstCard && typeof firstCard.flipDown === "function") {
				firstCard.flipDown();
			}
			if (secondCard && typeof secondCard.flipDown === "function") {
				secondCard.flipDown(function () {
					firstCard = null;
					secondCard = null;
					lockInput = false;
				});
			} else {
				// If secondCard is missing, still reset state after delay
				firstCard = null;
				secondCard = null;
				lockInput = false;
			}
		}, 250);
	}
}
// --- Game update (not used for logic, but required) ---
game.update = function () {
	// Movement-based card swap: if two cards are dragged/moved to each other's position, swap their symbol and index
	// (Assuming you have a drag/move system, e.g. for future features or mobile drag-to-swap)
	// This is a defensive implementation: checks for cards that overlap and are not already matched or face up
	for (var i = 0; i < cards.length; i++) {
		var cardA = cards[i];
		if (cardA.isMatched || cardA.isFaceUp) continue;
		for (var j = i + 1; j < cards.length; j++) {
			var cardB = cards[j];
			if (cardB.isMatched || cardB.isFaceUp) continue;
			// If cardA and cardB overlap (bounding box collision)
			if (Math.abs(cardA.x - cardB.x) < (cardA.cardWidth + cardB.cardWidth) / 2 && Math.abs(cardA.y - cardB.y) < (cardA.cardHeight + cardB.cardHeight) / 2) {
				// Only swap if not already swapped this frame
				if (!cardA._swappedThisFrame && !cardB._swappedThisFrame) {
					// Swap symbol and index
					var tempSymbol = cardA.symbol;
					var tempIndex = cardA.index;
					cardA.setSymbol(cardB.symbol);
					cardB.setSymbol(tempSymbol);
					cardA.index = cardB.index;
					cardB.index = tempIndex;
					cardA._swappedThisFrame = true;
					cardB._swappedThisFrame = true;
				}
			}
		}
	}
	// Reset swap flags for next frame
	for (var i = 0; i < cards.length; i++) {
		cards[i]._swappedThisFrame = false;
	}
};
// --- DEV Button: Center bottom, always visible, go to next level ---
// (Hidden for production, but function remains for later update test)
var devBtn = new Text2('DEV', {
	size: 90,
	fill: 0xFF00FF,
	font: "Impact"
});
devBtn.anchor.set(0.5, 1);
// Place DEV button slightly left of center
devBtn.x = -120;
devBtn.y = -50;
// LK.gui.bottom.addChild(devBtn); // HIDDEN: do not add to GUI, but keep logic for later test
devBtn.visible = false; // Hide from view
// DEV button handler: go to next level immediately (max 25)
devBtn.down = function (x, y, obj) {
	if (matchesFound === totalPairs) {
		// Already won, do nothing
		return;
	}
	// Replicate the level pass logic from checkMatch()
	if (currentLevel < maxLevel) {
		// Play level completed sound
		LK.getSound('levelcompleted').play();
		// Show "Level Completed" text in the center of the screen
		var levelCompletedText = new Text2('Level Completed!', {
			size: 180,
			fill: 0xFFD700,
			font: "Impact"
		});
		levelCompletedText.anchor.set(0.5, 0.5);
		levelCompletedText.x = 2048 / 2;
		levelCompletedText.y = 2732 / 2;
		game.addChild(levelCompletedText);
		if (currentLevel === 1) {
			currentLevel = 6;
		} else if (currentLevel === 6) {
			currentLevel = 11;
		} else if (currentLevel === 11) {
			currentLevel = 16;
		} else if (currentLevel === 16) {
			currentLevel = 21;
		} else if (currentLevel === 21) {
			currentLevel = 26;
		} else if (currentLevel === 26) {
			levelText.setText('Level: 6');
			currentLevel = 31;
		} else if (currentLevel === 31) {
			levelText.setText('Level: 7');
			currentLevel = 36;
		} else if (currentLevel === 36) {
			levelText.setText('Level: 8');
			levelText.setText('Level: 8');
			currentLevel = 41;
		} else if (currentLevel === 41) {
			levelText.setText('Level: 9');
			currentLevel = 46;
		} else if (currentLevel === 46) {
			levelText.setText('Level: 10');
			currentLevel = 50;
		} else if (currentLevel === 50) {
			levelText.setText('Final Level');
			currentLevel = 50;
		} else {
			currentLevel++;
		}
		LK.setTimeout(function () {
			if (levelCompletedText && typeof levelCompletedText.destroy === "function") {
				levelCompletedText.destroy();
			}
			resetGame();
		}, 1200);
	} else {
		LK.showYouWin();
	}
};
// --- Reveal Button: Center bottom, always visible, reveals all cards ---
// (Hidden for production, but function remains for later update test)
var revealBtn = new Text2('Reveal', {
	size: 90,
	fill: 0x00CCFF,
	font: "Impact"
});
revealBtn.anchor.set(0.5, 1);
// Place Reveal button slightly right of center
revealBtn.x = 120;
revealBtn.y = -50;
// LK.gui.bottom.addChild(revealBtn); // HIDDEN: do not add to GUI, but keep logic for later test
revealBtn.visible = false; // Hide from view
// Reveal button handler: toggle all cards between revealed and hidden
var revealState = false; // false = hidden, true = revealed
revealBtn.down = function (x, y, obj) {
	revealState = !revealState;
	if (revealState) {
		// Reveal all cards (that are not matched)
		for (var i = 0; i < cards.length; i++) {
			var card = cards[i];
			if (!card.isFaceUp && !card.isMatched) {
				card.flipUp();
			}
		}
		revealBtn.setText('Hide');
	} else {
		// Hide all cards (that are not matched)
		for (var i = 0; i < cards.length; i++) {
			var card = cards[i];
			if (card.isFaceUp && !card.isMatched) {
				card.flipDown();
			}
		}
		revealBtn.setText('Reveal');
	}
};
// --- Start game ---
LK.playMusic('gamemusic');
resetGame();
// --- Game over handler (reset on game over) ---
game.onGameOver = function () {
	if (timer) {
		LK.clearInterval(timer);
	}
	if (typeof randomSwapTimer !== "undefined" && randomSwapTimer) {
		LK.clearInterval(randomSwapTimer);
		randomSwapTimer = null;
	}
	if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
		LK.clearInterval(randomSwapTimer10s);
		randomSwapTimer10s = null;
	}
	if (typeof randomSwapTimer5s !== "undefined" && randomSwapTimer5s) {
		LK.clearInterval(randomSwapTimer5s);
		randomSwapTimer5s = null;
	}
	if (typeof randomSwapTimer2s !== "undefined" && randomSwapTimer2s) {
		LK.clearInterval(randomSwapTimer2s);
		randomSwapTimer2s = null;
	}
	currentLevel = 1;
	LK.stopMusic();
	resetGame();
};
// --- Win handler (reset on win) ---
game.onYouWin = function () {
	if (timer) {
		LK.clearInterval(timer);
	}
	if (typeof randomSwapTimer !== "undefined" && randomSwapTimer) {
		LK.clearInterval(randomSwapTimer);
		randomSwapTimer = null;
	}
	if (typeof randomSwapTimer10s !== "undefined" && randomSwapTimer10s) {
		LK.clearInterval(randomSwapTimer10s);
		randomSwapTimer10s = null;
	}
	if (typeof randomSwapTimer5s !== "undefined" && randomSwapTimer5s) {
		LK.clearInterval(randomSwapTimer5s);
		randomSwapTimer5s = null;
	}
	if (typeof randomSwapTimer2s !== "undefined" && randomSwapTimer2s) {
		LK.clearInterval(randomSwapTimer2s);
		randomSwapTimer2s = null;
	}
	currentLevel = 1;
	LK.stopMusic();
	// Game will reset automatically by LK
};