/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ChessBoard = Container.expand(function () {
var self = Container.call(this);
self.squares = [];
self.pieces = [];
self.moveHistory = [];
self.capturedWhite = [];
self.capturedBlack = [];
self.init = function () {
self.createBoard();
self.setupPieces();
return self;
};
self.createBoard = function () {
for (var row = 0; row < 8; row++) {
self.squares[row] = [];
for (var col = 0; col < 8; col++) {
var isLight = (row + col) % 2 === 0;
var assetId = isLight ? 'squareLight' : 'squareDark';
var square = LK.getAsset(assetId, {
anchorX: 0,
anchorY: 0
});
square.x = BOARD_START_X + col * SQUARE_SIZE;
square.y = BOARD_START_Y + row * SQUARE_SIZE;
square.boardX = col;
square.boardY = row;
self.addChild(square);
self.squares[row][col] = square;
}
}
};
self.setupPieces = function () {
var initialSetup = [['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'], [null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'], ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook']];
self.pieces = [];
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var piece = initialSetup[row][col];
if (piece !== null) {
var color = row < 2 ? 'black' : 'white';
var chessPiece = self.addChild(new ChessPiece());
chessPiece.init(piece, color, col, row);
chessPiece.updatePosition(col, row);
self.pieces.push(chessPiece);
boardState[row][col] = {
piece: piece,
color: color,
hasMoved: false
};
}
}
}
};
self.clearHighlights = function () {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var square = self.squares[row][col];
var isLight = (row + col) % 2 === 0;
var newAssetId = isLight ? 'squareLight' : 'squareDark';
// Remove only legal move indicators, not board pieces
for (var i = square.children.length - 1; i >= 0; i--) {
var child = square.children[i];
if (child.name === 'legalMoveIndicator') {
square.removeChild(child);
}
}
square.tint = 0xffffff;
}
}
// Remove capturable indicators from all pieces
for (var i = 0; i < self.pieces.length; i++) {
//{z_new}
var piece = self.pieces[i];
for (var j = piece.children.length - 1; j >= 0; j--) {
var child = piece.children[j];
if (child.name === 'captureableIndicator') {
piece.removeChild(child);
}
}
}
};
self.getPieceAt = function (boardX, boardY) {
for (var i = 0; i < self.pieces.length; i++) {
if (self.pieces[i].boardX === boardX && self.pieces[i].boardY === boardY) {
return self.pieces[i];
}
}
return null;
};
self.removePiece = function (piece) {
for (var i = 0; i < self.pieces.length; i++) {
if (self.pieces[i] === piece) {
var explosionX = piece.x;
var explosionY = piece.y;
for (var e = 0; e < 4; e++) {
var explosion = game.addChild(LK.getAsset('captureableIndicator', {
anchorX: 0.5,
anchorY: 0.5
}));
explosion.x = explosionX;
explosion.y = explosionY;
explosion.alpha = 0.8;
var angle = e / 4 * Math.PI * 2;
var endX = explosionX + Math.cos(angle) * 100;
var endY = explosionY + Math.sin(angle) * 100;
tween(explosion, {
x: endX,
y: endY,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
}
tween(piece, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.removeChild(piece);
self.pieces.splice(self.pieces.indexOf(piece), 1);
}
});
return;
}
}
};
self.movePiece = function (fromX, fromY, toX, toY) {
var piece = self.getPieceAt(fromX, fromY);
if (!piece) return false;
var targetPiece = self.getPieceAt(toX, toY);
if (targetPiece && targetPiece.color === piece.color) return false;
if (targetPiece) {
if (piece.color === 'white') {
self.capturedBlack.push(targetPiece);
} else {
self.capturedWhite.push(targetPiece);
}
self.removePiece(targetPiece);
}
piece.boardX = toX; //{N_new}
piece.boardY = toY; //{O_new}
var finalX = BOARD_START_X + toX * SQUARE_SIZE + SQUARE_SIZE / 2;
var finalY = BOARD_START_Y + toY * SQUARE_SIZE + SQUARE_SIZE / 2;
tween(piece, {
x: finalX,
y: finalY
}, {
duration: 300,
easing: tween.cubicOut
});
piece.hasMoved = true;
var finalPiece = piece.piece;
// Check for pawn promotion
if (piece.piece === 'pawn' && (piece.color === 'white' && toY === 0 || piece.color === 'black' && toY === 7)) {
finalPiece = 'queen';
piece.piece = 'queen';
piece.assetId = 'queen' + (piece.color === 'white' ? 'White' : 'Black');
// Update the visual representation
for (var i = piece.children.length - 1; i >= 0; i--) {
piece.removeChild(piece.children[i]);
} //{promo_clear}
var newGraphics = piece.attachAsset(piece.assetId, {
anchorX: 0.5,
anchorY: 0.5
}); //{promo_asset}
} //{promo_end}
// Check for pawn promotion
var promotedPiece = piece.piece;
if (piece.piece === 'pawn' && (piece.color === 'white' && toY === 0 || piece.color === 'black' && toY === 7)) {
promotedPiece = 'queen';
piece.piece = 'queen';
piece.assetId = 'queen' + (piece.color === 'white' ? 'White' : 'Black');
// Clear old piece graphics and add new queen graphics
for (var i = piece.children.length - 1; i >= 0; i--) {
piece.removeChild(piece.children[i]);
}
var newGraphics = piece.attachAsset(piece.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
piece.hasMoved = true;
// Animate promotion with rotation
piece.rotation = 0;
tween(piece, {
rotation: Math.PI * 2
}, {
duration: 600,
easing: tween.elasticOut
});
}
boardState[toY][toX] = _defineProperty(_defineProperty({
piece: finalPiece
}, "piece", promotedPiece), "color", piece.color);
boardState[fromY][fromX] = null;
self.moveHistory.push({
from: {
x: fromX,
y: fromY
},
to: {
x: toX,
y: toY
},
color: piece.color,
captured: targetPiece ? targetPiece.piece : null
});
return true;
};
self.resetBoard = function () {
for (var i = self.pieces.length - 1; i >= 0; i--) {
self.removeChild(self.pieces[i]);
}
self.pieces = [];
self.moveHistory = [];
self.capturedWhite = [];
self.capturedBlack = [];
boardState = Array(8).fill(null).map(function () {
return Array(8).fill(null);
});
self.setupPieces();
};
return self;
});
var ChessPiece = Container.expand(function () {
var self = Container.call(this);
self.piece = null;
self.color = null;
self.boardX = 0;
self.boardY = 0;
self.assetId = null;
self.hasMoved = false;
self.init = function (piece, color, boardX, boardY) {
self.piece = piece;
self.color = color;
self.boardX = boardX;
self.boardY = boardY;
self.assetId = piece + (color === 'white' ? 'White' : 'Black');
var graphics = self.attachAsset(self.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Position piece above board for drop animation
self.x = BOARD_START_X + boardX * SQUARE_SIZE + SQUARE_SIZE / 2;
self.y = BOARD_START_Y - 300;
// Animate piece falling into position
var finalY = BOARD_START_Y + boardY * SQUARE_SIZE + SQUARE_SIZE / 2;
tween(self, {
y: finalY
}, {
duration: 600,
easing: tween.bounceOut
});
return self;
};
self.updatePosition = function (boardX, boardY) {
self.boardX = boardX;
self.boardY = boardY;
self.x = BOARD_START_X + boardX * SQUARE_SIZE + SQUARE_SIZE / 2;
self.y = BOARD_START_Y + boardY * SQUARE_SIZE + SQUARE_SIZE / 2;
};
self.down = function (x, y, obj) {
// Handled by game.down instead to avoid conflicts
};
return self;
});
var TrailParticle = Container.expand(function () {
var self = Container.call(this);
self.init = function (x, y) {
var particle = self.attachAsset('legalMoveIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.alpha = 0.6;
return self;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d3436
});
/****
* Game Code
****/
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
var SQUARE_SIZE = 128;
var BOARD_START_X = (2048 - 8 * SQUARE_SIZE) / 2;
var BOARD_START_Y = (2732 - 8 * SQUARE_SIZE) / 2 - 100;
var gameMode = 'ai'; // 'ai' or 'multiplayer'
var aiDifficulty = 1; // 0 = easy, 1 = medium, 2 = hard
var currentPlayer = 'white';
var selectedPiece = null;
var gameOver = false;
var gameResult = null; // 'checkmate', 'stalemate', 'draw', 'resignation'
var board = null;
var boardState = Array(8).fill(null).map(function () {
return Array(8).fill(null);
});
var trailParticles = [];
var statusText = new Text2('White to move', {
size: 60,
fill: '#ffffff'
});
statusText.anchor.set(0.5, 0);
statusText.x = 1024;
statusText.y = BOARD_START_Y - 120;
game.addChild(statusText);
var eloText = new Text2('ELO: 1000', {
size: 40,
fill: '#ffff00' //{ELO_1}
}); //{ELO_2}
eloText.anchor.set(1, 0);
eloText.x = 2048 - 50;
eloText.y = 50;
game.addChild(eloText);
var moveCountText = new Text2('Moves: 0', {
size: 40,
fill: '#ffffff'
});
moveCountText.anchor.set(0, 0);
moveCountText.x = 50;
moveCountText.y = 50;
game.addChild(moveCountText);
function initializeGame() {
if (board) {
game.removeChild(board);
}
boardState = Array(8).fill(null).map(function () {
return Array(8).fill(null);
});
currentPlayer = 'white';
selectedPiece = null;
gameOver = false;
gameResult = null;
if (storage.playerElo === undefined) {
storage.playerElo = 1000;
}
board = game.addChild(new ChessBoard());
board.init();
statusText.setText('White to move');
moveCountText.setText('Moves: 0');
eloText.setText('ELO: ' + storage.playerElo);
}
function getPieceValue(piece) {
var values = {
'pawn': 1,
'knight': 3,
'bishop': 3,
'rook': 5,
'queen': 9,
'king': 999
};
return values[piece] || 0;
}
function isSquareAttacked(boardX, boardY, byColor) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.color === byColor) {
var legalMoves = calculateLegalMoves(col, row);
for (var i = 0; i < legalMoves.length; i++) {
if (legalMoves[i].x === boardX && legalMoves[i].y === boardY) {
return true;
}
}
}
}
}
return false;
}
function calculateLegalMoves(fromX, fromY) {
var moves = [];
var state = boardState[fromY][fromX];
if (!state) return moves;
var piece = state.piece;
var color = state.color;
var possibleMoves = [];
if (piece === 'pawn') {
var direction = color === 'white' ? -1 : 1;
var startRow = color === 'white' ? 6 : 1;
var forwardY = fromY + direction;
if (forwardY >= 0 && forwardY < 8 && !boardState[forwardY][fromX]) {
possibleMoves.push({
x: fromX,
y: forwardY
});
if (fromY === startRow && !boardState[fromY + 2 * direction][fromX]) {
possibleMoves.push({
x: fromX,
y: fromY + 2 * direction
});
}
}
for (var dx = -1; dx <= 1; dx += 2) {
var captureX = fromX + dx;
var captureY = fromY + direction;
if (captureX >= 0 && captureX < 8 && captureY >= 0 && captureY < 8) {
var target = boardState[captureY][captureX];
if (target && target.color !== color) {
possibleMoves.push({
x: captureX,
y: captureY
});
}
}
}
} else if (piece === 'rook' || piece === 'queen') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
for (var d = 0; d < directions.length; d++) {
for (var i = 1; i < 8; i++) {
var newX = fromX + directions[d][0] * i;
var newY = fromY + directions[d][1] * i;
if (newX < 0 || newX >= 8 || newY < 0 || newY >= 8) break;
var target = boardState[newY][newX];
if (!target) {
possibleMoves.push({
x: newX,
y: newY
});
} else {
if (target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
break;
}
}
}
}
if (piece === 'bishop' || piece === 'queen') {
var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
for (var i = 1; i < 8; i++) {
var newX = fromX + directions[d][0] * i;
var newY = fromY + directions[d][1] * i;
if (newX < 0 || newX >= 8 || newY < 0 || newY >= 8) break;
var target = boardState[newY][newX];
if (!target) {
possibleMoves.push({
x: newX,
y: newY
});
} else {
if (target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
break;
}
}
}
}
if (piece === 'knight') {
var knightMoves = [[2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2]];
for (var i = 0; i < knightMoves.length; i++) {
var newX = fromX + knightMoves[i][0];
var newY = fromY + knightMoves[i][1];
if (newX >= 0 && newX < 8 && newY >= 0 && newY < 8) {
var target = boardState[newY][newX];
if (!target || target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
}
}
}
if (piece === 'king') {
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
if (dx === 0 && dy === 0) continue;
var newX = fromX + dx;
var newY = fromY + dy;
if (newX >= 0 && newX < 8 && newY >= 0 && newY < 8) {
var target = boardState[newY][newX];
if (!target || target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
}
}
}
if (!state.hasMoved) {
if (fromX === 4 && (fromY === 0 || fromY === 7)) {
var rook = board.getPieceAt(7, fromY);
if (rook && rook.piece === 'rook' && !rook.hasMoved && !boardState[fromY][5] && !boardState[fromY][6]) {
possibleMoves.push({
x: 6,
y: fromY
});
}
rook = board.getPieceAt(0, fromY);
if (rook && rook.piece === 'rook' && !rook.hasMoved && !boardState[fromY][1] && !boardState[fromY][2] && !boardState[fromY][3]) {
possibleMoves.push({
x: 2,
y: fromY
});
}
}
}
}
var opponentColor = color === 'white' ? 'black' : 'white';
for (var i = possibleMoves.length - 1; i >= 0; i--) {
var move = possibleMoves[i];
var originalState = boardState[move.y][move.x];
boardState[move.y][move.x] = state;
boardState[fromY][fromX] = null;
var kingPos = findKing(color);
if (!kingPos) {
//{3s_new_fixed}
boardState[fromY][fromX] = state;
boardState[move.y][move.x] = originalState;
continue;
}
var isInCheck = false;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var checkState = boardState[row][col];
if (checkState && checkState.color === opponentColor) {
var dx = Math.abs(col - kingPos.x);
var dy = Math.abs(row - kingPos.y);
var canAttack = false;
if (checkState.piece === 'pawn') {
var direction = checkState.color === 'white' ? -1 : 1;
canAttack = dy === 1 && dx === 1 && row + direction === kingPos.y;
} else if (checkState.piece === 'knight') {
canAttack = dx === 2 && dy === 1 || dx === 1 && dy === 2;
} else if (checkState.piece === 'king') {
canAttack = dx <= 1 && dy <= 1;
} else if (checkState.piece === 'rook' || checkState.piece === 'queen') {
if (row === kingPos.y) {
var minCol = Math.min(col, kingPos.x);
var maxCol = Math.max(col, kingPos.x);
canAttack = true;
for (var c = minCol + 1; c < maxCol; c++) {
if (boardState[row][c]) canAttack = false;
}
} else if (col === kingPos.x) {
var minRow = Math.min(row, kingPos.y);
var maxRow = Math.max(row, kingPos.y);
canAttack = true;
for (var r = minRow + 1; r < maxRow; r++) {
if (boardState[r][col]) canAttack = false;
}
}
}
if (checkState.piece === 'bishop' || checkState.piece === 'queen') {
if (dx === dy && dx > 0) {
canAttack = true;
var stepX = col < kingPos.x ? 1 : -1;
var stepY = row < kingPos.y ? 1 : -1;
var checkCol = col + stepX;
var checkRow = row + stepY;
while (checkCol !== kingPos.x || checkRow !== kingPos.y) {
if (boardState[checkRow][checkCol]) canAttack = false;
checkCol += stepX;
checkRow += stepY;
}
}
}
if (canAttack) {
isInCheck = true;
break;
}
}
}
if (isInCheck) break;
}
boardState[fromY][fromX] = state;
boardState[move.y][move.x] = originalState;
if (!isInCheck) {
moves.push(move);
}
}
return moves;
}
function findKing(color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.piece === 'king' && state.color === color) {
return {
x: col,
y: row
};
}
}
}
return null;
}
function isInCheck(color) {
var kingPos = findKing(color);
if (!kingPos) return false; //{3F_new}
var opponentColor = color === 'white' ? 'black' : 'white';
return isSquareAttacked(kingPos.x, kingPos.y, opponentColor);
}
function hasLegalMoves(color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.color === color) {
var legalMoves = calculateLegalMoves(col, row);
if (legalMoves.length > 0) {
return true;
}
}
}
}
return false;
}
function highlightLegalMoves(piece) {
board.clearHighlights();
// Show red indicator behind black pieces to show they can be captured
if (piece.color === 'black') {
var captureIndicator = LK.getAsset('captureableIndicator', {
anchorX: 0.5,
//{4j_new}
anchorY: 0.5 //{4k_new}
}); //{4l_new}
captureIndicator.name = 'captureableIndicator';
captureIndicator.x = 0;
captureIndicator.y = 0;
piece.addChild(captureIndicator);
}
var legalMoves = calculateLegalMoves(piece.boardX, piece.boardY);
for (var i = 0; i < legalMoves.length; i++) {
var move = legalMoves[i];
var square = board.squares[move.y][move.x];
var targetPiece = board.getPieceAt(move.x, move.y);
var isCapture = targetPiece !== null;
var assetId = isCapture ? 'captureableIndicator' : 'legalMoveIndicator';
var indicator = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
indicator.name = 'legalMoveIndicator';
indicator.x = SQUARE_SIZE / 2;
indicator.y = SQUARE_SIZE / 2;
square.addChild(indicator);
}
}
function makeAIMove() {
var possibleMoves = [];
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.color === 'black') {
var legalMoves = calculateLegalMoves(col, row);
for (var i = 0; i < legalMoves.length; i++) {
possibleMoves.push({
fromX: col,
fromY: row,
toX: legalMoves[i].x,
toY: legalMoves[i].y
});
}
}
}
}
if (possibleMoves.length === 0) return false;
var move = null;
if (aiDifficulty === 0) {
move = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
} else if (aiDifficulty === 1) {
var bestScore = -999999;
for (var i = 0; i < possibleMoves.length; i++) {
var m = possibleMoves[i];
var targetState = boardState[m.toY][m.toX];
var score = targetState ? getPieceValue(targetState.piece) : 0;
if (Math.random() < 0.4) {
score += Math.random() * 10;
}
if (score > bestScore) {
bestScore = score;
move = m;
}
}
} else {
var bestScore = -999999;
for (var i = 0; i < possibleMoves.length; i++) {
var m = possibleMoves[i];
var targetState = boardState[m.toY][m.toX];
var score = targetState ? getPieceValue(targetState.piece) : 0;
var piece = boardState[m.fromY][m.fromX];
var attackers = 0;
var defenders = 0;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state) {
var attacks = calculateLegalMoves(col, row);
for (var j = 0; j < attacks.length; j++) {
if (attacks[j].x === m.toX && attacks[j].y === m.toY) {
if (state.color === 'black') defenders++;else attackers++;
}
}
}
}
}
if (defenders > attackers) {
score = -getPieceValue(piece.piece);
}
if (score > bestScore) {
bestScore = score;
move = m;
}
}
}
if (move) {
board.movePiece(move.fromX, move.fromY, move.toX, move.toY);
return true;
}
return false;
}
function switchPlayer() {
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
board.clearHighlights();
statusText.setText(currentPlayer === 'white' ? 'White to move' : 'Black to move');
if (isInCheck(currentPlayer)) {
statusText.setText((currentPlayer === 'white' ? 'White' : 'Black') + ' in check');
LK.getSound('checkSound').play();
var kingPos = findKing(currentPlayer);
if (kingPos) {
var kingPiece = board.getPieceAt(kingPos.x, kingPos.y);
if (kingPiece) {
tween(kingPiece, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.linear
});
tween(kingPiece, {
tint: 0xffffff
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(kingPiece, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.linear
});
tween(kingPiece, {
tint: 0xffffff
}, {
duration: 100,
easing: tween.linear
});
}
});
}
}
}
if (!hasLegalMoves(currentPlayer)) {
if (isInCheck(currentPlayer)) {
gameOver = true;
gameResult = 'checkmate';
statusText.setText((currentPlayer === 'white' ? 'Black' : 'White') + ' wins by checkmate');
var winner = currentPlayer === 'white' ? 'black' : 'white';
var eloDelta = 32;
if (winner === 'white') {
storage.playerElo = (storage.playerElo || 1000) + eloDelta;
} else {
storage.playerElo = Math.max(0, (storage.playerElo || 1000) - eloDelta);
}
eloText.setText('ELO: ' + storage.playerElo);
var flashOverlay = new Container();
flashOverlay.addChild(LK.getAsset('squareCheck', {
anchorX: 0,
anchorY: 0,
scaleX: 16,
scaleY: 21.375
}));
flashOverlay.children[0].x = 0;
flashOverlay.children[0].y = 0;
flashOverlay.alpha = 0;
game.addChild(flashOverlay);
tween(flashOverlay, {
alpha: 0.4
}, {
duration: 200,
easing: tween.easeOut
});
tween(flashOverlay, {
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(flashOverlay);
}
});
LK.showGameOver();
} else {
gameOver = true;
gameResult = 'stalemate';
statusText.setText('Draw - Stalemate');
eloText.setText('ELO: ' + storage.playerElo);
LK.showGameOver();
}
return;
}
if (gameMode === 'ai' && currentPlayer === 'black' && !gameOver) {
LK.setTimeout(function () {
if (!gameOver && currentPlayer === 'black') {
makeAIMove();
switchPlayer();
}
}, 500);
}
}
game.move = function (x, y, obj) {
if (gameOver || !selectedPiece) return;
};
game.down = function (x, y, obj) {
if (gameOver) return;
var boardX = Math.floor((x - BOARD_START_X) / SQUARE_SIZE);
var boardY = Math.floor((y - BOARD_START_Y) / SQUARE_SIZE);
if (boardX < 0 || boardX >= 8 || boardY < 0 || boardY >= 8) return;
if (selectedPiece) {
var legalMoves = calculateLegalMoves(selectedPiece.boardX, selectedPiece.boardY);
var isLegalMove = false;
for (var i = 0; i < legalMoves.length; i++) {
if (legalMoves[i].x === boardX && legalMoves[i].y === boardY) {
isLegalMove = true;
break;
}
}
if (isLegalMove) {
var targetPiece = board.getPieceAt(boardX, boardY);
var isCaptured = targetPiece !== null;
board.movePiece(selectedPiece.boardX, selectedPiece.boardY, boardX, boardY);
if (isCaptured) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
moveCountText.setText('Moves: ' + board.moveHistory.length);
board.clearHighlights();
selectedPiece = null;
switchPlayer();
} else {
var newPiece = board.getPieceAt(boardX, boardY);
if (newPiece && newPiece.color === currentPlayer) {
selectedPiece = newPiece;
board.clearHighlights();
highlightLegalMoves(newPiece);
} else {
selectedPiece = null;
board.clearHighlights();
}
}
} else {
var piece = board.getPieceAt(boardX, boardY);
if (piece && piece.color === currentPlayer) {
selectedPiece = piece;
highlightLegalMoves(piece);
}
}
};
game.up = function (x, y, obj) {};
game.update = function () {};
initializeGame();
LK.playMusic('bgmusic', {
loop: true
}); /****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ChessBoard = Container.expand(function () {
var self = Container.call(this);
self.squares = [];
self.pieces = [];
self.moveHistory = [];
self.capturedWhite = [];
self.capturedBlack = [];
self.init = function () {
self.createBoard();
self.setupPieces();
return self;
};
self.createBoard = function () {
for (var row = 0; row < 8; row++) {
self.squares[row] = [];
for (var col = 0; col < 8; col++) {
var isLight = (row + col) % 2 === 0;
var assetId = isLight ? 'squareLight' : 'squareDark';
var square = LK.getAsset(assetId, {
anchorX: 0,
anchorY: 0
});
square.x = BOARD_START_X + col * SQUARE_SIZE;
square.y = BOARD_START_Y + row * SQUARE_SIZE;
square.boardX = col;
square.boardY = row;
self.addChild(square);
self.squares[row][col] = square;
}
}
};
self.setupPieces = function () {
var initialSetup = [['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'], [null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null], ['pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn', 'pawn'], ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook']];
self.pieces = [];
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var piece = initialSetup[row][col];
if (piece !== null) {
var color = row < 2 ? 'black' : 'white';
var chessPiece = self.addChild(new ChessPiece());
chessPiece.init(piece, color, col, row);
chessPiece.updatePosition(col, row);
self.pieces.push(chessPiece);
boardState[row][col] = {
piece: piece,
color: color,
hasMoved: false
};
}
}
}
};
self.clearHighlights = function () {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var square = self.squares[row][col];
var isLight = (row + col) % 2 === 0;
var newAssetId = isLight ? 'squareLight' : 'squareDark';
// Remove only legal move indicators, not board pieces
for (var i = square.children.length - 1; i >= 0; i--) {
var child = square.children[i];
if (child.name === 'legalMoveIndicator') {
square.removeChild(child);
}
}
square.tint = 0xffffff;
}
}
// Remove capturable indicators from all pieces
for (var i = 0; i < self.pieces.length; i++) {
//{z_new}
var piece = self.pieces[i];
for (var j = piece.children.length - 1; j >= 0; j--) {
var child = piece.children[j];
if (child.name === 'captureableIndicator') {
piece.removeChild(child);
}
}
}
};
self.getPieceAt = function (boardX, boardY) {
for (var i = 0; i < self.pieces.length; i++) {
if (self.pieces[i].boardX === boardX && self.pieces[i].boardY === boardY) {
return self.pieces[i];
}
}
return null;
};
self.removePiece = function (piece) {
for (var i = 0; i < self.pieces.length; i++) {
if (self.pieces[i] === piece) {
var explosionX = piece.x;
var explosionY = piece.y;
for (var e = 0; e < 4; e++) {
var explosion = game.addChild(LK.getAsset('captureableIndicator', {
anchorX: 0.5,
anchorY: 0.5
}));
explosion.x = explosionX;
explosion.y = explosionY;
explosion.alpha = 0.8;
var angle = e / 4 * Math.PI * 2;
var endX = explosionX + Math.cos(angle) * 100;
var endY = explosionY + Math.sin(angle) * 100;
tween(explosion, {
x: endX,
y: endY,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
}
tween(piece, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.removeChild(piece);
self.pieces.splice(self.pieces.indexOf(piece), 1);
}
});
return;
}
}
};
self.movePiece = function (fromX, fromY, toX, toY) {
var piece = self.getPieceAt(fromX, fromY);
if (!piece) return false;
var targetPiece = self.getPieceAt(toX, toY);
if (targetPiece && targetPiece.color === piece.color) return false;
if (targetPiece) {
if (piece.color === 'white') {
self.capturedBlack.push(targetPiece);
} else {
self.capturedWhite.push(targetPiece);
}
self.removePiece(targetPiece);
}
piece.boardX = toX; //{N_new}
piece.boardY = toY; //{O_new}
var finalX = BOARD_START_X + toX * SQUARE_SIZE + SQUARE_SIZE / 2;
var finalY = BOARD_START_Y + toY * SQUARE_SIZE + SQUARE_SIZE / 2;
tween(piece, {
x: finalX,
y: finalY
}, {
duration: 300,
easing: tween.cubicOut
});
piece.hasMoved = true;
var finalPiece = piece.piece;
// Check for pawn promotion
if (piece.piece === 'pawn' && (piece.color === 'white' && toY === 0 || piece.color === 'black' && toY === 7)) {
finalPiece = 'queen';
piece.piece = 'queen';
piece.assetId = 'queen' + (piece.color === 'white' ? 'White' : 'Black');
// Update the visual representation
for (var i = piece.children.length - 1; i >= 0; i--) {
piece.removeChild(piece.children[i]);
} //{promo_clear}
var newGraphics = piece.attachAsset(piece.assetId, {
anchorX: 0.5,
anchorY: 0.5
}); //{promo_asset}
} //{promo_end}
// Check for pawn promotion
var promotedPiece = piece.piece;
if (piece.piece === 'pawn' && (piece.color === 'white' && toY === 0 || piece.color === 'black' && toY === 7)) {
promotedPiece = 'queen';
piece.piece = 'queen';
piece.assetId = 'queen' + (piece.color === 'white' ? 'White' : 'Black');
// Clear old piece graphics and add new queen graphics
for (var i = piece.children.length - 1; i >= 0; i--) {
piece.removeChild(piece.children[i]);
}
var newGraphics = piece.attachAsset(piece.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
piece.hasMoved = true;
// Animate promotion with rotation
piece.rotation = 0;
tween(piece, {
rotation: Math.PI * 2
}, {
duration: 600,
easing: tween.elasticOut
});
}
boardState[toY][toX] = _defineProperty(_defineProperty({
piece: finalPiece
}, "piece", promotedPiece), "color", piece.color);
boardState[fromY][fromX] = null;
self.moveHistory.push({
from: {
x: fromX,
y: fromY
},
to: {
x: toX,
y: toY
},
color: piece.color,
captured: targetPiece ? targetPiece.piece : null
});
return true;
};
self.resetBoard = function () {
for (var i = self.pieces.length - 1; i >= 0; i--) {
self.removeChild(self.pieces[i]);
}
self.pieces = [];
self.moveHistory = [];
self.capturedWhite = [];
self.capturedBlack = [];
boardState = Array(8).fill(null).map(function () {
return Array(8).fill(null);
});
self.setupPieces();
};
return self;
});
var ChessPiece = Container.expand(function () {
var self = Container.call(this);
self.piece = null;
self.color = null;
self.boardX = 0;
self.boardY = 0;
self.assetId = null;
self.hasMoved = false;
self.init = function (piece, color, boardX, boardY) {
self.piece = piece;
self.color = color;
self.boardX = boardX;
self.boardY = boardY;
self.assetId = piece + (color === 'white' ? 'White' : 'Black');
var graphics = self.attachAsset(self.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Position piece above board for drop animation
self.x = BOARD_START_X + boardX * SQUARE_SIZE + SQUARE_SIZE / 2;
self.y = BOARD_START_Y - 300;
// Animate piece falling into position
var finalY = BOARD_START_Y + boardY * SQUARE_SIZE + SQUARE_SIZE / 2;
tween(self, {
y: finalY
}, {
duration: 600,
easing: tween.bounceOut
});
return self;
};
self.updatePosition = function (boardX, boardY) {
self.boardX = boardX;
self.boardY = boardY;
self.x = BOARD_START_X + boardX * SQUARE_SIZE + SQUARE_SIZE / 2;
self.y = BOARD_START_Y + boardY * SQUARE_SIZE + SQUARE_SIZE / 2;
};
self.down = function (x, y, obj) {
// Handled by game.down instead to avoid conflicts
};
return self;
});
var TrailParticle = Container.expand(function () {
var self = Container.call(this);
self.init = function (x, y) {
var particle = self.attachAsset('legalMoveIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.alpha = 0.6;
return self;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d3436
});
/****
* Game Code
****/
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
var SQUARE_SIZE = 128;
var BOARD_START_X = (2048 - 8 * SQUARE_SIZE) / 2;
var BOARD_START_Y = (2732 - 8 * SQUARE_SIZE) / 2 - 100;
var gameMode = 'ai'; // 'ai' or 'multiplayer'
var aiDifficulty = 1; // 0 = easy, 1 = medium, 2 = hard
var currentPlayer = 'white';
var selectedPiece = null;
var gameOver = false;
var gameResult = null; // 'checkmate', 'stalemate', 'draw', 'resignation'
var board = null;
var boardState = Array(8).fill(null).map(function () {
return Array(8).fill(null);
});
var trailParticles = [];
var statusText = new Text2('White to move', {
size: 60,
fill: '#ffffff'
});
statusText.anchor.set(0.5, 0);
statusText.x = 1024;
statusText.y = BOARD_START_Y - 120;
game.addChild(statusText);
var eloText = new Text2('ELO: 1000', {
size: 40,
fill: '#ffff00' //{ELO_1}
}); //{ELO_2}
eloText.anchor.set(1, 0);
eloText.x = 2048 - 50;
eloText.y = 50;
game.addChild(eloText);
var moveCountText = new Text2('Moves: 0', {
size: 40,
fill: '#ffffff'
});
moveCountText.anchor.set(0, 0);
moveCountText.x = 50;
moveCountText.y = 50;
game.addChild(moveCountText);
function initializeGame() {
if (board) {
game.removeChild(board);
}
boardState = Array(8).fill(null).map(function () {
return Array(8).fill(null);
});
currentPlayer = 'white';
selectedPiece = null;
gameOver = false;
gameResult = null;
if (storage.playerElo === undefined) {
storage.playerElo = 1000;
}
board = game.addChild(new ChessBoard());
board.init();
statusText.setText('White to move');
moveCountText.setText('Moves: 0');
eloText.setText('ELO: ' + storage.playerElo);
}
function getPieceValue(piece) {
var values = {
'pawn': 1,
'knight': 3,
'bishop': 3,
'rook': 5,
'queen': 9,
'king': 999
};
return values[piece] || 0;
}
function isSquareAttacked(boardX, boardY, byColor) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.color === byColor) {
var legalMoves = calculateLegalMoves(col, row);
for (var i = 0; i < legalMoves.length; i++) {
if (legalMoves[i].x === boardX && legalMoves[i].y === boardY) {
return true;
}
}
}
}
}
return false;
}
function calculateLegalMoves(fromX, fromY) {
var moves = [];
var state = boardState[fromY][fromX];
if (!state) return moves;
var piece = state.piece;
var color = state.color;
var possibleMoves = [];
if (piece === 'pawn') {
var direction = color === 'white' ? -1 : 1;
var startRow = color === 'white' ? 6 : 1;
var forwardY = fromY + direction;
if (forwardY >= 0 && forwardY < 8 && !boardState[forwardY][fromX]) {
possibleMoves.push({
x: fromX,
y: forwardY
});
if (fromY === startRow && !boardState[fromY + 2 * direction][fromX]) {
possibleMoves.push({
x: fromX,
y: fromY + 2 * direction
});
}
}
for (var dx = -1; dx <= 1; dx += 2) {
var captureX = fromX + dx;
var captureY = fromY + direction;
if (captureX >= 0 && captureX < 8 && captureY >= 0 && captureY < 8) {
var target = boardState[captureY][captureX];
if (target && target.color !== color) {
possibleMoves.push({
x: captureX,
y: captureY
});
}
}
}
} else if (piece === 'rook' || piece === 'queen') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
for (var d = 0; d < directions.length; d++) {
for (var i = 1; i < 8; i++) {
var newX = fromX + directions[d][0] * i;
var newY = fromY + directions[d][1] * i;
if (newX < 0 || newX >= 8 || newY < 0 || newY >= 8) break;
var target = boardState[newY][newX];
if (!target) {
possibleMoves.push({
x: newX,
y: newY
});
} else {
if (target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
break;
}
}
}
}
if (piece === 'bishop' || piece === 'queen') {
var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
for (var i = 1; i < 8; i++) {
var newX = fromX + directions[d][0] * i;
var newY = fromY + directions[d][1] * i;
if (newX < 0 || newX >= 8 || newY < 0 || newY >= 8) break;
var target = boardState[newY][newX];
if (!target) {
possibleMoves.push({
x: newX,
y: newY
});
} else {
if (target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
break;
}
}
}
}
if (piece === 'knight') {
var knightMoves = [[2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2]];
for (var i = 0; i < knightMoves.length; i++) {
var newX = fromX + knightMoves[i][0];
var newY = fromY + knightMoves[i][1];
if (newX >= 0 && newX < 8 && newY >= 0 && newY < 8) {
var target = boardState[newY][newX];
if (!target || target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
}
}
}
if (piece === 'king') {
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
if (dx === 0 && dy === 0) continue;
var newX = fromX + dx;
var newY = fromY + dy;
if (newX >= 0 && newX < 8 && newY >= 0 && newY < 8) {
var target = boardState[newY][newX];
if (!target || target.color !== color) {
possibleMoves.push({
x: newX,
y: newY
});
}
}
}
}
if (!state.hasMoved) {
if (fromX === 4 && (fromY === 0 || fromY === 7)) {
var rook = board.getPieceAt(7, fromY);
if (rook && rook.piece === 'rook' && !rook.hasMoved && !boardState[fromY][5] && !boardState[fromY][6]) {
possibleMoves.push({
x: 6,
y: fromY
});
}
rook = board.getPieceAt(0, fromY);
if (rook && rook.piece === 'rook' && !rook.hasMoved && !boardState[fromY][1] && !boardState[fromY][2] && !boardState[fromY][3]) {
possibleMoves.push({
x: 2,
y: fromY
});
}
}
}
}
var opponentColor = color === 'white' ? 'black' : 'white';
for (var i = possibleMoves.length - 1; i >= 0; i--) {
var move = possibleMoves[i];
var originalState = boardState[move.y][move.x];
boardState[move.y][move.x] = state;
boardState[fromY][fromX] = null;
var kingPos = findKing(color);
if (!kingPos) {
//{3s_new_fixed}
boardState[fromY][fromX] = state;
boardState[move.y][move.x] = originalState;
continue;
}
var isInCheck = false;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var checkState = boardState[row][col];
if (checkState && checkState.color === opponentColor) {
var dx = Math.abs(col - kingPos.x);
var dy = Math.abs(row - kingPos.y);
var canAttack = false;
if (checkState.piece === 'pawn') {
var direction = checkState.color === 'white' ? -1 : 1;
canAttack = dy === 1 && dx === 1 && row + direction === kingPos.y;
} else if (checkState.piece === 'knight') {
canAttack = dx === 2 && dy === 1 || dx === 1 && dy === 2;
} else if (checkState.piece === 'king') {
canAttack = dx <= 1 && dy <= 1;
} else if (checkState.piece === 'rook' || checkState.piece === 'queen') {
if (row === kingPos.y) {
var minCol = Math.min(col, kingPos.x);
var maxCol = Math.max(col, kingPos.x);
canAttack = true;
for (var c = minCol + 1; c < maxCol; c++) {
if (boardState[row][c]) canAttack = false;
}
} else if (col === kingPos.x) {
var minRow = Math.min(row, kingPos.y);
var maxRow = Math.max(row, kingPos.y);
canAttack = true;
for (var r = minRow + 1; r < maxRow; r++) {
if (boardState[r][col]) canAttack = false;
}
}
}
if (checkState.piece === 'bishop' || checkState.piece === 'queen') {
if (dx === dy && dx > 0) {
canAttack = true;
var stepX = col < kingPos.x ? 1 : -1;
var stepY = row < kingPos.y ? 1 : -1;
var checkCol = col + stepX;
var checkRow = row + stepY;
while (checkCol !== kingPos.x || checkRow !== kingPos.y) {
if (boardState[checkRow][checkCol]) canAttack = false;
checkCol += stepX;
checkRow += stepY;
}
}
}
if (canAttack) {
isInCheck = true;
break;
}
}
}
if (isInCheck) break;
}
boardState[fromY][fromX] = state;
boardState[move.y][move.x] = originalState;
if (!isInCheck) {
moves.push(move);
}
}
return moves;
}
function findKing(color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.piece === 'king' && state.color === color) {
return {
x: col,
y: row
};
}
}
}
return null;
}
function isInCheck(color) {
var kingPos = findKing(color);
if (!kingPos) return false; //{3F_new}
var opponentColor = color === 'white' ? 'black' : 'white';
return isSquareAttacked(kingPos.x, kingPos.y, opponentColor);
}
function hasLegalMoves(color) {
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.color === color) {
var legalMoves = calculateLegalMoves(col, row);
if (legalMoves.length > 0) {
return true;
}
}
}
}
return false;
}
function highlightLegalMoves(piece) {
board.clearHighlights();
// Show red indicator behind black pieces to show they can be captured
if (piece.color === 'black') {
var captureIndicator = LK.getAsset('captureableIndicator', {
anchorX: 0.5,
//{4j_new}
anchorY: 0.5 //{4k_new}
}); //{4l_new}
captureIndicator.name = 'captureableIndicator';
captureIndicator.x = 0;
captureIndicator.y = 0;
piece.addChild(captureIndicator);
}
var legalMoves = calculateLegalMoves(piece.boardX, piece.boardY);
for (var i = 0; i < legalMoves.length; i++) {
var move = legalMoves[i];
var square = board.squares[move.y][move.x];
var targetPiece = board.getPieceAt(move.x, move.y);
var isCapture = targetPiece !== null;
var assetId = isCapture ? 'captureableIndicator' : 'legalMoveIndicator';
var indicator = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
indicator.name = 'legalMoveIndicator';
indicator.x = SQUARE_SIZE / 2;
indicator.y = SQUARE_SIZE / 2;
square.addChild(indicator);
}
}
function makeAIMove() {
var possibleMoves = [];
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state && state.color === 'black') {
var legalMoves = calculateLegalMoves(col, row);
for (var i = 0; i < legalMoves.length; i++) {
possibleMoves.push({
fromX: col,
fromY: row,
toX: legalMoves[i].x,
toY: legalMoves[i].y
});
}
}
}
}
if (possibleMoves.length === 0) return false;
var move = null;
if (aiDifficulty === 0) {
move = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
} else if (aiDifficulty === 1) {
var bestScore = -999999;
for (var i = 0; i < possibleMoves.length; i++) {
var m = possibleMoves[i];
var targetState = boardState[m.toY][m.toX];
var score = targetState ? getPieceValue(targetState.piece) : 0;
if (Math.random() < 0.4) {
score += Math.random() * 10;
}
if (score > bestScore) {
bestScore = score;
move = m;
}
}
} else {
var bestScore = -999999;
for (var i = 0; i < possibleMoves.length; i++) {
var m = possibleMoves[i];
var targetState = boardState[m.toY][m.toX];
var score = targetState ? getPieceValue(targetState.piece) : 0;
var piece = boardState[m.fromY][m.fromX];
var attackers = 0;
var defenders = 0;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var state = boardState[row][col];
if (state) {
var attacks = calculateLegalMoves(col, row);
for (var j = 0; j < attacks.length; j++) {
if (attacks[j].x === m.toX && attacks[j].y === m.toY) {
if (state.color === 'black') defenders++;else attackers++;
}
}
}
}
}
if (defenders > attackers) {
score = -getPieceValue(piece.piece);
}
if (score > bestScore) {
bestScore = score;
move = m;
}
}
}
if (move) {
board.movePiece(move.fromX, move.fromY, move.toX, move.toY);
return true;
}
return false;
}
function switchPlayer() {
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
board.clearHighlights();
statusText.setText(currentPlayer === 'white' ? 'White to move' : 'Black to move');
if (isInCheck(currentPlayer)) {
statusText.setText((currentPlayer === 'white' ? 'White' : 'Black') + ' in check');
LK.getSound('checkSound').play();
var kingPos = findKing(currentPlayer);
if (kingPos) {
var kingPiece = board.getPieceAt(kingPos.x, kingPos.y);
if (kingPiece) {
tween(kingPiece, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.linear
});
tween(kingPiece, {
tint: 0xffffff
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(kingPiece, {
tint: 0xff0000
}, {
duration: 100,
easing: tween.linear
});
tween(kingPiece, {
tint: 0xffffff
}, {
duration: 100,
easing: tween.linear
});
}
});
}
}
}
if (!hasLegalMoves(currentPlayer)) {
if (isInCheck(currentPlayer)) {
gameOver = true;
gameResult = 'checkmate';
statusText.setText((currentPlayer === 'white' ? 'Black' : 'White') + ' wins by checkmate');
var winner = currentPlayer === 'white' ? 'black' : 'white';
var eloDelta = 32;
if (winner === 'white') {
storage.playerElo = (storage.playerElo || 1000) + eloDelta;
} else {
storage.playerElo = Math.max(0, (storage.playerElo || 1000) - eloDelta);
}
eloText.setText('ELO: ' + storage.playerElo);
var flashOverlay = new Container();
flashOverlay.addChild(LK.getAsset('squareCheck', {
anchorX: 0,
anchorY: 0,
scaleX: 16,
scaleY: 21.375
}));
flashOverlay.children[0].x = 0;
flashOverlay.children[0].y = 0;
flashOverlay.alpha = 0;
game.addChild(flashOverlay);
tween(flashOverlay, {
alpha: 0.4
}, {
duration: 200,
easing: tween.easeOut
});
tween(flashOverlay, {
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(flashOverlay);
}
});
LK.showGameOver();
} else {
gameOver = true;
gameResult = 'stalemate';
statusText.setText('Draw - Stalemate');
eloText.setText('ELO: ' + storage.playerElo);
LK.showGameOver();
}
return;
}
if (gameMode === 'ai' && currentPlayer === 'black' && !gameOver) {
LK.setTimeout(function () {
if (!gameOver && currentPlayer === 'black') {
makeAIMove();
switchPlayer();
}
}, 500);
}
}
game.move = function (x, y, obj) {
if (gameOver || !selectedPiece) return;
};
game.down = function (x, y, obj) {
if (gameOver) return;
var boardX = Math.floor((x - BOARD_START_X) / SQUARE_SIZE);
var boardY = Math.floor((y - BOARD_START_Y) / SQUARE_SIZE);
if (boardX < 0 || boardX >= 8 || boardY < 0 || boardY >= 8) return;
if (selectedPiece) {
var legalMoves = calculateLegalMoves(selectedPiece.boardX, selectedPiece.boardY);
var isLegalMove = false;
for (var i = 0; i < legalMoves.length; i++) {
if (legalMoves[i].x === boardX && legalMoves[i].y === boardY) {
isLegalMove = true;
break;
}
}
if (isLegalMove) {
var targetPiece = board.getPieceAt(boardX, boardY);
var isCaptured = targetPiece !== null;
board.movePiece(selectedPiece.boardX, selectedPiece.boardY, boardX, boardY);
if (isCaptured) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
moveCountText.setText('Moves: ' + board.moveHistory.length);
board.clearHighlights();
selectedPiece = null;
switchPlayer();
} else {
var newPiece = board.getPieceAt(boardX, boardY);
if (newPiece && newPiece.color === currentPlayer) {
selectedPiece = newPiece;
board.clearHighlights();
highlightLegalMoves(newPiece);
} else {
selectedPiece = null;
board.clearHighlights();
}
}
} else {
var piece = board.getPieceAt(boardX, boardY);
if (piece && piece.color === currentPlayer) {
selectedPiece = piece;
highlightLegalMoves(piece);
}
}
};
game.up = function (x, y, obj) {};
game.update = function () {};
initializeGame();
LK.playMusic('bgmusic', {
loop: true
});