/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// --- ChessBoard Class ---
var ChessBoard = Container.expand(function () {
	var self = Container.call(this);
	// 8x8 array of ChessPiece or null
	self.squares = [];
	for (var y = 0; y < 8; y++) {
		self.squares[y] = [];
		for (var x = 0; x < 8; x++) {
			self.squares[y][x] = null;
		}
	}
	// Draw board squares
	self.squareNodes = [];
	for (var y = 0; y < 8; y++) {
		self.squareNodes[y] = [];
		for (var x = 0; x < 8; x++) {
			var isLight = (x + y) % 2 === 0;
			// Use classic chessboard colors: light = #f0d9b5, dark = #b58863
			var color = isLight ? 0xf0d9b5 : 0xb58863;
			var assetId = 'board_' + (isLight ? 'light' : 'dark');
			var node = LK.getAsset(assetId, {
				anchorX: 0,
				anchorY: 0,
				x: boardOriginX + x * squareSize,
				y: boardOriginY + y * squareSize,
				width: squareSize,
				height: squareSize,
				color: color,
				shape: 'box'
			});
			self.addChild(node);
			self.squareNodes[y][x] = node;
		}
	}
	// Highlight squares (for moves)
	self.highlightNodes = [];
	for (var i = 0; i < 64; i++) {
		var highlightId = 'highlight_' + i;
		// Use a circle (ellipse) and center it in the square
		var node = LK.getAsset('centerCircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: Math.floor(squareSize * 0.45),
			height: Math.floor(squareSize * 0.45),
			x: -1000,
			y: -1000
		}); // Hide initially
		node.alpha = 0.25;
		self.addChild(node);
		self.highlightNodes[i] = node;
	}
	// Place pieces in starting position
	self.reset = function () {
		// Remove all pieces
		for (var y = 0; y < 8; y++) {
			for (var x = 0; x < 8; x++) {
				if (self.squares[y][x]) {
					self.squares[y][x].destroy();
					self.squares[y][x] = null;
				}
			}
		}
		// Place pawns
		for (var x = 0; x < 8; x++) {
			var wp = new ChessPiece();
			wp.init('pawn', 'white', x, 6);
			wp.moveTo(x, 6, false);
			self.addChild(wp);
			self.squares[6][x] = wp;
			var bp = new ChessPiece();
			bp.init('pawn', 'black', x, 1);
			bp.moveTo(x, 1, false);
			self.addChild(bp);
			self.squares[1][x] = bp;
		}
		// Place other pieces
		var order = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'];
		for (var x = 0; x < 8; x++) {
			var w = new ChessPiece();
			w.init(order[x], 'white', x, 7);
			w.moveTo(x, 7, false);
			self.addChild(w);
			self.squares[7][x] = w;
			var b = new ChessPiece();
			b.init(order[x], 'black', x, 0);
			b.moveTo(x, 0, false);
			self.addChild(b);
			self.squares[0][x] = b;
		}
	};
	// Remove all highlights
	self.clearHighlights = function () {
		for (var i = 0; i < 64; i++) {
			self.highlightNodes[i].x = -1000;
			self.highlightNodes[i].y = -1000;
		}
	};
	// Highlight given squares (array of {x, y})
	self.showHighlights = function (squares) {
		self.clearHighlights();
		for (var i = 0; i < squares.length; i++) {
			var idx = squares[i].y * 8 + squares[i].x;
			var node = self.highlightNodes[idx];
			// Center the highlight circle in the square
			node.x = boardOriginX + squares[i].x * squareSize + squareSize / 2;
			node.y = boardOriginY + squares[i].y * squareSize + squareSize / 2;
		}
	};
	// Get piece at board position
	self.getPiece = function (x, y) {
		if (x < 0 || x > 7 || y < 0 || y > 7) return null;
		return self.squares[y][x];
	};
	// Set piece at board position
	self.setPiece = function (x, y, piece) {
		self.squares[y][x] = piece;
	};
	// Remove piece at board position
	self.removePiece = function (x, y) {
		var p = self.squares[y][x];
		if (p) {
			p.destroy();
			self.squares[y][x] = null;
		}
	};
	return self;
});
// --- ChessPiece Class ---
var ChessPiece = Container.expand(function () {
	var self = Container.call(this);
	// Properties
	self.type = null; // 'pawn', 'rook', 'knight', 'bishop', 'queen', 'king'
	self.color = null; // 'white' or 'black'
	self.boardX = 0; // 0-7
	self.boardY = 0; // 0-7
	self.hasMoved = false; // For castling/en passant
	self.promoted = false; // For pawn promotion
	// Asset
	self.pieceAsset = null;
	// Set piece type and color, and create asset
	self.init = function (type, color, boardX, boardY) {
		self.type = type;
		self.color = color;
		self.boardX = boardX;
		self.boardY = boardY;
		self.hasMoved = false;
		self.promoted = false;
		// Remove old asset if any
		if (self.pieceAsset) {
			self.removeChild(self.pieceAsset);
		}
		// Use classic piece colors: white = #fff, black = #222
		var colorMap = {
			'white': {
				'pawn': 0xffffff,
				'rook': 0xffffff,
				'knight': 0xffffff,
				'bishop': 0xffffff,
				'queen': 0xffffff,
				'king': 0xffffff
			},
			'black': {
				'pawn': 0x222222,
				'rook': 0x222222,
				'knight': 0x222222,
				'bishop': 0x222222,
				'queen': 0x222222,
				'king': 0x222222
			}
		};
		var shape = self.type === 'pawn' || self.type === 'bishop' ? 'ellipse' : 'box';
		var assetId = self.color + '_' + self.type;
		var assetColor = colorMap[self.color][self.type];
		var size = self.type === 'king' ? Math.floor(pieceSize * 1.25) : pieceSize;
		self.pieceAsset = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5,
			width: size,
			height: size,
			color: assetColor,
			shape: shape
		});
		// Add a crown for promoted pawns
		if (self.promoted && self.type === 'queen') {
			// Overlay a small yellow ellipse as a "crown"
			var crown = LK.getAsset('crown_' + self.color, {
				anchorX: 0.5,
				anchorY: 0.5,
				y: -size * 0.3
			});
			self.addChild(crown);
		}
	};
	// Move piece to board position (with optional animation)
	self.moveTo = function (bx, by, animate) {
		self.boardX = bx;
		self.boardY = by;
		var targetX = boardOriginX + bx * squareSize + squareSize / 2;
		var targetY = boardOriginY + by * squareSize + squareSize / 2;
		if (animate) {
			tween(self, {
				x: targetX,
				y: targetY
			}, {
				duration: 180,
				easing: tween.cubicOut
			});
		} else {
			self.x = targetX;
			self.y = targetY;
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x222222
});
/**** 
* Game Code
****/ 
// Crown for promoted pawn (queen)
// Black pieces
// White pieces
// Board squares
// We need tween for piece movement animations
// --- Board and Piece Sizes ---
var boardSize = Math.min(2048, 2048); // Square board, fit width
var squareSize = Math.floor(boardSize / 8);
var pieceSize = Math.floor(squareSize * 0.8);
var boardOriginX = Math.floor((2048 - squareSize * 8) / 2);
var boardOriginY = Math.floor((2732 - squareSize * 8) / 2);
// --- Game State ---
var board = new ChessBoard();
game.addChild(board);
board.reset();
var currentTurn = 'white'; // 'white' or 'black'
var selectedPiece = null;
var legalMoves = []; // Array of {x, y, special}
var lastMove = null; // {from: {x,y}, to: {x,y}, piece, captured, special}
var enPassantTarget = null; // {x, y} or null
var halfmoveClock = 0; // For 50-move rule
var fullmoveNumber = 1;
var gameEnded = false;
// --- GUI: Turn Display ---
var turnText = new Text2('White to move', {
	size: 90,
	fill: "#fff"
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
// --- GUI: Timers ---
// Each player starts with 10 minutes (600 seconds)
var whiteTime = 600;
var blackTime = 600;
var whiteTimerText = new Text2('10:00', {
	size: 90,
	fill: "#fff"
});
// Place white timer near bottom left, above white's side, but not in the bottom left 100x100 reserved area
whiteTimerText.anchor.set(0, 1); // left aligned, bottom
whiteTimerText.x = 320; // moved even further right
whiteTimerText.y = LK.gui.height - 40;
LK.gui.bottomLeft.addChild(whiteTimerText);
var blackTimerText = new Text2('10:00', {
	size: 90,
	fill: "#fff"
});
// Place black timer near top right, above black's side, but not in the top right 100x100 reserved area
blackTimerText.anchor.set(1, 0); // right aligned, top
blackTimerText.x = LK.gui.width - 40; // moved even further right (inward)
blackTimerText.y = 0;
LK.gui.topRight.addChild(blackTimerText);
// Timer state
var whiteTimerInterval = null;
var blackTimerInterval = null;
// Helper to format seconds as MM:SS
function formatTime(secs) {
	var m = Math.floor(secs / 60);
	var s = Math.floor(secs % 60);
	return (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s;
}
// Start/stop timer helpers
function startWhiteTimer() {
	if (whiteTimerInterval) LK.clearInterval(whiteTimerInterval);
	whiteTimerInterval = LK.setInterval(function () {
		if (gameEnded) return;
		whiteTime--;
		if (whiteTime < 0) whiteTime = 0;
		whiteTimerText.setText(formatTime(whiteTime));
		if (whiteTime === 0) {
			gameEnded = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showYouWin('Black wins on time!');
			stopAllTimers();
		}
	}, 1000);
}
function startBlackTimer() {
	if (blackTimerInterval) LK.clearInterval(blackTimerInterval);
	blackTimerInterval = LK.setInterval(function () {
		if (gameEnded) return;
		blackTime--;
		if (blackTime < 0) blackTime = 0;
		blackTimerText.setText(formatTime(blackTime));
		if (blackTime === 0) {
			gameEnded = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showYouWin('White wins on time!');
			stopAllTimers();
		}
	}, 1000);
}
function stopWhiteTimer() {
	if (whiteTimerInterval) {
		LK.clearInterval(whiteTimerInterval);
		whiteTimerInterval = null;
	}
}
function stopBlackTimer() {
	if (blackTimerInterval) {
		LK.clearInterval(blackTimerInterval);
		blackTimerInterval = null;
	}
}
function stopAllTimers() {
	stopWhiteTimer();
	stopBlackTimer();
}
// Start white's timer at game start
startWhiteTimer();
whiteTimerText.setText(formatTime(whiteTime));
blackTimerText.setText(formatTime(blackTime));
// --- GUI: Promotion Popup ---
var promotionPopup = null;
// --- Helper Functions ---
// Convert screen (x, y) to board (bx, by)
function screenToBoard(x, y) {
	var bx = Math.floor((x - boardOriginX) / squareSize);
	var by = Math.floor((y - boardOriginY) / squareSize);
	if (bx < 0 || bx > 7 || by < 0 || by > 7) return null;
	return {
		x: bx,
		y: by
	};
}
// Convert board (bx, by) to screen (x, y) (center of square)
function boardToScreen(bx, by) {
	return {
		x: boardOriginX + bx * squareSize + squareSize / 2,
		y: boardOriginY + by * squareSize + squareSize / 2
	};
}
// Is (x, y) on the board?
function isOnBoard(x, y) {
	return x >= 0 && x < 8 && y >= 0 && y < 8;
}
// Get all legal moves for a piece at (x, y)
function getLegalMoves(piece, x, y, ignoreCheck) {
	var moves = [];
	if (!piece) return moves;
	var color = piece.color;
	var opp = color === 'white' ? 'black' : 'white';
	// Directions for sliding pieces
	var dirs = {
		'rook': [[1, 0], [-1, 0], [0, 1], [0, -1]],
		'bishop': [[1, 1], [1, -1], [-1, 1], [-1, -1]],
		'queen': [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
	};
	// Pawn moves
	if (piece.type === 'pawn') {
		var dir = color === 'white' ? -1 : 1;
		// Forward
		if (isOnBoard(x, y + dir) && !board.getPiece(x, y + dir)) {
			moves.push({
				x: x,
				y: y + dir
			});
			// Double move from start
			if (!piece.hasMoved && isOnBoard(x, y + 2 * dir) && !board.getPiece(x, y + 2 * dir)) {
				moves.push({
					x: x,
					y: y + 2 * dir,
					special: 'double'
				});
			}
		}
		// Captures
		for (var dx = -1; dx <= 1; dx += 2) {
			var tx = x + dx,
				ty = y + dir;
			if (isOnBoard(tx, ty)) {
				var target = board.getPiece(tx, ty);
				if (target && target.color === opp) {
					moves.push({
						x: tx,
						y: ty
					});
				}
			}
		}
		// En passant
		if (enPassantTarget) {
			if (Math.abs(enPassantTarget.x - x) === 1 && enPassantTarget.y === y + dir) {
				moves.push({
					x: enPassantTarget.x,
					y: enPassantTarget.y,
					special: 'enpassant'
				});
			}
		}
	}
	// Knight moves
	else if (piece.type === 'knight') {
		var knightDeltas = [[1, 2], [2, 1], [-1, 2], [-2, 1], [1, -2], [2, -1], [-1, -2], [-2, -1]];
		for (var i = 0; i < knightDeltas.length; i++) {
			var dx = knightDeltas[i][0],
				dy = knightDeltas[i][1];
			var tx = x + dx,
				ty = y + dy;
			if (isOnBoard(tx, ty)) {
				var target = board.getPiece(tx, ty);
				if (!target || target.color === opp) {
					moves.push({
						x: tx,
						y: ty
					});
				}
			}
		}
	}
	// King moves (including castling)
	else if (piece.type === 'king') {
		// Prevent infinite recursion: when ignoreCheck is true, do NOT generate king moves
		if (ignoreCheck) {
			// Do not generate king moves when ignoreCheck is true (used for attack detection)
			// This prevents infinite recursion between isInCheck and getLegalMoves
		} else {
			// Find the other king's position
			var otherKingPos = null;
			for (var yy = 0; yy < 8; yy++) {
				for (var xx = 0; xx < 8; xx++) {
					var p = board.getPiece(xx, yy);
					if (p && p.type === 'king' && p.color !== color) {
						otherKingPos = {
							x: xx,
							y: yy
						};
						break;
					}
				}
				if (otherKingPos) break;
			}
			for (var dx = -1; dx <= 1; dx++) {
				for (var dy = -1; dy <= 1; dy++) {
					if (dx === 0 && dy === 0) continue;
					var tx = x + dx,
						ty = y + dy;
					if (isOnBoard(tx, ty)) {
						// Prevent moving to any square adjacent (1 square away) to the other king
						var allow = true;
						if (otherKingPos) {
							// If the target square is adjacent (including diagonals) to the other king, disallow
							if (Math.abs(tx - otherKingPos.x) <= 1 && Math.abs(ty - otherKingPos.y) <= 1) allow = false;
							if (tx === otherKingPos.x && ty === otherKingPos.y) allow = false;
						}
						var target = board.getPiece(tx, ty);
						if ((!target || target.color === opp) && allow) {
							moves.push({
								x: tx,
								y: ty
							});
						}
					}
				}
			}
			// Castling
			if (!piece.hasMoved && !isInCheck(color)) {
				// Kingside
				if (canCastle(color, 'kingside')) {
					// Check that castling does not violate the king distance rule
					var castleTx = x + 2;
					var castleTy = y;
					var allowCastle = true;
					if (otherKingPos) {
						if (Math.abs(castleTx - otherKingPos.x) <= 3 && castleTy === otherKingPos.y) allowCastle = false;
						if (Math.abs(castleTy - otherKingPos.y) <= 3 && castleTx === otherKingPos.x) allowCastle = false;
						if (castleTx === otherKingPos.x && castleTy === otherKingPos.y) allowCastle = false;
					}
					if (allowCastle) {
						moves.push({
							x: castleTx,
							y: castleTy,
							special: 'castle_kingside'
						});
					}
				}
				// Queenside
				if (canCastle(color, 'queenside')) {
					var castleTx = x - 2;
					var castleTy = y;
					var allowCastle = true;
					if (otherKingPos) {
						if (Math.abs(castleTx - otherKingPos.x) <= 3 && castleTy === otherKingPos.y) allowCastle = false;
						if (Math.abs(castleTy - otherKingPos.y) <= 3 && castleTx === otherKingPos.x) allowCastle = false;
						if (castleTx === otherKingPos.x && castleTy === otherKingPos.y) allowCastle = false;
					}
					if (allowCastle) {
						moves.push({
							x: castleTx,
							y: castleTy,
							special: 'castle_queenside'
						});
					}
				}
			}
		}
	}
	// Sliding pieces
	else if (piece.type === 'rook' || piece.type === 'bishop' || piece.type === 'queen') {
		var directions = dirs[piece.type];
		for (var d = 0; d < directions.length; d++) {
			var dx = directions[d][0],
				dy = directions[d][1];
			var tx = x + dx,
				ty = y + dy;
			while (isOnBoard(tx, ty)) {
				var target = board.getPiece(tx, ty);
				if (!target) {
					moves.push({
						x: tx,
						y: ty
					});
				} else {
					if (target.color === opp) {
						moves.push({
							x: tx,
							y: ty
						});
					}
					break;
				}
				tx += dx;
				ty += dy;
			}
		}
	}
	// Remove moves that leave king in check (unless ignoreCheck)
	if (!ignoreCheck) {
		var filtered = [];
		for (var i = 0; i < moves.length; i++) {
			var m = moves[i];
			if (!wouldLeaveKingInCheck(piece, x, y, m.x, m.y, m.special)) {
				filtered.push(m);
			}
		}
		return filtered;
	}
	return moves;
}
// Would moving piece at (x, y) to (tx, ty) leave own king in check?
function wouldLeaveKingInCheck(piece, x, y, tx, ty, special) {
	// Simulate move
	var origPiece = board.getPiece(tx, ty);
	var origEnPassant = enPassantTarget;
	var origHasMoved = piece.hasMoved;
	var origFrom = board.squares[y][x];
	var origTo = board.squares[ty][tx];
	// Remove captured piece
	if (special === 'enpassant') {
		var dir = piece.color === 'white' ? -1 : 1;
		var capY = ty - dir;
		var capPiece = board.getPiece(tx, capY);
		board.squares[capY][tx] = null;
	}
	board.squares[y][x] = null;
	board.squares[ty][tx] = piece;
	// For castling, move rook as well
	var rookMoved = null,
		rookFrom = null,
		rookTo = null;
	if (special === 'castle_kingside') {
		var row = piece.color === 'white' ? 7 : 0;
		rookFrom = board.getPiece(7, row);
		rookTo = board.getPiece(5, row);
		board.squares[row][7] = null;
		board.squares[row][5] = rookFrom;
	}
	if (special === 'castle_queenside') {
		var row = piece.color === 'white' ? 7 : 0;
		rookFrom = board.getPiece(0, row);
		rookTo = board.getPiece(3, row);
		board.squares[row][0] = null;
		board.squares[row][3] = rookFrom;
	}
	var inCheck = isInCheck(piece.color);
	// Undo move
	board.squares[y][x] = origFrom;
	board.squares[ty][tx] = origTo;
	if (special === 'enpassant') {
		var dir = piece.color === 'white' ? -1 : 1;
		var capY = ty - dir;
		board.squares[capY][tx] = origPiece;
	}
	if (special === 'castle_kingside') {
		var row = piece.color === 'white' ? 7 : 0;
		board.squares[row][7] = rookFrom;
		board.squares[row][5] = null;
	}
	if (special === 'castle_queenside') {
		var row = piece.color === 'white' ? 7 : 0;
		board.squares[row][0] = rookFrom;
		board.squares[row][3] = null;
	}
	piece.hasMoved = origHasMoved;
	enPassantTarget = origEnPassant;
	return inCheck;
}
// Is color's king in check?
function isInCheck(color) {
	var kingPos = findKing(color);
	if (!kingPos) return false;
	var opp = color === 'white' ? 'black' : 'white';
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.color === opp) {
				var moves = getLegalMoves(p, x, y, true);
				for (var i = 0; i < moves.length; i++) {
					if (moves[i].x === kingPos.x && moves[i].y === kingPos.y) {
						return true;
					}
				}
			}
		}
	}
	return false;
}
// Find king of color
function findKing(color) {
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.type === 'king' && p.color === color) {
				return {
					x: x,
					y: y
				};
			}
		}
	}
	return null;
}
// Can color castle on side ('kingside' or 'queenside')?
function canCastle(color, side) {
	var row = color === 'white' ? 7 : 0;
	var king = board.getPiece(4, row);
	if (!king || king.hasMoved) return false;
	if (side === 'kingside') {
		var rook = board.getPiece(7, row);
		if (!rook || rook.type !== 'rook' || rook.hasMoved) return false;
		// Squares between must be empty
		if (board.getPiece(5, row) || board.getPiece(6, row)) return false;
		// Squares king passes through must not be attacked
		if (isAttacked(5, row, color) || isAttacked(6, row, color)) return false;
		return true;
	}
	if (side === 'queenside') {
		var rook = board.getPiece(0, row);
		if (!rook || rook.type !== 'rook' || rook.hasMoved) return false;
		if (board.getPiece(1, row) || board.getPiece(2, row) || board.getPiece(3, row)) return false;
		if (isAttacked(2, row, color) || isAttacked(3, row, color)) return false;
		return true;
	}
	return false;
}
// Is square (x, y) attacked by opponent of color?
function isAttacked(x, y, color) {
	var opp = color === 'white' ? 'black' : 'white';
	for (var yy = 0; yy < 8; yy++) {
		for (var xx = 0; xx < 8; xx++) {
			var p = board.getPiece(xx, yy);
			if (p && p.color === opp) {
				var moves = getLegalMoves(p, xx, yy, true);
				for (var i = 0; i < moves.length; i++) {
					if (moves[i].x === x && moves[i].y === y) {
						return true;
					}
				}
			}
		}
	}
	return false;
}
// Get all legal moves for color
function getAllLegalMoves(color) {
	var moves = [];
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.color === color) {
				var pieceMoves = getLegalMoves(p, x, y, false);
				for (var i = 0; i < pieceMoves.length; i++) {
					moves.push({
						from: {
							x: x,
							y: y
						},
						to: {
							x: pieceMoves[i].x,
							y: pieceMoves[i].y
						},
						special: pieceMoves[i].special
					});
				}
			}
		}
	}
	return moves;
}
// Is the game over? Returns {over: true/false, result: 'checkmate'/'stalemate'/'draw', winner: 'white'/'black'/null}
function checkGameEnd() {
	var moves = getAllLegalMoves(currentTurn);
	if (moves.length === 0) {
		if (isInCheck(currentTurn)) {
			return {
				over: true,
				result: 'checkmate',
				winner: currentTurn === 'white' ? 'black' : 'white'
			};
		} else {
			return {
				over: true,
				result: 'stalemate',
				winner: null
			};
		}
	}
	// 50-move rule
	if (halfmoveClock >= 100) {
		return {
			over: true,
			result: 'draw',
			winner: null
		};
	}
	// Insufficient material (only kings)
	var onlyKings = true;
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.type !== 'king') onlyKings = false;
		}
	}
	if (onlyKings) {
		return {
			over: true,
			result: 'draw',
			winner: null
		};
	}
	return {
		over: false
	};
}
// --- Promotion Popup ---
function showPromotionPopup(piece, toX, toY, onSelect) {
	if (promotionPopup) {
		promotionPopup.destroy();
		promotionPopup = null;
	}
	promotionPopup = new Container();
	var popupW = squareSize * 4;
	var popupH = squareSize * 1.2;
	var popupX = boardOriginX + (toX - 1) * squareSize;
	var popupY = boardOriginY + toY * squareSize - popupH / 2;
	var bg = LK.getAsset('promotion_bg', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0
	});
	bg.alpha = 0.95;
	promotionPopup.addChild(bg);
	var types = ['queen', 'rook', 'bishop', 'knight'];
	for (var i = 0; i < types.length; i++) {
		var t = types[i];
		var tempPiece = new ChessPiece();
		tempPiece.init(t, piece.color, 0, 0);
		tempPiece.x = squareSize * (i + 0.5);
		tempPiece.y = popupH / 2;
		tempPiece.pieceAsset.width = pieceSize * 0.9;
		tempPiece.pieceAsset.height = pieceSize * 0.9;
		(function (type) {
			tempPiece.down = function (x, y, obj) {
				if (promotionPopup) {
					onSelect(type);
					promotionPopup.destroy();
					promotionPopup = null;
				}
			};
		})(t);
		promotionPopup.addChild(tempPiece);
	}
	promotionPopup.x = popupX;
	promotionPopup.y = popupY;
	game.addChild(promotionPopup);
}
// --- Tap-to-select and tap-to-move ---
// No dragging variables needed
// --- Event Handlers ---
// Handle touch/mouse down (tap)
game.down = function (x, y, obj) {
	if (gameEnded) return;
	if (promotionPopup) return; // Block input during promotion
	var pos = screenToBoard(x, y);
	if (!pos) return;
	var p = board.getPiece(pos.x, pos.y);
	// If a piece is already selected and the tap is on a legal move, move there
	if (selectedPiece && legalMoves.length > 0) {
		for (var i = 0; i < legalMoves.length; i++) {
			var m = legalMoves[i];
			if (m.x === pos.x && m.y === pos.y) {
				// Move piece
				doMove(selectedPiece, selectedPiece.boardX, selectedPiece.boardY, m.x, m.y, m.special);
				board.clearHighlights();
				selectedPiece = null;
				legalMoves = [];
				return;
			}
		}
	}
	// If tap is on a piece of current turn, select it and show moves
	if (p && p.color === currentTurn) {
		selectedPiece = p;
		legalMoves = getLegalMoves(p, pos.x, pos.y, false);
		board.showHighlights(legalMoves);
		return;
	}
	// If tap is on empty square or not a legal move, clear selection
	board.clearHighlights();
	selectedPiece = null;
	legalMoves = [];
};
// No dragging, so move and up handlers are not needed
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// --- Move Execution ---
function doMove(piece, fromX, fromY, toX, toY, special) {
	var opp = piece.color === 'white' ? 'black' : 'white';
	var captured = null;
	var isPawnMove = piece.type === 'pawn';
	var isCapture = false;
	// Handle en passant
	if (special === 'enpassant') {
		var dir = piece.color === 'white' ? -1 : 1;
		var capY = toY - dir;
		captured = board.getPiece(toX, capY);
		board.removePiece(toX, capY);
		isCapture = true;
	}
	// Handle castling
	if (special === 'castle_kingside') {
		var row = piece.color === 'white' ? 7 : 0;
		var rook = board.getPiece(7, row);
		board.setPiece(5, row, rook);
		board.setPiece(7, row, null);
		rook.moveTo(5, row, true);
		rook.hasMoved = true;
	}
	if (special === 'castle_queenside') {
		var row = piece.color === 'white' ? 7 : 0;
		var rook = board.getPiece(0, row);
		board.setPiece(3, row, rook);
		board.setPiece(0, row, null);
		rook.moveTo(3, row, true);
		rook.hasMoved = true;
	}
	// Remove captured piece
	var target = board.getPiece(toX, toY);
	if (target && target.color !== piece.color) {
		captured = target;
		board.removePiece(toX, toY);
		isCapture = true;
	}
	// Move piece
	board.setPiece(fromX, fromY, null);
	board.setPiece(toX, toY, piece);
	piece.moveTo(toX, toY, true);
	piece.hasMoved = true;
	// Play move sound
	LK.getSound('tas').play();
	// Pawn promotion
	if (piece.type === 'pawn' && (toY === 0 || toY === 7)) {
		showPromotionPopup(piece, toX, toY, function (newType) {
			piece.type = newType;
			piece.promoted = newType === 'queen';
			piece.init(newType, piece.color, toX, toY);
			endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture);
		});
		return;
	}
	endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture);
}
function endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture) {
	// Update en passant
	if (piece.type === 'pawn' && Math.abs(toY - fromY) === 2) {
		enPassantTarget = {
			x: toX,
			y: (fromY + toY) / 2
		};
	} else {
		enPassantTarget = null;
	}
	// Update halfmove clock
	if (isPawnMove || isCapture) {
		halfmoveClock = 0;
	} else {
		halfmoveClock++;
	}
	// Update fullmove number
	if (currentTurn === 'black') {
		fullmoveNumber++;
	}
	// Save last move
	lastMove = {
		from: {
			x: fromX,
			y: fromY
		},
		to: {
			x: toX,
			y: toY
		},
		piece: piece,
		captured: captured,
		special: special
	};
	// Switch turn
	if (currentTurn === 'white') {
		stopWhiteTimer();
		startBlackTimer();
		currentTurn = 'black';
	} else {
		stopBlackTimer();
		startWhiteTimer();
		currentTurn = 'white';
	}
	turnText.setText((currentTurn === 'white' ? 'White' : 'Black') + ' to move');
	// Check for game end
	var end = checkGameEnd();
	if (end.over) {
		gameEnded = true;
		stopAllTimers();
		if (end.result === 'checkmate') {
			LK.effects.flashScreen(0x00ff00, 800);
			if (end.winner === 'white') {
				LK.showYouWin('White wins by checkmate!');
			} else if (end.winner === 'black') {
				LK.showYouWin('Black wins by checkmate!');
			}
		} else if (end.result === 'stalemate') {
			LK.effects.flashScreen(0xffff00, 800);
			LK.showYouWin('Draw by stalemate');
		} else if (end.result === 'draw') {
			LK.effects.flashScreen(0xffff00, 800);
			LK.showYouWin('Draw');
		}
		return;
	}
	// --- AI Move for Black ---
	if (currentTurn === 'black' && !gameEnded) {
		// --- AI: If an important piece is threatened, try to move it away ---
		// Define important pieces
		var importantTypes = {
			queen: true,
			rook: true,
			bishop: true,
			knight: true
		};
		// Find all black important pieces that are threatened
		var threatenedPieces = [];
		for (var y = 0; y < 8; y++) {
			for (var x = 0; x < 8; x++) {
				var p = board.getPiece(x, y);
				if (p && p.color === 'black' && importantTypes[p.type]) {
					if (isAttacked(x, y, 'black')) {
						threatenedPieces.push({
							piece: p,
							x: x,
							y: y
						});
					}
				}
			}
		}
		// If any important piece is threatened, try to move it to safety
		var aiMoves = getAllLegalMoves('black');
		if (threatenedPieces.length > 0) {
			// Try to find a move that moves a threatened important piece to a safe square
			var safeMoves = [];
			for (var i = 0; i < threatenedPieces.length; i++) {
				var tp = threatenedPieces[i];
				var moves = getLegalMoves(tp.piece, tp.x, tp.y, false);
				for (var j = 0; j < moves.length; j++) {
					var m = moves[j];
					// Simulate the move
					var origX = tp.piece.boardX,
						origY = tp.piece.boardY;
					var origTo = board.getPiece(m.x, m.y);
					board.squares[tp.y][tp.x] = null;
					board.squares[m.y][m.x] = tp.piece;
					tp.piece.boardX = m.x;
					tp.piece.boardY = m.y;
					var stillAttacked = isAttacked(m.x, m.y, 'black');
					// Undo
					board.squares[tp.y][tp.x] = tp.piece;
					board.squares[m.y][m.x] = origTo;
					tp.piece.boardX = origX;
					tp.piece.boardY = origY;
					if (!stillAttacked) {
						// Find the corresponding move in aiMoves
						for (var k = 0; k < aiMoves.length; k++) {
							var am = aiMoves[k];
							if (am.from.x === tp.x && am.from.y === tp.y && am.to.x === m.x && am.to.y === m.y) {
								safeMoves.push(am);
							}
						}
					}
				}
			}
			// If there are safe moves, pick one randomly and play it
			if (safeMoves.length > 0) {
				var chosen = safeMoves[Math.floor(Math.random() * safeMoves.length)];
				var piece = board.getPiece(chosen.from.x, chosen.from.y);
				var delay = 400;
				if (chosen.special === 'castle_kingside' || chosen.special === 'castle_queenside') delay = 900;else if (piece && piece.type === 'pawn' && (chosen.to.y === 0 || chosen.to.y === 7)) delay = 900;else if (board.getPiece(chosen.to.x, chosen.to.y)) delay = 700;else delay = 350;
				LK.setTimeout(function () {
					if (piece) {
						doMove(piece, chosen.from.x, chosen.from.y, chosen.to.x, chosen.to.y, chosen.special);
					}
				}, delay);
				return;
			}
			// If no safe move, fallback to normal AI below
		}
		// --- AI tries to mimic player's last move style ---
		// We'll try to find a move for black that is similar in type to the player's last move.
		// If not possible, fallback to best move as before.
		// Helper: get move type string
		var getMoveType = function getMoveType(move) {
			if (!move) return '';
			if (move.special === 'castle_kingside' || move.special === 'castle_queenside') return 'castle';
			if (move.special === 'enpassant') return 'enpassant';
			if (move.piece && move.piece.type === 'pawn' && (move.to.y === 0 || move.to.y === 7)) return 'promotion';
			if (move.captured) return 'capture';
			if (move.piece && move.piece.type === 'pawn') return 'pawn';
			if (move.piece && move.piece.type === 'knight') return 'knight';
			if (move.piece && move.piece.type === 'bishop') return 'bishop';
			if (move.piece && move.piece.type === 'rook') return 'rook';
			if (move.piece && move.piece.type === 'queen') return 'queen';
			if (move.piece && move.piece.type === 'king') return 'king';
			return '';
		}; // Helper: get move distance (for delay)
		var getMoveDistance = function getMoveDistance(move) {
			if (!move) return 1;
			var dx = Math.abs(move.from.x - move.to.x);
			var dy = Math.abs(move.from.y - move.to.y);
			return Math.max(dx, dy);
		}; // Get all legal moves for black
		// aiMoves already defined above
		if (aiMoves.length > 0) {
			// Use a simple minimax (depth 2) with material evaluation
			var evaluateBoard = function evaluateBoard() {
				var values = {
					pawn: 1,
					knight: 3,
					bishop: 3,
					rook: 5,
					queen: 9,
					king: 0
				};
				var score = 0;
				for (var y = 0; y < 8; y++) {
					for (var x = 0; x < 8; x++) {
						var p = board.getPiece(x, y);
						if (p) {
							var val = values[p.type] || 0;
							score += p.color === 'white' ? val : -val;
						}
					}
				}
				return score;
			};
			var simulateMove = function simulateMove(move) {
				var piece = board.getPiece(move.from.x, move.from.y);
				var target = board.getPiece(move.to.x, move.to.y);
				var fromX = move.from.x,
					fromY = move.from.y,
					toX = move.to.x,
					toY = move.to.y;
				var special = move.special;
				var origHasMoved = piece.hasMoved;
				var origEnPassant = enPassantTarget;
				var captured = null;
				// Handle en passant
				if (special === 'enpassant') {
					var dir = piece.color === 'white' ? -1 : 1;
					var capY = toY - dir;
					captured = board.getPiece(toX, capY);
					board.squares[capY][toX] = null;
				}
				// Handle castling
				var rook = null,
					rookFrom = null,
					rookTo = null;
				if (special === 'castle_kingside') {
					var row = piece.color === 'white' ? 7 : 0;
					rook = board.getPiece(7, row);
					board.squares[row][5] = rook;
					board.squares[row][7] = null;
				}
				if (special === 'castle_queenside') {
					var row = piece.color === 'white' ? 7 : 0;
					rook = board.getPiece(0, row);
					board.squares[row][3] = rook;
					board.squares[row][0] = null;
				}
				// Remove captured piece
				if (target && target.color !== piece.color) {
					board.squares[toY][toX] = null;
				}
				// Move piece
				board.squares[fromY][fromX] = null;
				board.squares[toY][toX] = piece;
				piece.hasMoved = true;
				// Pawn promotion (always promote to queen for AI)
				var promoted = false;
				var oldType = piece.type;
				if (piece.type === 'pawn' && (toY === 0 || toY === 7)) {
					piece.type = 'queen';
					promoted = true;
				}
				return function undo() {
					if (promoted) piece.type = oldType;
					// Undo move
					board.squares[fromY][fromX] = piece;
					board.squares[toY][toX] = target;
					piece.hasMoved = origHasMoved;
					// Undo en passant
					if (special === 'enpassant') {
						var dir = piece.color === 'white' ? -1 : 1;
						var capY = toY - dir;
						board.squares[capY][toX] = captured;
					}
					// Undo castling
					if (special === 'castle_kingside') {
						var row = piece.color === 'white' ? 7 : 0;
						board.squares[row][7] = board.squares[row][5];
						board.squares[row][5] = null;
					}
					if (special === 'castle_queenside') {
						var row = piece.color === 'white' ? 7 : 0;
						board.squares[row][0] = board.squares[row][3];
						board.squares[row][3] = null;
					}
					enPassantTarget = origEnPassant;
				};
			};
			// Try to mimic player's last move
			var mimicMove = null;
			var mimicType = getMoveType(lastMove);
			var mimicPieceType = lastMove && lastMove.piece ? lastMove.piece.type : null;
			var mimicCapture = lastMove && lastMove.captured ? true : false;
			var mimicSpecial = lastMove ? lastMove.special : null;
			// Find all black moves that match the last move's type
			var mimicCandidates = [];
			for (var i = 0; i < aiMoves.length; i++) {
				var move = aiMoves[i];
				var piece = board.getPiece(move.from.x, move.from.y);
				if (!piece) continue;
				// Try to match special moves
				if (mimicSpecial && move.special === mimicSpecial) {
					mimicCandidates.push(move);
					continue;
				}
				// Try to match captures
				if (mimicCapture) {
					var target = board.getPiece(move.to.x, move.to.y);
					if (target && target.color === 'white') {
						mimicCandidates.push(move);
						continue;
					}
				}
				// Try to match piece type
				if (mimicPieceType && piece.type === mimicPieceType) {
					mimicCandidates.push(move);
					continue;
				}
				// Try to match move type
				if (getMoveType({
					piece: piece,
					to: move.to,
					special: move.special,
					captured: board.getPiece(move.to.x, move.to.y)
				}) === mimicType) {
					mimicCandidates.push(move);
					continue;
				}
			}
			// If we have mimic candidates, pick the best among them using minimax
			var candidateMoves = mimicCandidates.length > 0 ? mimicCandidates : aiMoves;
			// Minimax, depth 2 (AI: black, Player: white)
			var bestScore = null;
			var bestMoves = [];
			for (var i = 0; i < candidateMoves.length; i++) {
				var move = candidateMoves[i];
				var undo = simulateMove(move);
				// After black's move, get all white replies
				var whiteMoves = getAllLegalMoves('white');
				var worstScore = null;
				if (whiteMoves.length === 0) {
					// If white has no moves, checkmate or stalemate
					if (isInCheck('white')) {
						// Black wins
						worstScore = -9999;
					} else {
						// Draw
						worstScore = 0;
					}
				} else {
					for (var j = 0; j < whiteMoves.length; j++) {
						var wmove = whiteMoves[j];
						var wundo = simulateMove(wmove);
						var score = evaluateBoard();
						if (worstScore === null || score > worstScore) {
							worstScore = score;
						}
						wundo();
					}
				}
				undo();
				// AI wants to minimize the score (since black is negative)
				if (bestScore === null || worstScore < bestScore) {
					bestScore = worstScore;
					bestMoves = [move];
				} else if (worstScore === bestScore) {
					bestMoves.push(move);
				}
			}
			// Pick randomly among best moves
			var chosen = bestMoves[Math.floor(Math.random() * bestMoves.length)];
			var piece = board.getPiece(chosen.from.x, chosen.from.y);
			// Add a delay based on move complexity (longer for captures, promotions, castling, or long moves)
			var delay = 400;
			if (chosen.special === 'castle_kingside' || chosen.special === 'castle_queenside') delay = 900;else if (piece && piece.type === 'pawn' && (chosen.to.y === 0 || chosen.to.y === 7)) delay = 900;else if (board.getPiece(chosen.to.x, chosen.to.y)) delay = 700;else delay = 350 + 80 * getMoveDistance(chosen);
			LK.setTimeout(function () {
				if (piece) {
					doMove(piece, chosen.from.x, chosen.from.y, chosen.to.x, chosen.to.y, chosen.special);
				}
			}, delay);
		}
	}
}
// --- Game Update ---
game.update = function () {
	// No per-frame logic needed for chess
};
// --- Reset on Game Over ---
LK.on('gameover', function () {
	// Reset everything
	board.reset();
	currentTurn = 'white';
	selectedPiece = null;
	legalMoves = [];
	lastMove = null;
	enPassantTarget = null;
	halfmoveClock = 0;
	fullmoveNumber = 1;
	gameEnded = false;
	turnText.setText('White to move');
	if (promotionPopup) {
		promotionPopup.destroy();
		promotionPopup = null;
	}
	// Reset timers
	stopAllTimers();
	whiteTime = 600;
	blackTime = 600;
	whiteTimerText.setText(formatTime(whiteTime));
	blackTimerText.setText(formatTime(blackTime));
	startWhiteTimer();
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// --- ChessBoard Class ---
var ChessBoard = Container.expand(function () {
	var self = Container.call(this);
	// 8x8 array of ChessPiece or null
	self.squares = [];
	for (var y = 0; y < 8; y++) {
		self.squares[y] = [];
		for (var x = 0; x < 8; x++) {
			self.squares[y][x] = null;
		}
	}
	// Draw board squares
	self.squareNodes = [];
	for (var y = 0; y < 8; y++) {
		self.squareNodes[y] = [];
		for (var x = 0; x < 8; x++) {
			var isLight = (x + y) % 2 === 0;
			// Use classic chessboard colors: light = #f0d9b5, dark = #b58863
			var color = isLight ? 0xf0d9b5 : 0xb58863;
			var assetId = 'board_' + (isLight ? 'light' : 'dark');
			var node = LK.getAsset(assetId, {
				anchorX: 0,
				anchorY: 0,
				x: boardOriginX + x * squareSize,
				y: boardOriginY + y * squareSize,
				width: squareSize,
				height: squareSize,
				color: color,
				shape: 'box'
			});
			self.addChild(node);
			self.squareNodes[y][x] = node;
		}
	}
	// Highlight squares (for moves)
	self.highlightNodes = [];
	for (var i = 0; i < 64; i++) {
		var highlightId = 'highlight_' + i;
		// Use a circle (ellipse) and center it in the square
		var node = LK.getAsset('centerCircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: Math.floor(squareSize * 0.45),
			height: Math.floor(squareSize * 0.45),
			x: -1000,
			y: -1000
		}); // Hide initially
		node.alpha = 0.25;
		self.addChild(node);
		self.highlightNodes[i] = node;
	}
	// Place pieces in starting position
	self.reset = function () {
		// Remove all pieces
		for (var y = 0; y < 8; y++) {
			for (var x = 0; x < 8; x++) {
				if (self.squares[y][x]) {
					self.squares[y][x].destroy();
					self.squares[y][x] = null;
				}
			}
		}
		// Place pawns
		for (var x = 0; x < 8; x++) {
			var wp = new ChessPiece();
			wp.init('pawn', 'white', x, 6);
			wp.moveTo(x, 6, false);
			self.addChild(wp);
			self.squares[6][x] = wp;
			var bp = new ChessPiece();
			bp.init('pawn', 'black', x, 1);
			bp.moveTo(x, 1, false);
			self.addChild(bp);
			self.squares[1][x] = bp;
		}
		// Place other pieces
		var order = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'];
		for (var x = 0; x < 8; x++) {
			var w = new ChessPiece();
			w.init(order[x], 'white', x, 7);
			w.moveTo(x, 7, false);
			self.addChild(w);
			self.squares[7][x] = w;
			var b = new ChessPiece();
			b.init(order[x], 'black', x, 0);
			b.moveTo(x, 0, false);
			self.addChild(b);
			self.squares[0][x] = b;
		}
	};
	// Remove all highlights
	self.clearHighlights = function () {
		for (var i = 0; i < 64; i++) {
			self.highlightNodes[i].x = -1000;
			self.highlightNodes[i].y = -1000;
		}
	};
	// Highlight given squares (array of {x, y})
	self.showHighlights = function (squares) {
		self.clearHighlights();
		for (var i = 0; i < squares.length; i++) {
			var idx = squares[i].y * 8 + squares[i].x;
			var node = self.highlightNodes[idx];
			// Center the highlight circle in the square
			node.x = boardOriginX + squares[i].x * squareSize + squareSize / 2;
			node.y = boardOriginY + squares[i].y * squareSize + squareSize / 2;
		}
	};
	// Get piece at board position
	self.getPiece = function (x, y) {
		if (x < 0 || x > 7 || y < 0 || y > 7) return null;
		return self.squares[y][x];
	};
	// Set piece at board position
	self.setPiece = function (x, y, piece) {
		self.squares[y][x] = piece;
	};
	// Remove piece at board position
	self.removePiece = function (x, y) {
		var p = self.squares[y][x];
		if (p) {
			p.destroy();
			self.squares[y][x] = null;
		}
	};
	return self;
});
// --- ChessPiece Class ---
var ChessPiece = Container.expand(function () {
	var self = Container.call(this);
	// Properties
	self.type = null; // 'pawn', 'rook', 'knight', 'bishop', 'queen', 'king'
	self.color = null; // 'white' or 'black'
	self.boardX = 0; // 0-7
	self.boardY = 0; // 0-7
	self.hasMoved = false; // For castling/en passant
	self.promoted = false; // For pawn promotion
	// Asset
	self.pieceAsset = null;
	// Set piece type and color, and create asset
	self.init = function (type, color, boardX, boardY) {
		self.type = type;
		self.color = color;
		self.boardX = boardX;
		self.boardY = boardY;
		self.hasMoved = false;
		self.promoted = false;
		// Remove old asset if any
		if (self.pieceAsset) {
			self.removeChild(self.pieceAsset);
		}
		// Use classic piece colors: white = #fff, black = #222
		var colorMap = {
			'white': {
				'pawn': 0xffffff,
				'rook': 0xffffff,
				'knight': 0xffffff,
				'bishop': 0xffffff,
				'queen': 0xffffff,
				'king': 0xffffff
			},
			'black': {
				'pawn': 0x222222,
				'rook': 0x222222,
				'knight': 0x222222,
				'bishop': 0x222222,
				'queen': 0x222222,
				'king': 0x222222
			}
		};
		var shape = self.type === 'pawn' || self.type === 'bishop' ? 'ellipse' : 'box';
		var assetId = self.color + '_' + self.type;
		var assetColor = colorMap[self.color][self.type];
		var size = self.type === 'king' ? Math.floor(pieceSize * 1.25) : pieceSize;
		self.pieceAsset = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5,
			width: size,
			height: size,
			color: assetColor,
			shape: shape
		});
		// Add a crown for promoted pawns
		if (self.promoted && self.type === 'queen') {
			// Overlay a small yellow ellipse as a "crown"
			var crown = LK.getAsset('crown_' + self.color, {
				anchorX: 0.5,
				anchorY: 0.5,
				y: -size * 0.3
			});
			self.addChild(crown);
		}
	};
	// Move piece to board position (with optional animation)
	self.moveTo = function (bx, by, animate) {
		self.boardX = bx;
		self.boardY = by;
		var targetX = boardOriginX + bx * squareSize + squareSize / 2;
		var targetY = boardOriginY + by * squareSize + squareSize / 2;
		if (animate) {
			tween(self, {
				x: targetX,
				y: targetY
			}, {
				duration: 180,
				easing: tween.cubicOut
			});
		} else {
			self.x = targetX;
			self.y = targetY;
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x222222
});
/**** 
* Game Code
****/ 
// Crown for promoted pawn (queen)
// Black pieces
// White pieces
// Board squares
// We need tween for piece movement animations
// --- Board and Piece Sizes ---
var boardSize = Math.min(2048, 2048); // Square board, fit width
var squareSize = Math.floor(boardSize / 8);
var pieceSize = Math.floor(squareSize * 0.8);
var boardOriginX = Math.floor((2048 - squareSize * 8) / 2);
var boardOriginY = Math.floor((2732 - squareSize * 8) / 2);
// --- Game State ---
var board = new ChessBoard();
game.addChild(board);
board.reset();
var currentTurn = 'white'; // 'white' or 'black'
var selectedPiece = null;
var legalMoves = []; // Array of {x, y, special}
var lastMove = null; // {from: {x,y}, to: {x,y}, piece, captured, special}
var enPassantTarget = null; // {x, y} or null
var halfmoveClock = 0; // For 50-move rule
var fullmoveNumber = 1;
var gameEnded = false;
// --- GUI: Turn Display ---
var turnText = new Text2('White to move', {
	size: 90,
	fill: "#fff"
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
// --- GUI: Timers ---
// Each player starts with 10 minutes (600 seconds)
var whiteTime = 600;
var blackTime = 600;
var whiteTimerText = new Text2('10:00', {
	size: 90,
	fill: "#fff"
});
// Place white timer near bottom left, above white's side, but not in the bottom left 100x100 reserved area
whiteTimerText.anchor.set(0, 1); // left aligned, bottom
whiteTimerText.x = 320; // moved even further right
whiteTimerText.y = LK.gui.height - 40;
LK.gui.bottomLeft.addChild(whiteTimerText);
var blackTimerText = new Text2('10:00', {
	size: 90,
	fill: "#fff"
});
// Place black timer near top right, above black's side, but not in the top right 100x100 reserved area
blackTimerText.anchor.set(1, 0); // right aligned, top
blackTimerText.x = LK.gui.width - 40; // moved even further right (inward)
blackTimerText.y = 0;
LK.gui.topRight.addChild(blackTimerText);
// Timer state
var whiteTimerInterval = null;
var blackTimerInterval = null;
// Helper to format seconds as MM:SS
function formatTime(secs) {
	var m = Math.floor(secs / 60);
	var s = Math.floor(secs % 60);
	return (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s;
}
// Start/stop timer helpers
function startWhiteTimer() {
	if (whiteTimerInterval) LK.clearInterval(whiteTimerInterval);
	whiteTimerInterval = LK.setInterval(function () {
		if (gameEnded) return;
		whiteTime--;
		if (whiteTime < 0) whiteTime = 0;
		whiteTimerText.setText(formatTime(whiteTime));
		if (whiteTime === 0) {
			gameEnded = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showYouWin('Black wins on time!');
			stopAllTimers();
		}
	}, 1000);
}
function startBlackTimer() {
	if (blackTimerInterval) LK.clearInterval(blackTimerInterval);
	blackTimerInterval = LK.setInterval(function () {
		if (gameEnded) return;
		blackTime--;
		if (blackTime < 0) blackTime = 0;
		blackTimerText.setText(formatTime(blackTime));
		if (blackTime === 0) {
			gameEnded = true;
			LK.effects.flashScreen(0xff0000, 800);
			LK.showYouWin('White wins on time!');
			stopAllTimers();
		}
	}, 1000);
}
function stopWhiteTimer() {
	if (whiteTimerInterval) {
		LK.clearInterval(whiteTimerInterval);
		whiteTimerInterval = null;
	}
}
function stopBlackTimer() {
	if (blackTimerInterval) {
		LK.clearInterval(blackTimerInterval);
		blackTimerInterval = null;
	}
}
function stopAllTimers() {
	stopWhiteTimer();
	stopBlackTimer();
}
// Start white's timer at game start
startWhiteTimer();
whiteTimerText.setText(formatTime(whiteTime));
blackTimerText.setText(formatTime(blackTime));
// --- GUI: Promotion Popup ---
var promotionPopup = null;
// --- Helper Functions ---
// Convert screen (x, y) to board (bx, by)
function screenToBoard(x, y) {
	var bx = Math.floor((x - boardOriginX) / squareSize);
	var by = Math.floor((y - boardOriginY) / squareSize);
	if (bx < 0 || bx > 7 || by < 0 || by > 7) return null;
	return {
		x: bx,
		y: by
	};
}
// Convert board (bx, by) to screen (x, y) (center of square)
function boardToScreen(bx, by) {
	return {
		x: boardOriginX + bx * squareSize + squareSize / 2,
		y: boardOriginY + by * squareSize + squareSize / 2
	};
}
// Is (x, y) on the board?
function isOnBoard(x, y) {
	return x >= 0 && x < 8 && y >= 0 && y < 8;
}
// Get all legal moves for a piece at (x, y)
function getLegalMoves(piece, x, y, ignoreCheck) {
	var moves = [];
	if (!piece) return moves;
	var color = piece.color;
	var opp = color === 'white' ? 'black' : 'white';
	// Directions for sliding pieces
	var dirs = {
		'rook': [[1, 0], [-1, 0], [0, 1], [0, -1]],
		'bishop': [[1, 1], [1, -1], [-1, 1], [-1, -1]],
		'queen': [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
	};
	// Pawn moves
	if (piece.type === 'pawn') {
		var dir = color === 'white' ? -1 : 1;
		// Forward
		if (isOnBoard(x, y + dir) && !board.getPiece(x, y + dir)) {
			moves.push({
				x: x,
				y: y + dir
			});
			// Double move from start
			if (!piece.hasMoved && isOnBoard(x, y + 2 * dir) && !board.getPiece(x, y + 2 * dir)) {
				moves.push({
					x: x,
					y: y + 2 * dir,
					special: 'double'
				});
			}
		}
		// Captures
		for (var dx = -1; dx <= 1; dx += 2) {
			var tx = x + dx,
				ty = y + dir;
			if (isOnBoard(tx, ty)) {
				var target = board.getPiece(tx, ty);
				if (target && target.color === opp) {
					moves.push({
						x: tx,
						y: ty
					});
				}
			}
		}
		// En passant
		if (enPassantTarget) {
			if (Math.abs(enPassantTarget.x - x) === 1 && enPassantTarget.y === y + dir) {
				moves.push({
					x: enPassantTarget.x,
					y: enPassantTarget.y,
					special: 'enpassant'
				});
			}
		}
	}
	// Knight moves
	else if (piece.type === 'knight') {
		var knightDeltas = [[1, 2], [2, 1], [-1, 2], [-2, 1], [1, -2], [2, -1], [-1, -2], [-2, -1]];
		for (var i = 0; i < knightDeltas.length; i++) {
			var dx = knightDeltas[i][0],
				dy = knightDeltas[i][1];
			var tx = x + dx,
				ty = y + dy;
			if (isOnBoard(tx, ty)) {
				var target = board.getPiece(tx, ty);
				if (!target || target.color === opp) {
					moves.push({
						x: tx,
						y: ty
					});
				}
			}
		}
	}
	// King moves (including castling)
	else if (piece.type === 'king') {
		// Prevent infinite recursion: when ignoreCheck is true, do NOT generate king moves
		if (ignoreCheck) {
			// Do not generate king moves when ignoreCheck is true (used for attack detection)
			// This prevents infinite recursion between isInCheck and getLegalMoves
		} else {
			// Find the other king's position
			var otherKingPos = null;
			for (var yy = 0; yy < 8; yy++) {
				for (var xx = 0; xx < 8; xx++) {
					var p = board.getPiece(xx, yy);
					if (p && p.type === 'king' && p.color !== color) {
						otherKingPos = {
							x: xx,
							y: yy
						};
						break;
					}
				}
				if (otherKingPos) break;
			}
			for (var dx = -1; dx <= 1; dx++) {
				for (var dy = -1; dy <= 1; dy++) {
					if (dx === 0 && dy === 0) continue;
					var tx = x + dx,
						ty = y + dy;
					if (isOnBoard(tx, ty)) {
						// Prevent moving to any square adjacent (1 square away) to the other king
						var allow = true;
						if (otherKingPos) {
							// If the target square is adjacent (including diagonals) to the other king, disallow
							if (Math.abs(tx - otherKingPos.x) <= 1 && Math.abs(ty - otherKingPos.y) <= 1) allow = false;
							if (tx === otherKingPos.x && ty === otherKingPos.y) allow = false;
						}
						var target = board.getPiece(tx, ty);
						if ((!target || target.color === opp) && allow) {
							moves.push({
								x: tx,
								y: ty
							});
						}
					}
				}
			}
			// Castling
			if (!piece.hasMoved && !isInCheck(color)) {
				// Kingside
				if (canCastle(color, 'kingside')) {
					// Check that castling does not violate the king distance rule
					var castleTx = x + 2;
					var castleTy = y;
					var allowCastle = true;
					if (otherKingPos) {
						if (Math.abs(castleTx - otherKingPos.x) <= 3 && castleTy === otherKingPos.y) allowCastle = false;
						if (Math.abs(castleTy - otherKingPos.y) <= 3 && castleTx === otherKingPos.x) allowCastle = false;
						if (castleTx === otherKingPos.x && castleTy === otherKingPos.y) allowCastle = false;
					}
					if (allowCastle) {
						moves.push({
							x: castleTx,
							y: castleTy,
							special: 'castle_kingside'
						});
					}
				}
				// Queenside
				if (canCastle(color, 'queenside')) {
					var castleTx = x - 2;
					var castleTy = y;
					var allowCastle = true;
					if (otherKingPos) {
						if (Math.abs(castleTx - otherKingPos.x) <= 3 && castleTy === otherKingPos.y) allowCastle = false;
						if (Math.abs(castleTy - otherKingPos.y) <= 3 && castleTx === otherKingPos.x) allowCastle = false;
						if (castleTx === otherKingPos.x && castleTy === otherKingPos.y) allowCastle = false;
					}
					if (allowCastle) {
						moves.push({
							x: castleTx,
							y: castleTy,
							special: 'castle_queenside'
						});
					}
				}
			}
		}
	}
	// Sliding pieces
	else if (piece.type === 'rook' || piece.type === 'bishop' || piece.type === 'queen') {
		var directions = dirs[piece.type];
		for (var d = 0; d < directions.length; d++) {
			var dx = directions[d][0],
				dy = directions[d][1];
			var tx = x + dx,
				ty = y + dy;
			while (isOnBoard(tx, ty)) {
				var target = board.getPiece(tx, ty);
				if (!target) {
					moves.push({
						x: tx,
						y: ty
					});
				} else {
					if (target.color === opp) {
						moves.push({
							x: tx,
							y: ty
						});
					}
					break;
				}
				tx += dx;
				ty += dy;
			}
		}
	}
	// Remove moves that leave king in check (unless ignoreCheck)
	if (!ignoreCheck) {
		var filtered = [];
		for (var i = 0; i < moves.length; i++) {
			var m = moves[i];
			if (!wouldLeaveKingInCheck(piece, x, y, m.x, m.y, m.special)) {
				filtered.push(m);
			}
		}
		return filtered;
	}
	return moves;
}
// Would moving piece at (x, y) to (tx, ty) leave own king in check?
function wouldLeaveKingInCheck(piece, x, y, tx, ty, special) {
	// Simulate move
	var origPiece = board.getPiece(tx, ty);
	var origEnPassant = enPassantTarget;
	var origHasMoved = piece.hasMoved;
	var origFrom = board.squares[y][x];
	var origTo = board.squares[ty][tx];
	// Remove captured piece
	if (special === 'enpassant') {
		var dir = piece.color === 'white' ? -1 : 1;
		var capY = ty - dir;
		var capPiece = board.getPiece(tx, capY);
		board.squares[capY][tx] = null;
	}
	board.squares[y][x] = null;
	board.squares[ty][tx] = piece;
	// For castling, move rook as well
	var rookMoved = null,
		rookFrom = null,
		rookTo = null;
	if (special === 'castle_kingside') {
		var row = piece.color === 'white' ? 7 : 0;
		rookFrom = board.getPiece(7, row);
		rookTo = board.getPiece(5, row);
		board.squares[row][7] = null;
		board.squares[row][5] = rookFrom;
	}
	if (special === 'castle_queenside') {
		var row = piece.color === 'white' ? 7 : 0;
		rookFrom = board.getPiece(0, row);
		rookTo = board.getPiece(3, row);
		board.squares[row][0] = null;
		board.squares[row][3] = rookFrom;
	}
	var inCheck = isInCheck(piece.color);
	// Undo move
	board.squares[y][x] = origFrom;
	board.squares[ty][tx] = origTo;
	if (special === 'enpassant') {
		var dir = piece.color === 'white' ? -1 : 1;
		var capY = ty - dir;
		board.squares[capY][tx] = origPiece;
	}
	if (special === 'castle_kingside') {
		var row = piece.color === 'white' ? 7 : 0;
		board.squares[row][7] = rookFrom;
		board.squares[row][5] = null;
	}
	if (special === 'castle_queenside') {
		var row = piece.color === 'white' ? 7 : 0;
		board.squares[row][0] = rookFrom;
		board.squares[row][3] = null;
	}
	piece.hasMoved = origHasMoved;
	enPassantTarget = origEnPassant;
	return inCheck;
}
// Is color's king in check?
function isInCheck(color) {
	var kingPos = findKing(color);
	if (!kingPos) return false;
	var opp = color === 'white' ? 'black' : 'white';
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.color === opp) {
				var moves = getLegalMoves(p, x, y, true);
				for (var i = 0; i < moves.length; i++) {
					if (moves[i].x === kingPos.x && moves[i].y === kingPos.y) {
						return true;
					}
				}
			}
		}
	}
	return false;
}
// Find king of color
function findKing(color) {
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.type === 'king' && p.color === color) {
				return {
					x: x,
					y: y
				};
			}
		}
	}
	return null;
}
// Can color castle on side ('kingside' or 'queenside')?
function canCastle(color, side) {
	var row = color === 'white' ? 7 : 0;
	var king = board.getPiece(4, row);
	if (!king || king.hasMoved) return false;
	if (side === 'kingside') {
		var rook = board.getPiece(7, row);
		if (!rook || rook.type !== 'rook' || rook.hasMoved) return false;
		// Squares between must be empty
		if (board.getPiece(5, row) || board.getPiece(6, row)) return false;
		// Squares king passes through must not be attacked
		if (isAttacked(5, row, color) || isAttacked(6, row, color)) return false;
		return true;
	}
	if (side === 'queenside') {
		var rook = board.getPiece(0, row);
		if (!rook || rook.type !== 'rook' || rook.hasMoved) return false;
		if (board.getPiece(1, row) || board.getPiece(2, row) || board.getPiece(3, row)) return false;
		if (isAttacked(2, row, color) || isAttacked(3, row, color)) return false;
		return true;
	}
	return false;
}
// Is square (x, y) attacked by opponent of color?
function isAttacked(x, y, color) {
	var opp = color === 'white' ? 'black' : 'white';
	for (var yy = 0; yy < 8; yy++) {
		for (var xx = 0; xx < 8; xx++) {
			var p = board.getPiece(xx, yy);
			if (p && p.color === opp) {
				var moves = getLegalMoves(p, xx, yy, true);
				for (var i = 0; i < moves.length; i++) {
					if (moves[i].x === x && moves[i].y === y) {
						return true;
					}
				}
			}
		}
	}
	return false;
}
// Get all legal moves for color
function getAllLegalMoves(color) {
	var moves = [];
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.color === color) {
				var pieceMoves = getLegalMoves(p, x, y, false);
				for (var i = 0; i < pieceMoves.length; i++) {
					moves.push({
						from: {
							x: x,
							y: y
						},
						to: {
							x: pieceMoves[i].x,
							y: pieceMoves[i].y
						},
						special: pieceMoves[i].special
					});
				}
			}
		}
	}
	return moves;
}
// Is the game over? Returns {over: true/false, result: 'checkmate'/'stalemate'/'draw', winner: 'white'/'black'/null}
function checkGameEnd() {
	var moves = getAllLegalMoves(currentTurn);
	if (moves.length === 0) {
		if (isInCheck(currentTurn)) {
			return {
				over: true,
				result: 'checkmate',
				winner: currentTurn === 'white' ? 'black' : 'white'
			};
		} else {
			return {
				over: true,
				result: 'stalemate',
				winner: null
			};
		}
	}
	// 50-move rule
	if (halfmoveClock >= 100) {
		return {
			over: true,
			result: 'draw',
			winner: null
		};
	}
	// Insufficient material (only kings)
	var onlyKings = true;
	for (var y = 0; y < 8; y++) {
		for (var x = 0; x < 8; x++) {
			var p = board.getPiece(x, y);
			if (p && p.type !== 'king') onlyKings = false;
		}
	}
	if (onlyKings) {
		return {
			over: true,
			result: 'draw',
			winner: null
		};
	}
	return {
		over: false
	};
}
// --- Promotion Popup ---
function showPromotionPopup(piece, toX, toY, onSelect) {
	if (promotionPopup) {
		promotionPopup.destroy();
		promotionPopup = null;
	}
	promotionPopup = new Container();
	var popupW = squareSize * 4;
	var popupH = squareSize * 1.2;
	var popupX = boardOriginX + (toX - 1) * squareSize;
	var popupY = boardOriginY + toY * squareSize - popupH / 2;
	var bg = LK.getAsset('promotion_bg', {
		anchorX: 0,
		anchorY: 0,
		x: 0,
		y: 0
	});
	bg.alpha = 0.95;
	promotionPopup.addChild(bg);
	var types = ['queen', 'rook', 'bishop', 'knight'];
	for (var i = 0; i < types.length; i++) {
		var t = types[i];
		var tempPiece = new ChessPiece();
		tempPiece.init(t, piece.color, 0, 0);
		tempPiece.x = squareSize * (i + 0.5);
		tempPiece.y = popupH / 2;
		tempPiece.pieceAsset.width = pieceSize * 0.9;
		tempPiece.pieceAsset.height = pieceSize * 0.9;
		(function (type) {
			tempPiece.down = function (x, y, obj) {
				if (promotionPopup) {
					onSelect(type);
					promotionPopup.destroy();
					promotionPopup = null;
				}
			};
		})(t);
		promotionPopup.addChild(tempPiece);
	}
	promotionPopup.x = popupX;
	promotionPopup.y = popupY;
	game.addChild(promotionPopup);
}
// --- Tap-to-select and tap-to-move ---
// No dragging variables needed
// --- Event Handlers ---
// Handle touch/mouse down (tap)
game.down = function (x, y, obj) {
	if (gameEnded) return;
	if (promotionPopup) return; // Block input during promotion
	var pos = screenToBoard(x, y);
	if (!pos) return;
	var p = board.getPiece(pos.x, pos.y);
	// If a piece is already selected and the tap is on a legal move, move there
	if (selectedPiece && legalMoves.length > 0) {
		for (var i = 0; i < legalMoves.length; i++) {
			var m = legalMoves[i];
			if (m.x === pos.x && m.y === pos.y) {
				// Move piece
				doMove(selectedPiece, selectedPiece.boardX, selectedPiece.boardY, m.x, m.y, m.special);
				board.clearHighlights();
				selectedPiece = null;
				legalMoves = [];
				return;
			}
		}
	}
	// If tap is on a piece of current turn, select it and show moves
	if (p && p.color === currentTurn) {
		selectedPiece = p;
		legalMoves = getLegalMoves(p, pos.x, pos.y, false);
		board.showHighlights(legalMoves);
		return;
	}
	// If tap is on empty square or not a legal move, clear selection
	board.clearHighlights();
	selectedPiece = null;
	legalMoves = [];
};
// No dragging, so move and up handlers are not needed
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// --- Move Execution ---
function doMove(piece, fromX, fromY, toX, toY, special) {
	var opp = piece.color === 'white' ? 'black' : 'white';
	var captured = null;
	var isPawnMove = piece.type === 'pawn';
	var isCapture = false;
	// Handle en passant
	if (special === 'enpassant') {
		var dir = piece.color === 'white' ? -1 : 1;
		var capY = toY - dir;
		captured = board.getPiece(toX, capY);
		board.removePiece(toX, capY);
		isCapture = true;
	}
	// Handle castling
	if (special === 'castle_kingside') {
		var row = piece.color === 'white' ? 7 : 0;
		var rook = board.getPiece(7, row);
		board.setPiece(5, row, rook);
		board.setPiece(7, row, null);
		rook.moveTo(5, row, true);
		rook.hasMoved = true;
	}
	if (special === 'castle_queenside') {
		var row = piece.color === 'white' ? 7 : 0;
		var rook = board.getPiece(0, row);
		board.setPiece(3, row, rook);
		board.setPiece(0, row, null);
		rook.moveTo(3, row, true);
		rook.hasMoved = true;
	}
	// Remove captured piece
	var target = board.getPiece(toX, toY);
	if (target && target.color !== piece.color) {
		captured = target;
		board.removePiece(toX, toY);
		isCapture = true;
	}
	// Move piece
	board.setPiece(fromX, fromY, null);
	board.setPiece(toX, toY, piece);
	piece.moveTo(toX, toY, true);
	piece.hasMoved = true;
	// Play move sound
	LK.getSound('tas').play();
	// Pawn promotion
	if (piece.type === 'pawn' && (toY === 0 || toY === 7)) {
		showPromotionPopup(piece, toX, toY, function (newType) {
			piece.type = newType;
			piece.promoted = newType === 'queen';
			piece.init(newType, piece.color, toX, toY);
			endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture);
		});
		return;
	}
	endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture);
}
function endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture) {
	// Update en passant
	if (piece.type === 'pawn' && Math.abs(toY - fromY) === 2) {
		enPassantTarget = {
			x: toX,
			y: (fromY + toY) / 2
		};
	} else {
		enPassantTarget = null;
	}
	// Update halfmove clock
	if (isPawnMove || isCapture) {
		halfmoveClock = 0;
	} else {
		halfmoveClock++;
	}
	// Update fullmove number
	if (currentTurn === 'black') {
		fullmoveNumber++;
	}
	// Save last move
	lastMove = {
		from: {
			x: fromX,
			y: fromY
		},
		to: {
			x: toX,
			y: toY
		},
		piece: piece,
		captured: captured,
		special: special
	};
	// Switch turn
	if (currentTurn === 'white') {
		stopWhiteTimer();
		startBlackTimer();
		currentTurn = 'black';
	} else {
		stopBlackTimer();
		startWhiteTimer();
		currentTurn = 'white';
	}
	turnText.setText((currentTurn === 'white' ? 'White' : 'Black') + ' to move');
	// Check for game end
	var end = checkGameEnd();
	if (end.over) {
		gameEnded = true;
		stopAllTimers();
		if (end.result === 'checkmate') {
			LK.effects.flashScreen(0x00ff00, 800);
			if (end.winner === 'white') {
				LK.showYouWin('White wins by checkmate!');
			} else if (end.winner === 'black') {
				LK.showYouWin('Black wins by checkmate!');
			}
		} else if (end.result === 'stalemate') {
			LK.effects.flashScreen(0xffff00, 800);
			LK.showYouWin('Draw by stalemate');
		} else if (end.result === 'draw') {
			LK.effects.flashScreen(0xffff00, 800);
			LK.showYouWin('Draw');
		}
		return;
	}
	// --- AI Move for Black ---
	if (currentTurn === 'black' && !gameEnded) {
		// --- AI: If an important piece is threatened, try to move it away ---
		// Define important pieces
		var importantTypes = {
			queen: true,
			rook: true,
			bishop: true,
			knight: true
		};
		// Find all black important pieces that are threatened
		var threatenedPieces = [];
		for (var y = 0; y < 8; y++) {
			for (var x = 0; x < 8; x++) {
				var p = board.getPiece(x, y);
				if (p && p.color === 'black' && importantTypes[p.type]) {
					if (isAttacked(x, y, 'black')) {
						threatenedPieces.push({
							piece: p,
							x: x,
							y: y
						});
					}
				}
			}
		}
		// If any important piece is threatened, try to move it to safety
		var aiMoves = getAllLegalMoves('black');
		if (threatenedPieces.length > 0) {
			// Try to find a move that moves a threatened important piece to a safe square
			var safeMoves = [];
			for (var i = 0; i < threatenedPieces.length; i++) {
				var tp = threatenedPieces[i];
				var moves = getLegalMoves(tp.piece, tp.x, tp.y, false);
				for (var j = 0; j < moves.length; j++) {
					var m = moves[j];
					// Simulate the move
					var origX = tp.piece.boardX,
						origY = tp.piece.boardY;
					var origTo = board.getPiece(m.x, m.y);
					board.squares[tp.y][tp.x] = null;
					board.squares[m.y][m.x] = tp.piece;
					tp.piece.boardX = m.x;
					tp.piece.boardY = m.y;
					var stillAttacked = isAttacked(m.x, m.y, 'black');
					// Undo
					board.squares[tp.y][tp.x] = tp.piece;
					board.squares[m.y][m.x] = origTo;
					tp.piece.boardX = origX;
					tp.piece.boardY = origY;
					if (!stillAttacked) {
						// Find the corresponding move in aiMoves
						for (var k = 0; k < aiMoves.length; k++) {
							var am = aiMoves[k];
							if (am.from.x === tp.x && am.from.y === tp.y && am.to.x === m.x && am.to.y === m.y) {
								safeMoves.push(am);
							}
						}
					}
				}
			}
			// If there are safe moves, pick one randomly and play it
			if (safeMoves.length > 0) {
				var chosen = safeMoves[Math.floor(Math.random() * safeMoves.length)];
				var piece = board.getPiece(chosen.from.x, chosen.from.y);
				var delay = 400;
				if (chosen.special === 'castle_kingside' || chosen.special === 'castle_queenside') delay = 900;else if (piece && piece.type === 'pawn' && (chosen.to.y === 0 || chosen.to.y === 7)) delay = 900;else if (board.getPiece(chosen.to.x, chosen.to.y)) delay = 700;else delay = 350;
				LK.setTimeout(function () {
					if (piece) {
						doMove(piece, chosen.from.x, chosen.from.y, chosen.to.x, chosen.to.y, chosen.special);
					}
				}, delay);
				return;
			}
			// If no safe move, fallback to normal AI below
		}
		// --- AI tries to mimic player's last move style ---
		// We'll try to find a move for black that is similar in type to the player's last move.
		// If not possible, fallback to best move as before.
		// Helper: get move type string
		var getMoveType = function getMoveType(move) {
			if (!move) return '';
			if (move.special === 'castle_kingside' || move.special === 'castle_queenside') return 'castle';
			if (move.special === 'enpassant') return 'enpassant';
			if (move.piece && move.piece.type === 'pawn' && (move.to.y === 0 || move.to.y === 7)) return 'promotion';
			if (move.captured) return 'capture';
			if (move.piece && move.piece.type === 'pawn') return 'pawn';
			if (move.piece && move.piece.type === 'knight') return 'knight';
			if (move.piece && move.piece.type === 'bishop') return 'bishop';
			if (move.piece && move.piece.type === 'rook') return 'rook';
			if (move.piece && move.piece.type === 'queen') return 'queen';
			if (move.piece && move.piece.type === 'king') return 'king';
			return '';
		}; // Helper: get move distance (for delay)
		var getMoveDistance = function getMoveDistance(move) {
			if (!move) return 1;
			var dx = Math.abs(move.from.x - move.to.x);
			var dy = Math.abs(move.from.y - move.to.y);
			return Math.max(dx, dy);
		}; // Get all legal moves for black
		// aiMoves already defined above
		if (aiMoves.length > 0) {
			// Use a simple minimax (depth 2) with material evaluation
			var evaluateBoard = function evaluateBoard() {
				var values = {
					pawn: 1,
					knight: 3,
					bishop: 3,
					rook: 5,
					queen: 9,
					king: 0
				};
				var score = 0;
				for (var y = 0; y < 8; y++) {
					for (var x = 0; x < 8; x++) {
						var p = board.getPiece(x, y);
						if (p) {
							var val = values[p.type] || 0;
							score += p.color === 'white' ? val : -val;
						}
					}
				}
				return score;
			};
			var simulateMove = function simulateMove(move) {
				var piece = board.getPiece(move.from.x, move.from.y);
				var target = board.getPiece(move.to.x, move.to.y);
				var fromX = move.from.x,
					fromY = move.from.y,
					toX = move.to.x,
					toY = move.to.y;
				var special = move.special;
				var origHasMoved = piece.hasMoved;
				var origEnPassant = enPassantTarget;
				var captured = null;
				// Handle en passant
				if (special === 'enpassant') {
					var dir = piece.color === 'white' ? -1 : 1;
					var capY = toY - dir;
					captured = board.getPiece(toX, capY);
					board.squares[capY][toX] = null;
				}
				// Handle castling
				var rook = null,
					rookFrom = null,
					rookTo = null;
				if (special === 'castle_kingside') {
					var row = piece.color === 'white' ? 7 : 0;
					rook = board.getPiece(7, row);
					board.squares[row][5] = rook;
					board.squares[row][7] = null;
				}
				if (special === 'castle_queenside') {
					var row = piece.color === 'white' ? 7 : 0;
					rook = board.getPiece(0, row);
					board.squares[row][3] = rook;
					board.squares[row][0] = null;
				}
				// Remove captured piece
				if (target && target.color !== piece.color) {
					board.squares[toY][toX] = null;
				}
				// Move piece
				board.squares[fromY][fromX] = null;
				board.squares[toY][toX] = piece;
				piece.hasMoved = true;
				// Pawn promotion (always promote to queen for AI)
				var promoted = false;
				var oldType = piece.type;
				if (piece.type === 'pawn' && (toY === 0 || toY === 7)) {
					piece.type = 'queen';
					promoted = true;
				}
				return function undo() {
					if (promoted) piece.type = oldType;
					// Undo move
					board.squares[fromY][fromX] = piece;
					board.squares[toY][toX] = target;
					piece.hasMoved = origHasMoved;
					// Undo en passant
					if (special === 'enpassant') {
						var dir = piece.color === 'white' ? -1 : 1;
						var capY = toY - dir;
						board.squares[capY][toX] = captured;
					}
					// Undo castling
					if (special === 'castle_kingside') {
						var row = piece.color === 'white' ? 7 : 0;
						board.squares[row][7] = board.squares[row][5];
						board.squares[row][5] = null;
					}
					if (special === 'castle_queenside') {
						var row = piece.color === 'white' ? 7 : 0;
						board.squares[row][0] = board.squares[row][3];
						board.squares[row][3] = null;
					}
					enPassantTarget = origEnPassant;
				};
			};
			// Try to mimic player's last move
			var mimicMove = null;
			var mimicType = getMoveType(lastMove);
			var mimicPieceType = lastMove && lastMove.piece ? lastMove.piece.type : null;
			var mimicCapture = lastMove && lastMove.captured ? true : false;
			var mimicSpecial = lastMove ? lastMove.special : null;
			// Find all black moves that match the last move's type
			var mimicCandidates = [];
			for (var i = 0; i < aiMoves.length; i++) {
				var move = aiMoves[i];
				var piece = board.getPiece(move.from.x, move.from.y);
				if (!piece) continue;
				// Try to match special moves
				if (mimicSpecial && move.special === mimicSpecial) {
					mimicCandidates.push(move);
					continue;
				}
				// Try to match captures
				if (mimicCapture) {
					var target = board.getPiece(move.to.x, move.to.y);
					if (target && target.color === 'white') {
						mimicCandidates.push(move);
						continue;
					}
				}
				// Try to match piece type
				if (mimicPieceType && piece.type === mimicPieceType) {
					mimicCandidates.push(move);
					continue;
				}
				// Try to match move type
				if (getMoveType({
					piece: piece,
					to: move.to,
					special: move.special,
					captured: board.getPiece(move.to.x, move.to.y)
				}) === mimicType) {
					mimicCandidates.push(move);
					continue;
				}
			}
			// If we have mimic candidates, pick the best among them using minimax
			var candidateMoves = mimicCandidates.length > 0 ? mimicCandidates : aiMoves;
			// Minimax, depth 2 (AI: black, Player: white)
			var bestScore = null;
			var bestMoves = [];
			for (var i = 0; i < candidateMoves.length; i++) {
				var move = candidateMoves[i];
				var undo = simulateMove(move);
				// After black's move, get all white replies
				var whiteMoves = getAllLegalMoves('white');
				var worstScore = null;
				if (whiteMoves.length === 0) {
					// If white has no moves, checkmate or stalemate
					if (isInCheck('white')) {
						// Black wins
						worstScore = -9999;
					} else {
						// Draw
						worstScore = 0;
					}
				} else {
					for (var j = 0; j < whiteMoves.length; j++) {
						var wmove = whiteMoves[j];
						var wundo = simulateMove(wmove);
						var score = evaluateBoard();
						if (worstScore === null || score > worstScore) {
							worstScore = score;
						}
						wundo();
					}
				}
				undo();
				// AI wants to minimize the score (since black is negative)
				if (bestScore === null || worstScore < bestScore) {
					bestScore = worstScore;
					bestMoves = [move];
				} else if (worstScore === bestScore) {
					bestMoves.push(move);
				}
			}
			// Pick randomly among best moves
			var chosen = bestMoves[Math.floor(Math.random() * bestMoves.length)];
			var piece = board.getPiece(chosen.from.x, chosen.from.y);
			// Add a delay based on move complexity (longer for captures, promotions, castling, or long moves)
			var delay = 400;
			if (chosen.special === 'castle_kingside' || chosen.special === 'castle_queenside') delay = 900;else if (piece && piece.type === 'pawn' && (chosen.to.y === 0 || chosen.to.y === 7)) delay = 900;else if (board.getPiece(chosen.to.x, chosen.to.y)) delay = 700;else delay = 350 + 80 * getMoveDistance(chosen);
			LK.setTimeout(function () {
				if (piece) {
					doMove(piece, chosen.from.x, chosen.from.y, chosen.to.x, chosen.to.y, chosen.special);
				}
			}, delay);
		}
	}
}
// --- Game Update ---
game.update = function () {
	// No per-frame logic needed for chess
};
// --- Reset on Game Over ---
LK.on('gameover', function () {
	// Reset everything
	board.reset();
	currentTurn = 'white';
	selectedPiece = null;
	legalMoves = [];
	lastMove = null;
	enPassantTarget = null;
	halfmoveClock = 0;
	fullmoveNumber = 1;
	gameEnded = false;
	turnText.setText('White to move');
	if (promotionPopup) {
		promotionPopup.destroy();
		promotionPopup = null;
	}
	// Reset timers
	stopAllTimers();
	whiteTime = 600;
	blackTime = 600;
	whiteTimerText.setText(formatTime(whiteTime));
	blackTimerText.setText(formatTime(blackTime));
	startWhiteTimer();
});