User prompt
tahta ve piyonları biraz daha büyüt gözüksünler daha iyi bide ppiyonların vs üstündeki şeylerin isimlerini kaldır,bide eğer bir taşı alıcak pozisyondaysan rakibin piyonunda yada vs şeyinde arkasında sarı yuvarlak olması yerine kırmızı yuvarlak olucak
User prompt
piyon vb olan şeyleri anlamak için heppsine bir görsel oluştur yada yap neyin ne olduğunu anlayalım
User prompt
bide siyah ppiyon vb şeyi alırken belirgin bir şey gözüksün yani bunu alabilirsin diye arkasında kırmızı renk falan bir şey çıksın
User prompt
sarı yuvarlıklar yani hareket etirme şeyinde tahtanın üzerinde çıkması gerekiyor ama en sağ altta çıkıyor bu sorunuda düzelt piyonu vb şeyi nereye gideeceğini gösterilsin tahtada düzgün bir şekilde
User prompt
Please fix the bug: 'Uncaught RangeError: Maximum call stack size exceeded' in or related to this line: 'var legalMoves = calculateLegalMoves(col, row);' Line Number: 279
User prompt
satranç piyonlarını vb şeylerini hareket ettiremeiyoturz haraket ettirilelim ve ilerlememe sorunu var onnuda düzelt hep aynı yerde kalıyor çalışmıyor
User prompt
biz beyazız ve karelere dokunduğumuzda önünde nerye gideceğini gösteren bir şey olsun ve oraya tıkaldığımıozda oryaa ilerler önceki yerinden gider ve sonra sıra ai siyah satrancınna gider ve oda oynadığında yine sıra bize gelir
User prompt
oynatamıyorum piyonları ve diğer şeyleri bide nereyee gideceğini göstermek için sarı küçük yuvarlak çıksın ve o küçük sarı şeye tıkladığımızda oraya ilerler bide tıkladığımda da arkadaki görünnen satranç seti kayboluyor bu sorunuda düzelt
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'x')' in or related to this line: 'var isInCheck = isSquareAttacked(kingPos.x, kingPos.y, opponentColor);' Line Number: 442
Code edit (1 edits merged)
Please save this source code
User prompt
Chess Master
Initial prompt
mükemmel bir satranç oyunu yap
/****
* 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
});