User prompt
make the chess bot smarter
User prompt
add coordinates of the squares
User prompt
add a button at the right bottom to restart the game
User prompt
Please fix the bug: 'self.getPieceSymbol is not a function' in or related to this line: 'self.symbol = new Text2(self.getPieceSymbol(), {' Line Number: 109
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'fill')' in or related to this line: 'easyBtn.style.fill = "#ffff00";' Line Number: 1276
Code edit (1 edits merged)
Please save this source code
User prompt
Classic Chess Challenge
Initial prompt
chess game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
aiDifficulty: 1,
gameHistory: []
});
/****
* Classes
****/
var Board = Container.expand(function () {
var self = Container.call(this);
self.tiles = [];
self.tileSize = 256;
self.boardSize = 8 * self.tileSize;
self.highlightLayer = new Container();
self.piecesLayer = new Container();
self.createBoard = function () {
// Create tiles
for (var row = 0; row < 8; row++) {
self.tiles[row] = [];
for (var col = 0; col < 8; col++) {
var isWhite = (row + col) % 2 === 0;
var tile = self.attachAsset(isWhite ? 'whiteTile' : 'blackTile', {
x: col * self.tileSize,
y: row * self.tileSize,
anchorX: 0,
anchorY: 0
});
self.tiles[row][col] = tile;
tile.boardRow = row;
tile.boardCol = col;
}
}
self.addChild(self.highlightLayer);
self.addChild(self.piecesLayer);
};
self.highlightTile = function (row, col, type) {
var highlight = LK.getAsset(type, {
x: col * self.tileSize,
y: row * self.tileSize,
anchorX: 0,
anchorY: 0,
alpha: 0.5
});
self.highlightLayer.addChild(highlight);
return highlight;
};
self.clearHighlights = function () {
while (self.highlightLayer.children.length > 0) {
self.highlightLayer.removeChildAt(0);
}
};
self.getTileAt = function (x, y) {
var col = Math.floor(x / self.tileSize);
var row = Math.floor(y / self.tileSize);
if (row >= 0 && row < 8 && col >= 0 && col < 8) {
return {
row: row,
col: col
};
}
return null;
};
return self;
});
var Piece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.type = type;
self.color = color;
self.row = row;
self.col = col;
self.hasMoved = false;
// Get asset id based on color and type
var assetId = color + type.charAt(0).toUpperCase() + type.slice(1);
self.sprite = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add chess piece symbol
self.symbol = new Text2(self.getPieceSymbol(), {
size: 150,
fill: color === 'white' ? "#333333" : "#ffffff"
});
self.symbol.anchor.set(0.5, 0.5);
self.addChild(self.symbol);
self.getPieceSymbol = function () {
switch (self.type) {
case 'king':
return '♚';
case 'queen':
return '♛';
case 'rook':
return '♜';
case 'bishop':
return '♝';
case 'knight':
return '♞';
case 'pawn':
return '♟';
default:
return '';
}
};
self.moveTo = function (row, col, duration) {
self.row = row;
self.col = col;
var newX = col * chessBoard.tileSize + chessBoard.tileSize / 2;
var newY = row * chessBoard.tileSize + chessBoard.tileSize / 2;
if (duration) {
tween(self, {
x: newX,
y: newY
}, {
duration: duration,
easing: tween.easeOutQuad
});
} else {
self.x = newX;
self.y = newY;
}
self.hasMoved = true;
};
self.update = function () {
// For any per-frame updates
};
self.down = function (x, y, obj) {
if (gameState.currentTurn === self.color && !gameState.isAnimating) {
gameState.selectedPiece = self;
chessBoard.clearHighlights();
// Highlight the current piece's tile
self.currentHighlight = chessBoard.highlightTile(self.row, self.col, 'highlightTile');
// Highlight valid moves
var validMoves = getValidMoves(self);
gameState.validMoves = validMoves;
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
chessBoard.highlightTile(move.row, move.col, 'validMoveTile');
}
}
};
// Place piece at its position
self.x = col * 256 + 128;
self.y = row * 256 + 128;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game state
var gameState = {
currentTurn: 'white',
selectedPiece: null,
validMoves: [],
board: Array(8).fill().map(function () {
return Array(8).fill(null);
}),
isAnimating: false,
lastMove: null,
aiDifficulty: storage.aiDifficulty || 1,
gameMode: 'ai',
// 'ai' or 'twoPlayer'
status: 'playing',
// 'playing', 'check', 'checkmate', 'stalemate'
aiPlayer: 'black'
};
// Create UI
var titleText = new Text2('Chess Challenge', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
LK.gui.top.addChild(titleText);
var turnText = new Text2('White to move', {
size: 50,
fill: 0xFFFFFF
});
turnText.anchor.set(0.5, 0);
turnText.y = 100;
LK.gui.top.addChild(turnText);
var statusText = new Text2('', {
size: 50,
fill: 0xFFFF00
});
statusText.anchor.set(0.5, 0);
statusText.y = 160;
LK.gui.top.addChild(statusText);
// Create and position the chess board
var chessBoard = new Board();
game.addChild(chessBoard);
chessBoard.createBoard();
// Center the board
chessBoard.x = (2048 - chessBoard.boardSize) / 2;
chessBoard.y = (2732 - chessBoard.boardSize) / 2;
// Initialize pieces
function initializeChessBoard() {
// Clear existing pieces
while (chessBoard.piecesLayer.children.length > 0) {
chessBoard.piecesLayer.removeChildAt(0);
}
// Reset game state
gameState.board = Array(8).fill().map(function () {
return Array(8).fill(null);
});
gameState.currentTurn = 'white';
gameState.selectedPiece = null;
gameState.validMoves = [];
gameState.isAnimating = false;
gameState.lastMove = null;
gameState.status = 'playing';
// Update UI
updateTurnText();
// Create pieces
var pieces = [{
type: 'rook',
color: 'black',
row: 0,
col: 0
}, {
type: 'knight',
color: 'black',
row: 0,
col: 1
}, {
type: 'bishop',
color: 'black',
row: 0,
col: 2
}, {
type: 'queen',
color: 'black',
row: 0,
col: 3
}, {
type: 'king',
color: 'black',
row: 0,
col: 4
}, {
type: 'bishop',
color: 'black',
row: 0,
col: 5
}, {
type: 'knight',
color: 'black',
row: 0,
col: 6
}, {
type: 'rook',
color: 'black',
row: 0,
col: 7
}, {
type: 'rook',
color: 'white',
row: 7,
col: 0
}, {
type: 'knight',
color: 'white',
row: 7,
col: 1
}, {
type: 'bishop',
color: 'white',
row: 7,
col: 2
}, {
type: 'queen',
color: 'white',
row: 7,
col: 3
}, {
type: 'king',
color: 'white',
row: 7,
col: 4
}, {
type: 'bishop',
color: 'white',
row: 7,
col: 5
}, {
type: 'knight',
color: 'white',
row: 7,
col: 6
}, {
type: 'rook',
color: 'white',
row: 7,
col: 7
}];
// Add pawns
for (var i = 0; i < 8; i++) {
pieces.push({
type: 'pawn',
color: 'black',
row: 1,
col: i
});
pieces.push({
type: 'pawn',
color: 'white',
row: 6,
col: i
});
}
// Create and position pieces
for (var i = 0; i < pieces.length; i++) {
var p = pieces[i];
var piece = new Piece(p.type, p.color, p.row, p.col);
chessBoard.piecesLayer.addChild(piece);
gameState.board[p.row][p.col] = piece;
}
// Clear highlights
chessBoard.clearHighlights();
}
// Chess move validation
function getValidMoves(piece) {
var moves = [];
if (!piece) return moves;
function addMove(row, col) {
moves.push({
row: row,
col: col
});
}
function isOnBoard(row, col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
}
function isOccupied(row, col) {
return gameState.board[row][col] !== null;
}
function isEnemyPiece(row, col) {
return isOccupied(row, col) && gameState.board[row][col].color !== piece.color;
}
function isFriendlyPiece(row, col) {
return isOccupied(row, col) && gameState.board[row][col].color === piece.color;
}
var row = piece.row;
var col = piece.col;
switch (piece.type) {
case 'pawn':
var direction = piece.color === 'white' ? -1 : 1;
// Move forward one square
if (isOnBoard(row + direction, col) && !isOccupied(row + direction, col)) {
addMove(row + direction, col);
// Move forward two squares on first move
if (!piece.hasMoved && isOnBoard(row + 2 * direction, col) && !isOccupied(row + 2 * direction, col)) {
addMove(row + 2 * direction, col);
}
}
// Capture diagonally
if (isOnBoard(row + direction, col - 1) && isEnemyPiece(row + direction, col - 1)) {
addMove(row + direction, col - 1);
}
if (isOnBoard(row + direction, col + 1) && isEnemyPiece(row + direction, col + 1)) {
addMove(row + direction, col + 1);
}
// En passant (simplified)
if (gameState.lastMove && gameState.lastMove.piece.type === 'pawn' && gameState.lastMove.fromRow === (piece.color === 'white' ? 1 : 6) && gameState.lastMove.toRow === (piece.color === 'white' ? 3 : 4) && Math.abs(gameState.lastMove.toCol - col) === 1 && row === gameState.lastMove.toRow) {
addMove(row + direction, gameState.lastMove.toCol);
}
break;
case 'rook':
// Horizontal and vertical directions
var directions = [{
dr: -1,
dc: 0
},
// up
{
dr: 1,
dc: 0
},
// down
{
dr: 0,
dc: -1
},
// left
{
dr: 0,
dc: 1
} // right
];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
while (isOnBoard(r, c)) {
if (isOccupied(r, c)) {
if (isEnemyPiece(r, c)) {
addMove(r, c);
}
break;
}
addMove(r, c);
r += dir.dr;
c += dir.dc;
}
});
break;
case 'knight':
// Knight moves
var knightMoves = [{
dr: -2,
dc: -1
}, {
dr: -2,
dc: 1
}, {
dr: -1,
dc: -2
}, {
dr: -1,
dc: 2
}, {
dr: 1,
dc: -2
}, {
dr: 1,
dc: 2
}, {
dr: 2,
dc: -1
}, {
dr: 2,
dc: 1
}];
knightMoves.forEach(function (move) {
var r = row + move.dr;
var c = col + move.dc;
if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
addMove(r, c);
}
});
break;
case 'bishop':
// Diagonal directions
var directions = [{
dr: -1,
dc: -1
},
// up-left
{
dr: -1,
dc: 1
},
// up-right
{
dr: 1,
dc: -1
},
// down-left
{
dr: 1,
dc: 1
} // down-right
];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
while (isOnBoard(r, c)) {
if (isOccupied(r, c)) {
if (isEnemyPiece(r, c)) {
addMove(r, c);
}
break;
}
addMove(r, c);
r += dir.dr;
c += dir.dc;
}
});
break;
case 'queen':
// Combine rook and bishop moves
var directions = [{
dr: -1,
dc: 0
}, {
dr: 1,
dc: 0
},
// vertical
{
dr: 0,
dc: -1
}, {
dr: 0,
dc: 1
},
// horizontal
{
dr: -1,
dc: -1
}, {
dr: -1,
dc: 1
},
// diagonal
{
dr: 1,
dc: -1
}, {
dr: 1,
dc: 1
} // diagonal
];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
while (isOnBoard(r, c)) {
if (isOccupied(r, c)) {
if (isEnemyPiece(r, c)) {
addMove(r, c);
}
break;
}
addMove(r, c);
r += dir.dr;
c += dir.dc;
}
});
break;
case 'king':
// King moves (one square in any direction)
var directions = [{
dr: -1,
dc: -1
}, {
dr: -1,
dc: 0
}, {
dr: -1,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 0,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: 1,
dc: 1
}];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
addMove(r, c);
}
});
// Castling
if (!piece.hasMoved) {
// Kingside castling
if (!isOccupied(row, col + 1) && !isOccupied(row, col + 2) && isOccupied(row, col + 3) && !gameState.board[row][col + 3].hasMoved && gameState.board[row][col + 3].type === 'rook') {
addMove(row, col + 2);
}
// Queenside castling
if (!isOccupied(row, col - 1) && !isOccupied(row, col - 2) && !isOccupied(row, col - 3) && isOccupied(row, col - 4) && !gameState.board[row][col - 4].hasMoved && gameState.board[row][col - 4].type === 'rook') {
addMove(row, col - 2);
}
}
break;
}
// Filter out moves that would put the king in check
var validMoves = [];
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
// Make a temporary move
var tempPiece = gameState.board[move.row][move.col];
gameState.board[move.row][move.col] = piece;
gameState.board[row][col] = null;
// Check if the move puts/leaves the king in check
var inCheck = isKingInCheck(piece.color);
// Undo the move
gameState.board[row][col] = piece;
gameState.board[move.row][move.col] = tempPiece;
if (!inCheck) {
validMoves.push(move);
}
}
return validMoves;
}
function isKingInCheck(color) {
// Find the king
var kingRow = -1;
var kingCol = -1;
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
var piece = gameState.board[r][c];
if (piece && piece.type === 'king' && piece.color === color) {
kingRow = r;
kingCol = c;
break;
}
}
if (kingRow !== -1) break;
}
// Check if any enemy piece can capture the king
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
var piece = gameState.board[r][c];
if (piece && piece.color !== color) {
// Get the enemy's valid moves (ignoring check)
var moves = getBasicMoves(piece);
// See if any of the moves can capture the king
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === kingRow && moves[i].col === kingCol) {
return true;
}
}
}
}
}
return false;
}
function getBasicMoves(piece) {
var moves = [];
if (!piece) return moves;
function addMove(row, col) {
moves.push({
row: row,
col: col
});
}
function isOnBoard(row, col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
}
function isOccupied(row, col) {
return gameState.board[row][col] !== null;
}
function isEnemyPiece(row, col) {
return isOccupied(row, col) && gameState.board[row][col].color !== piece.color;
}
function isFriendlyPiece(row, col) {
return isOccupied(row, col) && gameState.board[row][col].color === piece.color;
}
var row = piece.row;
var col = piece.col;
switch (piece.type) {
case 'pawn':
var direction = piece.color === 'white' ? -1 : 1;
// Move forward one square
if (isOnBoard(row + direction, col) && !isOccupied(row + direction, col)) {
addMove(row + direction, col);
// Move forward two squares on first move
if (!piece.hasMoved && isOnBoard(row + 2 * direction, col) && !isOccupied(row + 2 * direction, col)) {
addMove(row + 2 * direction, col);
}
}
// Capture diagonally
if (isOnBoard(row + direction, col - 1) && isEnemyPiece(row + direction, col - 1)) {
addMove(row + direction, col - 1);
}
if (isOnBoard(row + direction, col + 1) && isEnemyPiece(row + direction, col + 1)) {
addMove(row + direction, col + 1);
}
break;
case 'rook':
// Horizontal and vertical directions
var directions = [{
dr: -1,
dc: 0
},
// up
{
dr: 1,
dc: 0
},
// down
{
dr: 0,
dc: -1
},
// left
{
dr: 0,
dc: 1
} // right
];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
while (isOnBoard(r, c)) {
if (isOccupied(r, c)) {
if (isEnemyPiece(r, c)) {
addMove(r, c);
}
break;
}
addMove(r, c);
r += dir.dr;
c += dir.dc;
}
});
break;
case 'knight':
// Knight moves
var knightMoves = [{
dr: -2,
dc: -1
}, {
dr: -2,
dc: 1
}, {
dr: -1,
dc: -2
}, {
dr: -1,
dc: 2
}, {
dr: 1,
dc: -2
}, {
dr: 1,
dc: 2
}, {
dr: 2,
dc: -1
}, {
dr: 2,
dc: 1
}];
knightMoves.forEach(function (move) {
var r = row + move.dr;
var c = col + move.dc;
if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
addMove(r, c);
}
});
break;
case 'bishop':
// Diagonal directions
var directions = [{
dr: -1,
dc: -1
},
// up-left
{
dr: -1,
dc: 1
},
// up-right
{
dr: 1,
dc: -1
},
// down-left
{
dr: 1,
dc: 1
} // down-right
];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
while (isOnBoard(r, c)) {
if (isOccupied(r, c)) {
if (isEnemyPiece(r, c)) {
addMove(r, c);
}
break;
}
addMove(r, c);
r += dir.dr;
c += dir.dc;
}
});
break;
case 'queen':
// Combine rook and bishop moves
var directions = [{
dr: -1,
dc: 0
}, {
dr: 1,
dc: 0
},
// vertical
{
dr: 0,
dc: -1
}, {
dr: 0,
dc: 1
},
// horizontal
{
dr: -1,
dc: -1
}, {
dr: -1,
dc: 1
},
// diagonal
{
dr: 1,
dc: -1
}, {
dr: 1,
dc: 1
} // diagonal
];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
while (isOnBoard(r, c)) {
if (isOccupied(r, c)) {
if (isEnemyPiece(r, c)) {
addMove(r, c);
}
break;
}
addMove(r, c);
r += dir.dr;
c += dir.dc;
}
});
break;
case 'king':
// King moves (one square in any direction)
var directions = [{
dr: -1,
dc: -1
}, {
dr: -1,
dc: 0
}, {
dr: -1,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 0,
dc: 1
}, {
dr: 1,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: 1,
dc: 1
}];
directions.forEach(function (dir) {
var r = row + dir.dr;
var c = col + dir.dc;
if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
addMove(r, c);
}
});
break;
}
return moves;
}
function isCheckmate(color) {
if (!isKingInCheck(color)) return false;
// Check if any piece can make a valid move
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
var piece = gameState.board[r][c];
if (piece && piece.color === color) {
var validMoves = getValidMoves(piece);
if (validMoves.length > 0) {
return false;
}
}
}
}
return true;
}
function isStalemate(color) {
if (isKingInCheck(color)) return false;
// Check if any piece can make a valid move
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
var piece = gameState.board[r][c];
if (piece && piece.color === color) {
var validMoves = getValidMoves(piece);
if (validMoves.length > 0) {
return false;
}
}
}
}
return true;
}
function updateGameStatus() {
if (isCheckmate(gameState.currentTurn)) {
gameState.status = 'checkmate';
var winner = gameState.currentTurn === 'white' ? 'Black' : 'White';
statusText.setText(winner + ' wins by checkmate!');
LK.getSound('gameEnd').play();
// Update score if AI was played against
if (gameState.gameMode === 'ai') {
if (winner === 'White' && gameState.aiPlayer === 'black' || winner === 'Black' && gameState.aiPlayer === 'white') {
LK.setScore(LK.getScore() + 1);
}
}
return true;
} else if (isStalemate(gameState.currentTurn)) {
gameState.status = 'stalemate';
statusText.setText('Game drawn by stalemate!');
LK.getSound('gameEnd').play();
return true;
} else if (isKingInCheck(gameState.currentTurn)) {
gameState.status = 'check';
statusText.setText(gameState.currentTurn.charAt(0).toUpperCase() + gameState.currentTurn.slice(1) + ' is in check!');
LK.getSound('check').play();
} else {
gameState.status = 'playing';
statusText.setText('');
}
return false;
}
function updateTurnText() {
var turnName = gameState.currentTurn.charAt(0).toUpperCase() + gameState.currentTurn.slice(1);
turnText.setText(turnName + ' to move');
}
function movePiece(piece, targetRow, targetCol) {
var isCapture = gameState.board[targetRow][targetCol] !== null;
var capturedPiece = gameState.board[targetRow][targetCol];
var fromRow = piece.row;
var fromCol = piece.col;
// Handle castling
if (piece.type === 'king' && Math.abs(targetCol - fromCol) === 2) {
// Kingside castling
if (targetCol > fromCol) {
var rook = gameState.board[fromRow][7];
gameState.board[fromRow][5] = rook;
gameState.board[fromRow][7] = null;
rook.moveTo(fromRow, 5, 300);
}
// Queenside castling
else {
var rook = gameState.board[fromRow][0];
gameState.board[fromRow][3] = rook;
gameState.board[fromRow][0] = null;
rook.moveTo(fromRow, 3, 300);
}
}
// Handle en passant capture
if (piece.type === 'pawn' && Math.abs(targetCol - fromCol) === 1 && !isCapture) {
var enPassantRow = piece.color === 'white' ? targetRow + 1 : targetRow - 1;
capturedPiece = gameState.board[enPassantRow][targetCol];
gameState.board[enPassantRow][targetCol] = null;
if (capturedPiece) {
capturedPiece.parent.removeChild(capturedPiece);
}
isCapture = true;
}
// Update board array
gameState.board[fromRow][fromCol] = null;
if (capturedPiece) {
capturedPiece.parent.removeChild(capturedPiece);
}
gameState.board[targetRow][targetCol] = piece;
// Move the piece with animation
gameState.isAnimating = true;
piece.moveTo(targetRow, targetCol, 300);
// Play sound
if (isCapture) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
// Handle pawn promotion (always to queen for simplicity)
if (piece.type === 'pawn' && (targetRow === 0 || targetRow === 7)) {
// Wait for the piece to finish moving
var promotionTimeout = LK.setTimeout(function () {
// Remove the pawn
piece.parent.removeChild(piece);
gameState.board[targetRow][targetCol] = null;
// Create a new queen
var queen = new Piece('queen', piece.color, targetRow, targetCol);
chessBoard.piecesLayer.addChild(queen);
gameState.board[targetRow][targetCol] = queen;
LK.clearTimeout(promotionTimeout);
}, 350);
}
// Update last move
gameState.lastMove = {
piece: piece,
fromRow: fromRow,
fromCol: fromCol,
toRow: targetRow,
toCol: targetCol
};
// Highlight the last move
var moveTimeout = LK.setTimeout(function () {
chessBoard.clearHighlights();
chessBoard.highlightTile(fromRow, fromCol, 'lastMoveTile');
chessBoard.highlightTile(targetRow, targetCol, 'lastMoveTile');
// Switch turns
gameState.currentTurn = gameState.currentTurn === 'white' ? 'black' : 'white';
updateTurnText();
// Check for check, checkmate, stalemate
var gameEnded = updateGameStatus();
gameState.isAnimating = false;
gameState.selectedPiece = null;
// If AI is playing and it's AI's turn
if (!gameEnded && gameState.gameMode === 'ai' && gameState.currentTurn === gameState.aiPlayer) {
makeAIMove();
}
LK.clearTimeout(moveTimeout);
}, 350);
}
function makeAIMove() {
var aiTimeout = LK.setTimeout(function () {
var allPossibleMoves = [];
// Collect all possible moves for AI pieces
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
var piece = gameState.board[r][c];
if (piece && piece.color === gameState.aiPlayer) {
var validMoves = getValidMoves(piece);
for (var i = 0; i < validMoves.length; i++) {
allPossibleMoves.push({
piece: piece,
move: validMoves[i]
});
}
}
}
}
if (allPossibleMoves.length > 0) {
var selectedMove;
// Basic AI difficulty levels
if (gameState.aiDifficulty === 1) {
// Easy: Random move
selectedMove = allPossibleMoves[Math.floor(Math.random() * allPossibleMoves.length)];
} else if (gameState.aiDifficulty === 2) {
// Medium: Prefer captures and checks
var captureMoves = allPossibleMoves.filter(function (moveObj) {
return gameState.board[moveObj.move.row][moveObj.move.col] !== null;
});
if (captureMoves.length > 0) {
selectedMove = captureMoves[Math.floor(Math.random() * captureMoves.length)];
} else {
selectedMove = allPossibleMoves[Math.floor(Math.random() * allPossibleMoves.length)];
}
} else {
// Hard: Prioritize captures by piece value
var bestValue = -1;
var bestMoves = [];
for (var i = 0; i < allPossibleMoves.length; i++) {
var moveObj = allPossibleMoves[i];
var targetPiece = gameState.board[moveObj.move.row][moveObj.move.col];
var moveValue = 0;
if (targetPiece) {
// Assign values to pieces
switch (targetPiece.type) {
case 'pawn':
moveValue = 1;
break;
case 'knight':
case 'bishop':
moveValue = 3;
break;
case 'rook':
moveValue = 5;
break;
case 'queen':
moveValue = 9;
break;
case 'king':
moveValue = 100;
break;
}
}
// Prioritize center control for pawns and knights
if (moveObj.piece.type === 'pawn' || moveObj.piece.type === 'knight') {
var centerDistance = Math.abs(moveObj.move.row - 3.5) + Math.abs(moveObj.move.col - 3.5);
moveValue += (4 - centerDistance) * 0.1;
}
if (moveValue > bestValue) {
bestValue = moveValue;
bestMoves = [moveObj];
} else if (moveValue === bestValue) {
bestMoves.push(moveObj);
}
}
if (bestMoves.length > 0) {
selectedMove = bestMoves[Math.floor(Math.random() * bestMoves.length)];
} else {
selectedMove = allPossibleMoves[Math.floor(Math.random() * allPossibleMoves.length)];
}
}
// Make the selected move
movePiece(selectedMove.piece, selectedMove.move.row, selectedMove.move.col);
}
LK.clearTimeout(aiTimeout);
}, 500);
}
// Game event handlers
game.down = function (x, y, obj) {
if (gameState.isAnimating) return;
// Convert screen coordinates to board coordinates
var boardX = x - chessBoard.x;
var boardY = y - chessBoard.y;
var tile = chessBoard.getTileAt(boardX, boardY);
if (tile && gameState.selectedPiece) {
// Check if the clicked tile is a valid move
var isValidMove = false;
for (var i = 0; i < gameState.validMoves.length; i++) {
var move = gameState.validMoves[i];
if (move.row === tile.row && move.col === tile.col) {
isValidMove = true;
break;
}
}
if (isValidMove) {
// Move the piece
movePiece(gameState.selectedPiece, tile.row, tile.col);
return;
}
}
// Clear selection if clicking elsewhere
if (gameState.selectedPiece) {
chessBoard.clearHighlights();
gameState.selectedPiece = null;
}
};
// Game Mode Buttons
var twoPlayerBtn = new Text2('Two Player', {
size: 50,
fill: 0xFFFFFF
});
twoPlayerBtn.anchor.set(0.5, 0);
twoPlayerBtn.y = 2732 - 200;
twoPlayerBtn.x = 2048 / 2 - 300;
LK.gui.addChild(twoPlayerBtn);
twoPlayerBtn.interactive = true;
twoPlayerBtn.buttonMode = true;
twoPlayerBtn.on('pointerdown', function () {
gameState.gameMode = 'twoPlayer';
gameState.aiPlayer = null;
LK.setScore(0);
initializeChessBoard();
updateTurnText();
chessBoard.clearHighlights();
});
var aiBtn = new Text2('Play vs AI', {
size: 50,
fill: 0xFFFFFF
});
aiBtn.anchor.set(0.5, 0);
aiBtn.y = 2732 - 200;
aiBtn.x = 2048 / 2 + 300;
LK.gui.addChild(aiBtn);
aiBtn.interactive = true;
aiBtn.buttonMode = true;
aiBtn.on('pointerdown', function () {
gameState.gameMode = 'ai';
gameState.aiPlayer = 'black';
LK.setScore(0);
initializeChessBoard();
updateTurnText();
chessBoard.clearHighlights();
});
// AI Difficulty Buttons
var easyBtn = new Text2('Easy', {
size: 40,
fill: gameState.aiDifficulty === 1 ? "#ffff00" : "#aaaaaa"
});
easyBtn.anchor.set(0.5, 0);
easyBtn.y = 2732 - 120;
easyBtn.x = 2048 / 2 - 300;
LK.gui.addChild(easyBtn);
easyBtn.interactive = true;
easyBtn.buttonMode = true;
easyBtn.on('pointerdown', function () {
gameState.aiDifficulty = 1;
storage.aiDifficulty = 1;
easyBtn.style.fill = "#ffff00";
mediumBtn.style.fill = "#aaaaaa";
hardBtn.style.fill = "#aaaaaa";
});
var mediumBtn = new Text2('Medium', {
size: 40,
fill: gameState.aiDifficulty === 2 ? "#ffff00" : "#aaaaaa"
});
mediumBtn.anchor.set(0.5, 0);
mediumBtn.y = 2732 - 120;
mediumBtn.x = 2048 / 2;
LK.gui.addChild(mediumBtn);
mediumBtn.interactive = true;
mediumBtn.buttonMode = true;
mediumBtn.on('pointerdown', function () {
gameState.aiDifficulty = 2;
storage.aiDifficulty = 2;
easyBtn.style.fill = "#aaaaaa";
mediumBtn.style.fill = "#ffff00";
hardBtn.style.fill = "#aaaaaa";
});
var hardBtn = new Text2('Hard', {
size: 40,
fill: gameState.aiDifficulty === 3 ? "#ffff00" : "#aaaaaa"
});
hardBtn.anchor.set(0.5, 0);
hardBtn.y = 2732 - 120;
hardBtn.x = 2048 / 2 + 300;
LK.gui.addChild(hardBtn);
hardBtn.interactive = true;
hardBtn.buttonMode = true;
hardBtn.on('pointerdown', function () {
gameState.aiDifficulty = 3;
storage.aiDifficulty = 3;
easyBtn.style.fill = "#aaaaaa";
mediumBtn.style.fill = "#aaaaaa";
hardBtn.style.fill = "#ffff00";
});
// Update difficulty button colors based on current setting
switch (gameState.aiDifficulty) {
case 1:
easyBtn.style.fill = "#ffff00";
mediumBtn.style.fill = "#aaaaaa";
hardBtn.style.fill = "#aaaaaa";
break;
case 2:
easyBtn.style.fill = "#aaaaaa";
mediumBtn.style.fill = "#ffff00";
hardBtn.style.fill = "#aaaaaa";
break;
case 3:
easyBtn.style.fill = "#aaaaaa";
mediumBtn.style.fill = "#aaaaaa";
hardBtn.style.fill = "#ffff00";
break;
}
// New Game button
var newGameBtn = new Text2('New Game', {
size: 50,
fill: 0xFFFFFF
});
newGameBtn.anchor.set(0.5, 0);
newGameBtn.y = 2732 - 280;
newGameBtn.x = 2048 / 2;
LK.gui.addChild(newGameBtn);
newGameBtn.interactive = true;
newGameBtn.buttonMode = true;
newGameBtn.on('pointerdown', function () {
initializeChessBoard();
updateTurnText();
});
// Initialize the game
initializeChessBoard();
// Main game loop
game.update = function () {
// Game update logic happens in event handlers and callbacks
};
// Play background music
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 0.3,
duration: 1000
}
}); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,1281 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ aiDifficulty: 1,
+ gameHistory: []
+});
+
+/****
+* Classes
+****/
+var Board = Container.expand(function () {
+ var self = Container.call(this);
+ self.tiles = [];
+ self.tileSize = 256;
+ self.boardSize = 8 * self.tileSize;
+ self.highlightLayer = new Container();
+ self.piecesLayer = new Container();
+ self.createBoard = function () {
+ // Create tiles
+ for (var row = 0; row < 8; row++) {
+ self.tiles[row] = [];
+ for (var col = 0; col < 8; col++) {
+ var isWhite = (row + col) % 2 === 0;
+ var tile = self.attachAsset(isWhite ? 'whiteTile' : 'blackTile', {
+ x: col * self.tileSize,
+ y: row * self.tileSize,
+ anchorX: 0,
+ anchorY: 0
+ });
+ self.tiles[row][col] = tile;
+ tile.boardRow = row;
+ tile.boardCol = col;
+ }
+ }
+ self.addChild(self.highlightLayer);
+ self.addChild(self.piecesLayer);
+ };
+ self.highlightTile = function (row, col, type) {
+ var highlight = LK.getAsset(type, {
+ x: col * self.tileSize,
+ y: row * self.tileSize,
+ anchorX: 0,
+ anchorY: 0,
+ alpha: 0.5
+ });
+ self.highlightLayer.addChild(highlight);
+ return highlight;
+ };
+ self.clearHighlights = function () {
+ while (self.highlightLayer.children.length > 0) {
+ self.highlightLayer.removeChildAt(0);
+ }
+ };
+ self.getTileAt = function (x, y) {
+ var col = Math.floor(x / self.tileSize);
+ var row = Math.floor(y / self.tileSize);
+ if (row >= 0 && row < 8 && col >= 0 && col < 8) {
+ return {
+ row: row,
+ col: col
+ };
+ }
+ return null;
+ };
+ return self;
+});
+var Piece = Container.expand(function (type, color, row, col) {
+ var self = Container.call(this);
+ self.type = type;
+ self.color = color;
+ self.row = row;
+ self.col = col;
+ self.hasMoved = false;
+ // Get asset id based on color and type
+ var assetId = color + type.charAt(0).toUpperCase() + type.slice(1);
+ self.sprite = self.attachAsset(assetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Add chess piece symbol
+ self.symbol = new Text2(self.getPieceSymbol(), {
+ size: 150,
+ fill: color === 'white' ? "#333333" : "#ffffff"
+ });
+ self.symbol.anchor.set(0.5, 0.5);
+ self.addChild(self.symbol);
+ self.getPieceSymbol = function () {
+ switch (self.type) {
+ case 'king':
+ return '♚';
+ case 'queen':
+ return '♛';
+ case 'rook':
+ return '♜';
+ case 'bishop':
+ return '♝';
+ case 'knight':
+ return '♞';
+ case 'pawn':
+ return '♟';
+ default:
+ return '';
+ }
+ };
+ self.moveTo = function (row, col, duration) {
+ self.row = row;
+ self.col = col;
+ var newX = col * chessBoard.tileSize + chessBoard.tileSize / 2;
+ var newY = row * chessBoard.tileSize + chessBoard.tileSize / 2;
+ if (duration) {
+ tween(self, {
+ x: newX,
+ y: newY
+ }, {
+ duration: duration,
+ easing: tween.easeOutQuad
+ });
+ } else {
+ self.x = newX;
+ self.y = newY;
+ }
+ self.hasMoved = true;
+ };
+ self.update = function () {
+ // For any per-frame updates
+ };
+ self.down = function (x, y, obj) {
+ if (gameState.currentTurn === self.color && !gameState.isAnimating) {
+ gameState.selectedPiece = self;
+ chessBoard.clearHighlights();
+ // Highlight the current piece's tile
+ self.currentHighlight = chessBoard.highlightTile(self.row, self.col, 'highlightTile');
+ // Highlight valid moves
+ var validMoves = getValidMoves(self);
+ gameState.validMoves = validMoves;
+ for (var i = 0; i < validMoves.length; i++) {
+ var move = validMoves[i];
+ chessBoard.highlightTile(move.row, move.col, 'validMoveTile');
+ }
+ }
+ };
+ // Place piece at its position
+ self.x = col * 256 + 128;
+ self.y = row * 256 + 128;
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x2c3e50
+});
+
+/****
+* Game Code
+****/
+// Game state
+var gameState = {
+ currentTurn: 'white',
+ selectedPiece: null,
+ validMoves: [],
+ board: Array(8).fill().map(function () {
+ return Array(8).fill(null);
+ }),
+ isAnimating: false,
+ lastMove: null,
+ aiDifficulty: storage.aiDifficulty || 1,
+ gameMode: 'ai',
+ // 'ai' or 'twoPlayer'
+ status: 'playing',
+ // 'playing', 'check', 'checkmate', 'stalemate'
+ aiPlayer: 'black'
+};
+// Create UI
+var titleText = new Text2('Chess Challenge', {
+ size: 80,
+ fill: 0xFFFFFF
+});
+titleText.anchor.set(0.5, 0);
+LK.gui.top.addChild(titleText);
+var turnText = new Text2('White to move', {
+ size: 50,
+ fill: 0xFFFFFF
+});
+turnText.anchor.set(0.5, 0);
+turnText.y = 100;
+LK.gui.top.addChild(turnText);
+var statusText = new Text2('', {
+ size: 50,
+ fill: 0xFFFF00
+});
+statusText.anchor.set(0.5, 0);
+statusText.y = 160;
+LK.gui.top.addChild(statusText);
+// Create and position the chess board
+var chessBoard = new Board();
+game.addChild(chessBoard);
+chessBoard.createBoard();
+// Center the board
+chessBoard.x = (2048 - chessBoard.boardSize) / 2;
+chessBoard.y = (2732 - chessBoard.boardSize) / 2;
+// Initialize pieces
+function initializeChessBoard() {
+ // Clear existing pieces
+ while (chessBoard.piecesLayer.children.length > 0) {
+ chessBoard.piecesLayer.removeChildAt(0);
+ }
+ // Reset game state
+ gameState.board = Array(8).fill().map(function () {
+ return Array(8).fill(null);
+ });
+ gameState.currentTurn = 'white';
+ gameState.selectedPiece = null;
+ gameState.validMoves = [];
+ gameState.isAnimating = false;
+ gameState.lastMove = null;
+ gameState.status = 'playing';
+ // Update UI
+ updateTurnText();
+ // Create pieces
+ var pieces = [{
+ type: 'rook',
+ color: 'black',
+ row: 0,
+ col: 0
+ }, {
+ type: 'knight',
+ color: 'black',
+ row: 0,
+ col: 1
+ }, {
+ type: 'bishop',
+ color: 'black',
+ row: 0,
+ col: 2
+ }, {
+ type: 'queen',
+ color: 'black',
+ row: 0,
+ col: 3
+ }, {
+ type: 'king',
+ color: 'black',
+ row: 0,
+ col: 4
+ }, {
+ type: 'bishop',
+ color: 'black',
+ row: 0,
+ col: 5
+ }, {
+ type: 'knight',
+ color: 'black',
+ row: 0,
+ col: 6
+ }, {
+ type: 'rook',
+ color: 'black',
+ row: 0,
+ col: 7
+ }, {
+ type: 'rook',
+ color: 'white',
+ row: 7,
+ col: 0
+ }, {
+ type: 'knight',
+ color: 'white',
+ row: 7,
+ col: 1
+ }, {
+ type: 'bishop',
+ color: 'white',
+ row: 7,
+ col: 2
+ }, {
+ type: 'queen',
+ color: 'white',
+ row: 7,
+ col: 3
+ }, {
+ type: 'king',
+ color: 'white',
+ row: 7,
+ col: 4
+ }, {
+ type: 'bishop',
+ color: 'white',
+ row: 7,
+ col: 5
+ }, {
+ type: 'knight',
+ color: 'white',
+ row: 7,
+ col: 6
+ }, {
+ type: 'rook',
+ color: 'white',
+ row: 7,
+ col: 7
+ }];
+ // Add pawns
+ for (var i = 0; i < 8; i++) {
+ pieces.push({
+ type: 'pawn',
+ color: 'black',
+ row: 1,
+ col: i
+ });
+ pieces.push({
+ type: 'pawn',
+ color: 'white',
+ row: 6,
+ col: i
+ });
+ }
+ // Create and position pieces
+ for (var i = 0; i < pieces.length; i++) {
+ var p = pieces[i];
+ var piece = new Piece(p.type, p.color, p.row, p.col);
+ chessBoard.piecesLayer.addChild(piece);
+ gameState.board[p.row][p.col] = piece;
+ }
+ // Clear highlights
+ chessBoard.clearHighlights();
+}
+// Chess move validation
+function getValidMoves(piece) {
+ var moves = [];
+ if (!piece) return moves;
+ function addMove(row, col) {
+ moves.push({
+ row: row,
+ col: col
+ });
+ }
+ function isOnBoard(row, col) {
+ return row >= 0 && row < 8 && col >= 0 && col < 8;
+ }
+ function isOccupied(row, col) {
+ return gameState.board[row][col] !== null;
+ }
+ function isEnemyPiece(row, col) {
+ return isOccupied(row, col) && gameState.board[row][col].color !== piece.color;
+ }
+ function isFriendlyPiece(row, col) {
+ return isOccupied(row, col) && gameState.board[row][col].color === piece.color;
+ }
+ var row = piece.row;
+ var col = piece.col;
+ switch (piece.type) {
+ case 'pawn':
+ var direction = piece.color === 'white' ? -1 : 1;
+ // Move forward one square
+ if (isOnBoard(row + direction, col) && !isOccupied(row + direction, col)) {
+ addMove(row + direction, col);
+ // Move forward two squares on first move
+ if (!piece.hasMoved && isOnBoard(row + 2 * direction, col) && !isOccupied(row + 2 * direction, col)) {
+ addMove(row + 2 * direction, col);
+ }
+ }
+ // Capture diagonally
+ if (isOnBoard(row + direction, col - 1) && isEnemyPiece(row + direction, col - 1)) {
+ addMove(row + direction, col - 1);
+ }
+ if (isOnBoard(row + direction, col + 1) && isEnemyPiece(row + direction, col + 1)) {
+ addMove(row + direction, col + 1);
+ }
+ // En passant (simplified)
+ if (gameState.lastMove && gameState.lastMove.piece.type === 'pawn' && gameState.lastMove.fromRow === (piece.color === 'white' ? 1 : 6) && gameState.lastMove.toRow === (piece.color === 'white' ? 3 : 4) && Math.abs(gameState.lastMove.toCol - col) === 1 && row === gameState.lastMove.toRow) {
+ addMove(row + direction, gameState.lastMove.toCol);
+ }
+ break;
+ case 'rook':
+ // Horizontal and vertical directions
+ var directions = [{
+ dr: -1,
+ dc: 0
+ },
+ // up
+ {
+ dr: 1,
+ dc: 0
+ },
+ // down
+ {
+ dr: 0,
+ dc: -1
+ },
+ // left
+ {
+ dr: 0,
+ dc: 1
+ } // right
+ ];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ while (isOnBoard(r, c)) {
+ if (isOccupied(r, c)) {
+ if (isEnemyPiece(r, c)) {
+ addMove(r, c);
+ }
+ break;
+ }
+ addMove(r, c);
+ r += dir.dr;
+ c += dir.dc;
+ }
+ });
+ break;
+ case 'knight':
+ // Knight moves
+ var knightMoves = [{
+ dr: -2,
+ dc: -1
+ }, {
+ dr: -2,
+ dc: 1
+ }, {
+ dr: -1,
+ dc: -2
+ }, {
+ dr: -1,
+ dc: 2
+ }, {
+ dr: 1,
+ dc: -2
+ }, {
+ dr: 1,
+ dc: 2
+ }, {
+ dr: 2,
+ dc: -1
+ }, {
+ dr: 2,
+ dc: 1
+ }];
+ knightMoves.forEach(function (move) {
+ var r = row + move.dr;
+ var c = col + move.dc;
+ if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
+ addMove(r, c);
+ }
+ });
+ break;
+ case 'bishop':
+ // Diagonal directions
+ var directions = [{
+ dr: -1,
+ dc: -1
+ },
+ // up-left
+ {
+ dr: -1,
+ dc: 1
+ },
+ // up-right
+ {
+ dr: 1,
+ dc: -1
+ },
+ // down-left
+ {
+ dr: 1,
+ dc: 1
+ } // down-right
+ ];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ while (isOnBoard(r, c)) {
+ if (isOccupied(r, c)) {
+ if (isEnemyPiece(r, c)) {
+ addMove(r, c);
+ }
+ break;
+ }
+ addMove(r, c);
+ r += dir.dr;
+ c += dir.dc;
+ }
+ });
+ break;
+ case 'queen':
+ // Combine rook and bishop moves
+ var directions = [{
+ dr: -1,
+ dc: 0
+ }, {
+ dr: 1,
+ dc: 0
+ },
+ // vertical
+ {
+ dr: 0,
+ dc: -1
+ }, {
+ dr: 0,
+ dc: 1
+ },
+ // horizontal
+ {
+ dr: -1,
+ dc: -1
+ }, {
+ dr: -1,
+ dc: 1
+ },
+ // diagonal
+ {
+ dr: 1,
+ dc: -1
+ }, {
+ dr: 1,
+ dc: 1
+ } // diagonal
+ ];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ while (isOnBoard(r, c)) {
+ if (isOccupied(r, c)) {
+ if (isEnemyPiece(r, c)) {
+ addMove(r, c);
+ }
+ break;
+ }
+ addMove(r, c);
+ r += dir.dr;
+ c += dir.dc;
+ }
+ });
+ break;
+ case 'king':
+ // King moves (one square in any direction)
+ var directions = [{
+ dr: -1,
+ dc: -1
+ }, {
+ dr: -1,
+ dc: 0
+ }, {
+ dr: -1,
+ dc: 1
+ }, {
+ dr: 0,
+ dc: -1
+ }, {
+ dr: 0,
+ dc: 1
+ }, {
+ dr: 1,
+ dc: -1
+ }, {
+ dr: 1,
+ dc: 0
+ }, {
+ dr: 1,
+ dc: 1
+ }];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
+ addMove(r, c);
+ }
+ });
+ // Castling
+ if (!piece.hasMoved) {
+ // Kingside castling
+ if (!isOccupied(row, col + 1) && !isOccupied(row, col + 2) && isOccupied(row, col + 3) && !gameState.board[row][col + 3].hasMoved && gameState.board[row][col + 3].type === 'rook') {
+ addMove(row, col + 2);
+ }
+ // Queenside castling
+ if (!isOccupied(row, col - 1) && !isOccupied(row, col - 2) && !isOccupied(row, col - 3) && isOccupied(row, col - 4) && !gameState.board[row][col - 4].hasMoved && gameState.board[row][col - 4].type === 'rook') {
+ addMove(row, col - 2);
+ }
+ }
+ break;
+ }
+ // Filter out moves that would put the king in check
+ var validMoves = [];
+ for (var i = 0; i < moves.length; i++) {
+ var move = moves[i];
+ // Make a temporary move
+ var tempPiece = gameState.board[move.row][move.col];
+ gameState.board[move.row][move.col] = piece;
+ gameState.board[row][col] = null;
+ // Check if the move puts/leaves the king in check
+ var inCheck = isKingInCheck(piece.color);
+ // Undo the move
+ gameState.board[row][col] = piece;
+ gameState.board[move.row][move.col] = tempPiece;
+ if (!inCheck) {
+ validMoves.push(move);
+ }
+ }
+ return validMoves;
+}
+function isKingInCheck(color) {
+ // Find the king
+ var kingRow = -1;
+ var kingCol = -1;
+ for (var r = 0; r < 8; r++) {
+ for (var c = 0; c < 8; c++) {
+ var piece = gameState.board[r][c];
+ if (piece && piece.type === 'king' && piece.color === color) {
+ kingRow = r;
+ kingCol = c;
+ break;
+ }
+ }
+ if (kingRow !== -1) break;
+ }
+ // Check if any enemy piece can capture the king
+ for (var r = 0; r < 8; r++) {
+ for (var c = 0; c < 8; c++) {
+ var piece = gameState.board[r][c];
+ if (piece && piece.color !== color) {
+ // Get the enemy's valid moves (ignoring check)
+ var moves = getBasicMoves(piece);
+ // See if any of the moves can capture the king
+ for (var i = 0; i < moves.length; i++) {
+ if (moves[i].row === kingRow && moves[i].col === kingCol) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+function getBasicMoves(piece) {
+ var moves = [];
+ if (!piece) return moves;
+ function addMove(row, col) {
+ moves.push({
+ row: row,
+ col: col
+ });
+ }
+ function isOnBoard(row, col) {
+ return row >= 0 && row < 8 && col >= 0 && col < 8;
+ }
+ function isOccupied(row, col) {
+ return gameState.board[row][col] !== null;
+ }
+ function isEnemyPiece(row, col) {
+ return isOccupied(row, col) && gameState.board[row][col].color !== piece.color;
+ }
+ function isFriendlyPiece(row, col) {
+ return isOccupied(row, col) && gameState.board[row][col].color === piece.color;
+ }
+ var row = piece.row;
+ var col = piece.col;
+ switch (piece.type) {
+ case 'pawn':
+ var direction = piece.color === 'white' ? -1 : 1;
+ // Move forward one square
+ if (isOnBoard(row + direction, col) && !isOccupied(row + direction, col)) {
+ addMove(row + direction, col);
+ // Move forward two squares on first move
+ if (!piece.hasMoved && isOnBoard(row + 2 * direction, col) && !isOccupied(row + 2 * direction, col)) {
+ addMove(row + 2 * direction, col);
+ }
+ }
+ // Capture diagonally
+ if (isOnBoard(row + direction, col - 1) && isEnemyPiece(row + direction, col - 1)) {
+ addMove(row + direction, col - 1);
+ }
+ if (isOnBoard(row + direction, col + 1) && isEnemyPiece(row + direction, col + 1)) {
+ addMove(row + direction, col + 1);
+ }
+ break;
+ case 'rook':
+ // Horizontal and vertical directions
+ var directions = [{
+ dr: -1,
+ dc: 0
+ },
+ // up
+ {
+ dr: 1,
+ dc: 0
+ },
+ // down
+ {
+ dr: 0,
+ dc: -1
+ },
+ // left
+ {
+ dr: 0,
+ dc: 1
+ } // right
+ ];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ while (isOnBoard(r, c)) {
+ if (isOccupied(r, c)) {
+ if (isEnemyPiece(r, c)) {
+ addMove(r, c);
+ }
+ break;
+ }
+ addMove(r, c);
+ r += dir.dr;
+ c += dir.dc;
+ }
+ });
+ break;
+ case 'knight':
+ // Knight moves
+ var knightMoves = [{
+ dr: -2,
+ dc: -1
+ }, {
+ dr: -2,
+ dc: 1
+ }, {
+ dr: -1,
+ dc: -2
+ }, {
+ dr: -1,
+ dc: 2
+ }, {
+ dr: 1,
+ dc: -2
+ }, {
+ dr: 1,
+ dc: 2
+ }, {
+ dr: 2,
+ dc: -1
+ }, {
+ dr: 2,
+ dc: 1
+ }];
+ knightMoves.forEach(function (move) {
+ var r = row + move.dr;
+ var c = col + move.dc;
+ if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
+ addMove(r, c);
+ }
+ });
+ break;
+ case 'bishop':
+ // Diagonal directions
+ var directions = [{
+ dr: -1,
+ dc: -1
+ },
+ // up-left
+ {
+ dr: -1,
+ dc: 1
+ },
+ // up-right
+ {
+ dr: 1,
+ dc: -1
+ },
+ // down-left
+ {
+ dr: 1,
+ dc: 1
+ } // down-right
+ ];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ while (isOnBoard(r, c)) {
+ if (isOccupied(r, c)) {
+ if (isEnemyPiece(r, c)) {
+ addMove(r, c);
+ }
+ break;
+ }
+ addMove(r, c);
+ r += dir.dr;
+ c += dir.dc;
+ }
+ });
+ break;
+ case 'queen':
+ // Combine rook and bishop moves
+ var directions = [{
+ dr: -1,
+ dc: 0
+ }, {
+ dr: 1,
+ dc: 0
+ },
+ // vertical
+ {
+ dr: 0,
+ dc: -1
+ }, {
+ dr: 0,
+ dc: 1
+ },
+ // horizontal
+ {
+ dr: -1,
+ dc: -1
+ }, {
+ dr: -1,
+ dc: 1
+ },
+ // diagonal
+ {
+ dr: 1,
+ dc: -1
+ }, {
+ dr: 1,
+ dc: 1
+ } // diagonal
+ ];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ while (isOnBoard(r, c)) {
+ if (isOccupied(r, c)) {
+ if (isEnemyPiece(r, c)) {
+ addMove(r, c);
+ }
+ break;
+ }
+ addMove(r, c);
+ r += dir.dr;
+ c += dir.dc;
+ }
+ });
+ break;
+ case 'king':
+ // King moves (one square in any direction)
+ var directions = [{
+ dr: -1,
+ dc: -1
+ }, {
+ dr: -1,
+ dc: 0
+ }, {
+ dr: -1,
+ dc: 1
+ }, {
+ dr: 0,
+ dc: -1
+ }, {
+ dr: 0,
+ dc: 1
+ }, {
+ dr: 1,
+ dc: -1
+ }, {
+ dr: 1,
+ dc: 0
+ }, {
+ dr: 1,
+ dc: 1
+ }];
+ directions.forEach(function (dir) {
+ var r = row + dir.dr;
+ var c = col + dir.dc;
+ if (isOnBoard(r, c) && !isFriendlyPiece(r, c)) {
+ addMove(r, c);
+ }
+ });
+ break;
+ }
+ return moves;
+}
+function isCheckmate(color) {
+ if (!isKingInCheck(color)) return false;
+ // Check if any piece can make a valid move
+ for (var r = 0; r < 8; r++) {
+ for (var c = 0; c < 8; c++) {
+ var piece = gameState.board[r][c];
+ if (piece && piece.color === color) {
+ var validMoves = getValidMoves(piece);
+ if (validMoves.length > 0) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+function isStalemate(color) {
+ if (isKingInCheck(color)) return false;
+ // Check if any piece can make a valid move
+ for (var r = 0; r < 8; r++) {
+ for (var c = 0; c < 8; c++) {
+ var piece = gameState.board[r][c];
+ if (piece && piece.color === color) {
+ var validMoves = getValidMoves(piece);
+ if (validMoves.length > 0) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+function updateGameStatus() {
+ if (isCheckmate(gameState.currentTurn)) {
+ gameState.status = 'checkmate';
+ var winner = gameState.currentTurn === 'white' ? 'Black' : 'White';
+ statusText.setText(winner + ' wins by checkmate!');
+ LK.getSound('gameEnd').play();
+ // Update score if AI was played against
+ if (gameState.gameMode === 'ai') {
+ if (winner === 'White' && gameState.aiPlayer === 'black' || winner === 'Black' && gameState.aiPlayer === 'white') {
+ LK.setScore(LK.getScore() + 1);
+ }
+ }
+ return true;
+ } else if (isStalemate(gameState.currentTurn)) {
+ gameState.status = 'stalemate';
+ statusText.setText('Game drawn by stalemate!');
+ LK.getSound('gameEnd').play();
+ return true;
+ } else if (isKingInCheck(gameState.currentTurn)) {
+ gameState.status = 'check';
+ statusText.setText(gameState.currentTurn.charAt(0).toUpperCase() + gameState.currentTurn.slice(1) + ' is in check!');
+ LK.getSound('check').play();
+ } else {
+ gameState.status = 'playing';
+ statusText.setText('');
+ }
+ return false;
+}
+function updateTurnText() {
+ var turnName = gameState.currentTurn.charAt(0).toUpperCase() + gameState.currentTurn.slice(1);
+ turnText.setText(turnName + ' to move');
+}
+function movePiece(piece, targetRow, targetCol) {
+ var isCapture = gameState.board[targetRow][targetCol] !== null;
+ var capturedPiece = gameState.board[targetRow][targetCol];
+ var fromRow = piece.row;
+ var fromCol = piece.col;
+ // Handle castling
+ if (piece.type === 'king' && Math.abs(targetCol - fromCol) === 2) {
+ // Kingside castling
+ if (targetCol > fromCol) {
+ var rook = gameState.board[fromRow][7];
+ gameState.board[fromRow][5] = rook;
+ gameState.board[fromRow][7] = null;
+ rook.moveTo(fromRow, 5, 300);
+ }
+ // Queenside castling
+ else {
+ var rook = gameState.board[fromRow][0];
+ gameState.board[fromRow][3] = rook;
+ gameState.board[fromRow][0] = null;
+ rook.moveTo(fromRow, 3, 300);
+ }
+ }
+ // Handle en passant capture
+ if (piece.type === 'pawn' && Math.abs(targetCol - fromCol) === 1 && !isCapture) {
+ var enPassantRow = piece.color === 'white' ? targetRow + 1 : targetRow - 1;
+ capturedPiece = gameState.board[enPassantRow][targetCol];
+ gameState.board[enPassantRow][targetCol] = null;
+ if (capturedPiece) {
+ capturedPiece.parent.removeChild(capturedPiece);
+ }
+ isCapture = true;
+ }
+ // Update board array
+ gameState.board[fromRow][fromCol] = null;
+ if (capturedPiece) {
+ capturedPiece.parent.removeChild(capturedPiece);
+ }
+ gameState.board[targetRow][targetCol] = piece;
+ // Move the piece with animation
+ gameState.isAnimating = true;
+ piece.moveTo(targetRow, targetCol, 300);
+ // Play sound
+ if (isCapture) {
+ LK.getSound('capture').play();
+ } else {
+ LK.getSound('move').play();
+ }
+ // Handle pawn promotion (always to queen for simplicity)
+ if (piece.type === 'pawn' && (targetRow === 0 || targetRow === 7)) {
+ // Wait for the piece to finish moving
+ var promotionTimeout = LK.setTimeout(function () {
+ // Remove the pawn
+ piece.parent.removeChild(piece);
+ gameState.board[targetRow][targetCol] = null;
+ // Create a new queen
+ var queen = new Piece('queen', piece.color, targetRow, targetCol);
+ chessBoard.piecesLayer.addChild(queen);
+ gameState.board[targetRow][targetCol] = queen;
+ LK.clearTimeout(promotionTimeout);
+ }, 350);
+ }
+ // Update last move
+ gameState.lastMove = {
+ piece: piece,
+ fromRow: fromRow,
+ fromCol: fromCol,
+ toRow: targetRow,
+ toCol: targetCol
+ };
+ // Highlight the last move
+ var moveTimeout = LK.setTimeout(function () {
+ chessBoard.clearHighlights();
+ chessBoard.highlightTile(fromRow, fromCol, 'lastMoveTile');
+ chessBoard.highlightTile(targetRow, targetCol, 'lastMoveTile');
+ // Switch turns
+ gameState.currentTurn = gameState.currentTurn === 'white' ? 'black' : 'white';
+ updateTurnText();
+ // Check for check, checkmate, stalemate
+ var gameEnded = updateGameStatus();
+ gameState.isAnimating = false;
+ gameState.selectedPiece = null;
+ // If AI is playing and it's AI's turn
+ if (!gameEnded && gameState.gameMode === 'ai' && gameState.currentTurn === gameState.aiPlayer) {
+ makeAIMove();
+ }
+ LK.clearTimeout(moveTimeout);
+ }, 350);
+}
+function makeAIMove() {
+ var aiTimeout = LK.setTimeout(function () {
+ var allPossibleMoves = [];
+ // Collect all possible moves for AI pieces
+ for (var r = 0; r < 8; r++) {
+ for (var c = 0; c < 8; c++) {
+ var piece = gameState.board[r][c];
+ if (piece && piece.color === gameState.aiPlayer) {
+ var validMoves = getValidMoves(piece);
+ for (var i = 0; i < validMoves.length; i++) {
+ allPossibleMoves.push({
+ piece: piece,
+ move: validMoves[i]
+ });
+ }
+ }
+ }
+ }
+ if (allPossibleMoves.length > 0) {
+ var selectedMove;
+ // Basic AI difficulty levels
+ if (gameState.aiDifficulty === 1) {
+ // Easy: Random move
+ selectedMove = allPossibleMoves[Math.floor(Math.random() * allPossibleMoves.length)];
+ } else if (gameState.aiDifficulty === 2) {
+ // Medium: Prefer captures and checks
+ var captureMoves = allPossibleMoves.filter(function (moveObj) {
+ return gameState.board[moveObj.move.row][moveObj.move.col] !== null;
+ });
+ if (captureMoves.length > 0) {
+ selectedMove = captureMoves[Math.floor(Math.random() * captureMoves.length)];
+ } else {
+ selectedMove = allPossibleMoves[Math.floor(Math.random() * allPossibleMoves.length)];
+ }
+ } else {
+ // Hard: Prioritize captures by piece value
+ var bestValue = -1;
+ var bestMoves = [];
+ for (var i = 0; i < allPossibleMoves.length; i++) {
+ var moveObj = allPossibleMoves[i];
+ var targetPiece = gameState.board[moveObj.move.row][moveObj.move.col];
+ var moveValue = 0;
+ if (targetPiece) {
+ // Assign values to pieces
+ switch (targetPiece.type) {
+ case 'pawn':
+ moveValue = 1;
+ break;
+ case 'knight':
+ case 'bishop':
+ moveValue = 3;
+ break;
+ case 'rook':
+ moveValue = 5;
+ break;
+ case 'queen':
+ moveValue = 9;
+ break;
+ case 'king':
+ moveValue = 100;
+ break;
+ }
+ }
+ // Prioritize center control for pawns and knights
+ if (moveObj.piece.type === 'pawn' || moveObj.piece.type === 'knight') {
+ var centerDistance = Math.abs(moveObj.move.row - 3.5) + Math.abs(moveObj.move.col - 3.5);
+ moveValue += (4 - centerDistance) * 0.1;
+ }
+ if (moveValue > bestValue) {
+ bestValue = moveValue;
+ bestMoves = [moveObj];
+ } else if (moveValue === bestValue) {
+ bestMoves.push(moveObj);
+ }
+ }
+ if (bestMoves.length > 0) {
+ selectedMove = bestMoves[Math.floor(Math.random() * bestMoves.length)];
+ } else {
+ selectedMove = allPossibleMoves[Math.floor(Math.random() * allPossibleMoves.length)];
+ }
+ }
+ // Make the selected move
+ movePiece(selectedMove.piece, selectedMove.move.row, selectedMove.move.col);
+ }
+ LK.clearTimeout(aiTimeout);
+ }, 500);
+}
+// Game event handlers
+game.down = function (x, y, obj) {
+ if (gameState.isAnimating) return;
+ // Convert screen coordinates to board coordinates
+ var boardX = x - chessBoard.x;
+ var boardY = y - chessBoard.y;
+ var tile = chessBoard.getTileAt(boardX, boardY);
+ if (tile && gameState.selectedPiece) {
+ // Check if the clicked tile is a valid move
+ var isValidMove = false;
+ for (var i = 0; i < gameState.validMoves.length; i++) {
+ var move = gameState.validMoves[i];
+ if (move.row === tile.row && move.col === tile.col) {
+ isValidMove = true;
+ break;
+ }
+ }
+ if (isValidMove) {
+ // Move the piece
+ movePiece(gameState.selectedPiece, tile.row, tile.col);
+ return;
+ }
+ }
+ // Clear selection if clicking elsewhere
+ if (gameState.selectedPiece) {
+ chessBoard.clearHighlights();
+ gameState.selectedPiece = null;
+ }
+};
+// Game Mode Buttons
+var twoPlayerBtn = new Text2('Two Player', {
+ size: 50,
+ fill: 0xFFFFFF
+});
+twoPlayerBtn.anchor.set(0.5, 0);
+twoPlayerBtn.y = 2732 - 200;
+twoPlayerBtn.x = 2048 / 2 - 300;
+LK.gui.addChild(twoPlayerBtn);
+twoPlayerBtn.interactive = true;
+twoPlayerBtn.buttonMode = true;
+twoPlayerBtn.on('pointerdown', function () {
+ gameState.gameMode = 'twoPlayer';
+ gameState.aiPlayer = null;
+ LK.setScore(0);
+ initializeChessBoard();
+ updateTurnText();
+ chessBoard.clearHighlights();
+});
+var aiBtn = new Text2('Play vs AI', {
+ size: 50,
+ fill: 0xFFFFFF
+});
+aiBtn.anchor.set(0.5, 0);
+aiBtn.y = 2732 - 200;
+aiBtn.x = 2048 / 2 + 300;
+LK.gui.addChild(aiBtn);
+aiBtn.interactive = true;
+aiBtn.buttonMode = true;
+aiBtn.on('pointerdown', function () {
+ gameState.gameMode = 'ai';
+ gameState.aiPlayer = 'black';
+ LK.setScore(0);
+ initializeChessBoard();
+ updateTurnText();
+ chessBoard.clearHighlights();
+});
+// AI Difficulty Buttons
+var easyBtn = new Text2('Easy', {
+ size: 40,
+ fill: gameState.aiDifficulty === 1 ? "#ffff00" : "#aaaaaa"
+});
+easyBtn.anchor.set(0.5, 0);
+easyBtn.y = 2732 - 120;
+easyBtn.x = 2048 / 2 - 300;
+LK.gui.addChild(easyBtn);
+easyBtn.interactive = true;
+easyBtn.buttonMode = true;
+easyBtn.on('pointerdown', function () {
+ gameState.aiDifficulty = 1;
+ storage.aiDifficulty = 1;
+ easyBtn.style.fill = "#ffff00";
+ mediumBtn.style.fill = "#aaaaaa";
+ hardBtn.style.fill = "#aaaaaa";
+});
+var mediumBtn = new Text2('Medium', {
+ size: 40,
+ fill: gameState.aiDifficulty === 2 ? "#ffff00" : "#aaaaaa"
+});
+mediumBtn.anchor.set(0.5, 0);
+mediumBtn.y = 2732 - 120;
+mediumBtn.x = 2048 / 2;
+LK.gui.addChild(mediumBtn);
+mediumBtn.interactive = true;
+mediumBtn.buttonMode = true;
+mediumBtn.on('pointerdown', function () {
+ gameState.aiDifficulty = 2;
+ storage.aiDifficulty = 2;
+ easyBtn.style.fill = "#aaaaaa";
+ mediumBtn.style.fill = "#ffff00";
+ hardBtn.style.fill = "#aaaaaa";
+});
+var hardBtn = new Text2('Hard', {
+ size: 40,
+ fill: gameState.aiDifficulty === 3 ? "#ffff00" : "#aaaaaa"
+});
+hardBtn.anchor.set(0.5, 0);
+hardBtn.y = 2732 - 120;
+hardBtn.x = 2048 / 2 + 300;
+LK.gui.addChild(hardBtn);
+hardBtn.interactive = true;
+hardBtn.buttonMode = true;
+hardBtn.on('pointerdown', function () {
+ gameState.aiDifficulty = 3;
+ storage.aiDifficulty = 3;
+ easyBtn.style.fill = "#aaaaaa";
+ mediumBtn.style.fill = "#aaaaaa";
+ hardBtn.style.fill = "#ffff00";
+});
+// Update difficulty button colors based on current setting
+switch (gameState.aiDifficulty) {
+ case 1:
+ easyBtn.style.fill = "#ffff00";
+ mediumBtn.style.fill = "#aaaaaa";
+ hardBtn.style.fill = "#aaaaaa";
+ break;
+ case 2:
+ easyBtn.style.fill = "#aaaaaa";
+ mediumBtn.style.fill = "#ffff00";
+ hardBtn.style.fill = "#aaaaaa";
+ break;
+ case 3:
+ easyBtn.style.fill = "#aaaaaa";
+ mediumBtn.style.fill = "#aaaaaa";
+ hardBtn.style.fill = "#ffff00";
+ break;
+}
+// New Game button
+var newGameBtn = new Text2('New Game', {
+ size: 50,
+ fill: 0xFFFFFF
+});
+newGameBtn.anchor.set(0.5, 0);
+newGameBtn.y = 2732 - 280;
+newGameBtn.x = 2048 / 2;
+LK.gui.addChild(newGameBtn);
+newGameBtn.interactive = true;
+newGameBtn.buttonMode = true;
+newGameBtn.on('pointerdown', function () {
+ initializeChessBoard();
+ updateTurnText();
+});
+// Initialize the game
+initializeChessBoard();
+// Main game loop
+game.update = function () {
+ // Game update logic happens in event handlers and callbacks
+};
+// Play background music
+LK.playMusic('bgMusic', {
+ fade: {
+ start: 0,
+ end: 0.3,
+ duration: 1000
+ }
});
\ No newline at end of file