User prompt
Şahlar birbirlerine 1 kare yaklaşamasınlar yani birbirlerine 1 kare hep uzaklıkta olsunlar.
User prompt
Taşları hareket ettirdiğimizde tas soundu çalsın.
User prompt
Şahlar birbirlerine 3 kare yatay veya dikey yaklaşamasınlar
User prompt
Oyuna kazanma kaybetme ekle.Satrançta ki kurallardaki gibi kazanma ve kaybetme kuralları olsun.
User prompt
Rakip yapay zekanın önemli bir taşı tehdit altındaysa o önemli taşı kaçırsın
User prompt
Her iki tarafın kendi süresi olsun
User prompt
Süreyi birazdaha sağ kaydır
User prompt
Süreyi biraz sağa kaydır
User prompt
Dakika yazma yerlerini değiştir.
User prompt
Dakikaların yazma yerlerini değiştir benim süremi benim tarafıma onun süresini onun tarafında boş bir yere koy.
User prompt
Her iki tarafında 10 dakika süresi olsun her hamle oynadığında süre bir sonrakinin süresini başlatsın kendi süresi dursun.
User prompt
Taşlara dokunduğunda gitmek istediğin yeri seçerek direk gitmesini sağla. Sürüklemek zorunda kalmasın
User prompt
Her iki tarafında piyonların boyutunu çok az küçült.
User prompt
Her iki tarafın şahlarının boyutunu büyütm
User prompt
Yapay zeka benim hamlelerime bakarak benim gibi oynamaya çalışsın ve yapay zeka hemen oynamak yerine biraz düşünerek oynasın.
User prompt
Rakip yapay zeka daha zeki olsun
User prompt
Taşların oynayabileceği kareleri gösteren kare göstergeyi yuvarlak yap ve tam ortaya koy.
User prompt
Bana taşların görünümlerini asetlere ekle
User prompt
Renkler satranç renklerine benzesin
User prompt
Rakibi yapay zeka oynasın
User prompt
Please fix the bug: 'Uncaught RangeError: Maximum call stack size exceeded' in or related to this line: 'var moves = getLegalMoves(p, x, y, true);' Line Number: 507
Code edit (1 edits merged)
Please save this source code
Initial prompt
Chess Master: Satranç
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// --- ChessBoard Class ---
var ChessBoard = Container.expand(function () {
var self = Container.call(this);
// 8x8 array of ChessPiece or null
self.squares = [];
for (var y = 0; y < 8; y++) {
self.squares[y] = [];
for (var x = 0; x < 8; x++) {
self.squares[y][x] = null;
}
}
// Draw board squares
self.squareNodes = [];
for (var y = 0; y < 8; y++) {
self.squareNodes[y] = [];
for (var x = 0; x < 8; x++) {
var isLight = (x + y) % 2 === 0;
var color = isLight ? 0xf0d9b5 : 0xb58863;
var assetId = 'board_' + (isLight ? 'light' : 'dark');
var node = LK.getAsset(assetId, {
anchorX: 0,
anchorY: 0,
x: boardOriginX + x * squareSize,
y: boardOriginY + y * squareSize
});
self.addChild(node);
self.squareNodes[y][x] = node;
}
}
// Highlight squares (for moves)
self.highlightNodes = [];
for (var i = 0; i < 64; i++) {
var highlightId = 'highlight_' + i;
var node = LK.getAsset(highlightId, {
anchorX: 0,
anchorY: 0,
x: -1000,
y: -1000
}); // Hide initially
node.alpha = 0.25;
self.addChild(node);
self.highlightNodes[i] = node;
}
// Place pieces in starting position
self.reset = function () {
// Remove all pieces
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 8; x++) {
if (self.squares[y][x]) {
self.squares[y][x].destroy();
self.squares[y][x] = null;
}
}
}
// Place pawns
for (var x = 0; x < 8; x++) {
var wp = new ChessPiece();
wp.init('pawn', 'white', x, 6);
wp.moveTo(x, 6, false);
self.addChild(wp);
self.squares[6][x] = wp;
var bp = new ChessPiece();
bp.init('pawn', 'black', x, 1);
bp.moveTo(x, 1, false);
self.addChild(bp);
self.squares[1][x] = bp;
}
// Place other pieces
var order = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'];
for (var x = 0; x < 8; x++) {
var w = new ChessPiece();
w.init(order[x], 'white', x, 7);
w.moveTo(x, 7, false);
self.addChild(w);
self.squares[7][x] = w;
var b = new ChessPiece();
b.init(order[x], 'black', x, 0);
b.moveTo(x, 0, false);
self.addChild(b);
self.squares[0][x] = b;
}
};
// Remove all highlights
self.clearHighlights = function () {
for (var i = 0; i < 64; i++) {
self.highlightNodes[i].x = -1000;
self.highlightNodes[i].y = -1000;
}
};
// Highlight given squares (array of {x, y})
self.showHighlights = function (squares) {
self.clearHighlights();
for (var i = 0; i < squares.length; i++) {
var idx = squares[i].y * 8 + squares[i].x;
var node = self.highlightNodes[idx];
node.x = boardOriginX + squares[i].x * squareSize;
node.y = boardOriginY + squares[i].y * squareSize;
}
};
// Get piece at board position
self.getPiece = function (x, y) {
if (x < 0 || x > 7 || y < 0 || y > 7) return null;
return self.squares[y][x];
};
// Set piece at board position
self.setPiece = function (x, y, piece) {
self.squares[y][x] = piece;
};
// Remove piece at board position
self.removePiece = function (x, y) {
var p = self.squares[y][x];
if (p) {
p.destroy();
self.squares[y][x] = null;
}
};
return self;
});
// --- ChessPiece Class ---
var ChessPiece = Container.expand(function () {
var self = Container.call(this);
// Properties
self.type = null; // 'pawn', 'rook', 'knight', 'bishop', 'queen', 'king'
self.color = null; // 'white' or 'black'
self.boardX = 0; // 0-7
self.boardY = 0; // 0-7
self.hasMoved = false; // For castling/en passant
self.promoted = false; // For pawn promotion
// Asset
self.pieceAsset = null;
// Set piece type and color, and create asset
self.init = function (type, color, boardX, boardY) {
self.type = type;
self.color = color;
self.boardX = boardX;
self.boardY = boardY;
self.hasMoved = false;
self.promoted = false;
// Remove old asset if any
if (self.pieceAsset) {
self.removeChild(self.pieceAsset);
}
// Use simple shapes for pieces (different color for each type)
var colorMap = {
'white': {
'pawn': 0xffffff,
'rook': 0xe0e0e0,
'knight': 0xc0c0c0,
'bishop': 0xa0a0a0,
'queen': 0xccccff,
'king': 0xffe0cc
},
'black': {
'pawn': 0x222222,
'rook': 0x444444,
'knight': 0x666666,
'bishop': 0x888888,
'queen': 0x444488,
'king': 0x886644
}
};
var shape = self.type === 'pawn' || self.type === 'bishop' ? 'ellipse' : 'box';
var assetId = self.color + '_' + self.type;
var assetColor = colorMap[self.color][self.type];
var size = pieceSize;
self.pieceAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add a crown for promoted pawns
if (self.promoted && self.type === 'queen') {
// Overlay a small yellow ellipse as a "crown"
var crown = LK.getAsset('crown_' + self.color, {
anchorX: 0.5,
anchorY: 0.5,
y: -size * 0.3
});
self.addChild(crown);
}
};
// Move piece to board position (with optional animation)
self.moveTo = function (bx, by, animate) {
self.boardX = bx;
self.boardY = by;
var targetX = boardOriginX + bx * squareSize + squareSize / 2;
var targetY = boardOriginY + by * squareSize + squareSize / 2;
if (animate) {
tween(self, {
x: targetX,
y: targetY
}, {
duration: 180,
easing: tween.cubicOut
});
} else {
self.x = targetX;
self.y = targetY;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// We need tween for piece movement animations
// --- Board and Piece Sizes ---
var boardSize = Math.min(2048, 2048); // Square board, fit width
var squareSize = Math.floor(boardSize / 8);
var pieceSize = Math.floor(squareSize * 0.8);
var boardOriginX = Math.floor((2048 - squareSize * 8) / 2);
var boardOriginY = Math.floor((2732 - squareSize * 8) / 2);
// --- Game State ---
var board = new ChessBoard();
game.addChild(board);
board.reset();
var currentTurn = 'white'; // 'white' or 'black'
var selectedPiece = null;
var legalMoves = []; // Array of {x, y, special}
var lastMove = null; // {from: {x,y}, to: {x,y}, piece, captured, special}
var enPassantTarget = null; // {x, y} or null
var halfmoveClock = 0; // For 50-move rule
var fullmoveNumber = 1;
var gameEnded = false;
// --- GUI: Turn Display ---
var turnText = new Text2('White to move', {
size: 90,
fill: "#fff"
});
turnText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnText);
// --- GUI: Promotion Popup ---
var promotionPopup = null;
// --- Helper Functions ---
// Convert screen (x, y) to board (bx, by)
function screenToBoard(x, y) {
var bx = Math.floor((x - boardOriginX) / squareSize);
var by = Math.floor((y - boardOriginY) / squareSize);
if (bx < 0 || bx > 7 || by < 0 || by > 7) return null;
return {
x: bx,
y: by
};
}
// Convert board (bx, by) to screen (x, y) (center of square)
function boardToScreen(bx, by) {
return {
x: boardOriginX + bx * squareSize + squareSize / 2,
y: boardOriginY + by * squareSize + squareSize / 2
};
}
// Is (x, y) on the board?
function isOnBoard(x, y) {
return x >= 0 && x < 8 && y >= 0 && y < 8;
}
// Get all legal moves for a piece at (x, y)
function getLegalMoves(piece, x, y, ignoreCheck) {
var moves = [];
if (!piece) return moves;
var color = piece.color;
var opp = color === 'white' ? 'black' : 'white';
// Directions for sliding pieces
var dirs = {
'rook': [[1, 0], [-1, 0], [0, 1], [0, -1]],
'bishop': [[1, 1], [1, -1], [-1, 1], [-1, -1]],
'queen': [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
};
// Pawn moves
if (piece.type === 'pawn') {
var dir = color === 'white' ? -1 : 1;
// Forward
if (isOnBoard(x, y + dir) && !board.getPiece(x, y + dir)) {
moves.push({
x: x,
y: y + dir
});
// Double move from start
if (!piece.hasMoved && isOnBoard(x, y + 2 * dir) && !board.getPiece(x, y + 2 * dir)) {
moves.push({
x: x,
y: y + 2 * dir,
special: 'double'
});
}
}
// Captures
for (var dx = -1; dx <= 1; dx += 2) {
var tx = x + dx,
ty = y + dir;
if (isOnBoard(tx, ty)) {
var target = board.getPiece(tx, ty);
if (target && target.color === opp) {
moves.push({
x: tx,
y: ty
});
}
}
}
// En passant
if (enPassantTarget) {
if (Math.abs(enPassantTarget.x - x) === 1 && enPassantTarget.y === y + dir) {
moves.push({
x: enPassantTarget.x,
y: enPassantTarget.y,
special: 'enpassant'
});
}
}
}
// Knight moves
else if (piece.type === 'knight') {
var knightDeltas = [[1, 2], [2, 1], [-1, 2], [-2, 1], [1, -2], [2, -1], [-1, -2], [-2, -1]];
for (var i = 0; i < knightDeltas.length; i++) {
var dx = knightDeltas[i][0],
dy = knightDeltas[i][1];
var tx = x + dx,
ty = y + dy;
if (isOnBoard(tx, ty)) {
var target = board.getPiece(tx, ty);
if (!target || target.color === opp) {
moves.push({
x: tx,
y: ty
});
}
}
}
}
// King moves (including castling)
else if (piece.type === 'king') {
// Prevent infinite recursion: when ignoreCheck is true, do NOT generate king moves
if (ignoreCheck) {
// Do not generate king moves when ignoreCheck is true (used for attack detection)
// This prevents infinite recursion between isInCheck and getLegalMoves
} else {
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
if (dx === 0 && dy === 0) continue;
var tx = x + dx,
ty = y + dy;
if (isOnBoard(tx, ty)) {
var target = board.getPiece(tx, ty);
if (!target || target.color === opp) {
moves.push({
x: tx,
y: ty
});
}
}
}
}
// Castling
if (!piece.hasMoved && !isInCheck(color)) {
// Kingside
if (canCastle(color, 'kingside')) {
moves.push({
x: x + 2,
y: y,
special: 'castle_kingside'
});
}
// Queenside
if (canCastle(color, 'queenside')) {
moves.push({
x: x - 2,
y: y,
special: 'castle_queenside'
});
}
}
}
}
// Sliding pieces
else if (piece.type === 'rook' || piece.type === 'bishop' || piece.type === 'queen') {
var directions = dirs[piece.type];
for (var d = 0; d < directions.length; d++) {
var dx = directions[d][0],
dy = directions[d][1];
var tx = x + dx,
ty = y + dy;
while (isOnBoard(tx, ty)) {
var target = board.getPiece(tx, ty);
if (!target) {
moves.push({
x: tx,
y: ty
});
} else {
if (target.color === opp) {
moves.push({
x: tx,
y: ty
});
}
break;
}
tx += dx;
ty += dy;
}
}
}
// Remove moves that leave king in check (unless ignoreCheck)
if (!ignoreCheck) {
var filtered = [];
for (var i = 0; i < moves.length; i++) {
var m = moves[i];
if (!wouldLeaveKingInCheck(piece, x, y, m.x, m.y, m.special)) {
filtered.push(m);
}
}
return filtered;
}
return moves;
}
// Would moving piece at (x, y) to (tx, ty) leave own king in check?
function wouldLeaveKingInCheck(piece, x, y, tx, ty, special) {
// Simulate move
var origPiece = board.getPiece(tx, ty);
var origEnPassant = enPassantTarget;
var origHasMoved = piece.hasMoved;
var origFrom = board.squares[y][x];
var origTo = board.squares[ty][tx];
// Remove captured piece
if (special === 'enpassant') {
var dir = piece.color === 'white' ? -1 : 1;
var capY = ty - dir;
var capPiece = board.getPiece(tx, capY);
board.squares[capY][tx] = null;
}
board.squares[y][x] = null;
board.squares[ty][tx] = piece;
// For castling, move rook as well
var rookMoved = null,
rookFrom = null,
rookTo = null;
if (special === 'castle_kingside') {
var row = piece.color === 'white' ? 7 : 0;
rookFrom = board.getPiece(7, row);
rookTo = board.getPiece(5, row);
board.squares[row][7] = null;
board.squares[row][5] = rookFrom;
}
if (special === 'castle_queenside') {
var row = piece.color === 'white' ? 7 : 0;
rookFrom = board.getPiece(0, row);
rookTo = board.getPiece(3, row);
board.squares[row][0] = null;
board.squares[row][3] = rookFrom;
}
var inCheck = isInCheck(piece.color);
// Undo move
board.squares[y][x] = origFrom;
board.squares[ty][tx] = origTo;
if (special === 'enpassant') {
var dir = piece.color === 'white' ? -1 : 1;
var capY = ty - dir;
board.squares[capY][tx] = origPiece;
}
if (special === 'castle_kingside') {
var row = piece.color === 'white' ? 7 : 0;
board.squares[row][7] = rookFrom;
board.squares[row][5] = null;
}
if (special === 'castle_queenside') {
var row = piece.color === 'white' ? 7 : 0;
board.squares[row][0] = rookFrom;
board.squares[row][3] = null;
}
piece.hasMoved = origHasMoved;
enPassantTarget = origEnPassant;
return inCheck;
}
// Is color's king in check?
function isInCheck(color) {
var kingPos = findKing(color);
if (!kingPos) return false;
var opp = color === 'white' ? 'black' : 'white';
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 8; x++) {
var p = board.getPiece(x, y);
if (p && p.color === opp) {
var moves = getLegalMoves(p, x, y, true);
for (var i = 0; i < moves.length; i++) {
if (moves[i].x === kingPos.x && moves[i].y === kingPos.y) {
return true;
}
}
}
}
}
return false;
}
// Find king of color
function findKing(color) {
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 8; x++) {
var p = board.getPiece(x, y);
if (p && p.type === 'king' && p.color === color) {
return {
x: x,
y: y
};
}
}
}
return null;
}
// Can color castle on side ('kingside' or 'queenside')?
function canCastle(color, side) {
var row = color === 'white' ? 7 : 0;
var king = board.getPiece(4, row);
if (!king || king.hasMoved) return false;
if (side === 'kingside') {
var rook = board.getPiece(7, row);
if (!rook || rook.type !== 'rook' || rook.hasMoved) return false;
// Squares between must be empty
if (board.getPiece(5, row) || board.getPiece(6, row)) return false;
// Squares king passes through must not be attacked
if (isAttacked(5, row, color) || isAttacked(6, row, color)) return false;
return true;
}
if (side === 'queenside') {
var rook = board.getPiece(0, row);
if (!rook || rook.type !== 'rook' || rook.hasMoved) return false;
if (board.getPiece(1, row) || board.getPiece(2, row) || board.getPiece(3, row)) return false;
if (isAttacked(2, row, color) || isAttacked(3, row, color)) return false;
return true;
}
return false;
}
// Is square (x, y) attacked by opponent of color?
function isAttacked(x, y, color) {
var opp = color === 'white' ? 'black' : 'white';
for (var yy = 0; yy < 8; yy++) {
for (var xx = 0; xx < 8; xx++) {
var p = board.getPiece(xx, yy);
if (p && p.color === opp) {
var moves = getLegalMoves(p, xx, yy, true);
for (var i = 0; i < moves.length; i++) {
if (moves[i].x === x && moves[i].y === y) {
return true;
}
}
}
}
}
return false;
}
// Get all legal moves for color
function getAllLegalMoves(color) {
var moves = [];
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 8; x++) {
var p = board.getPiece(x, y);
if (p && p.color === color) {
var pieceMoves = getLegalMoves(p, x, y, false);
for (var i = 0; i < pieceMoves.length; i++) {
moves.push({
from: {
x: x,
y: y
},
to: {
x: pieceMoves[i].x,
y: pieceMoves[i].y
},
special: pieceMoves[i].special
});
}
}
}
}
return moves;
}
// Is the game over? Returns {over: true/false, result: 'checkmate'/'stalemate'/'draw', winner: 'white'/'black'/null}
function checkGameEnd() {
var moves = getAllLegalMoves(currentTurn);
if (moves.length === 0) {
if (isInCheck(currentTurn)) {
return {
over: true,
result: 'checkmate',
winner: currentTurn === 'white' ? 'black' : 'white'
};
} else {
return {
over: true,
result: 'stalemate',
winner: null
};
}
}
// 50-move rule
if (halfmoveClock >= 100) {
return {
over: true,
result: 'draw',
winner: null
};
}
// Insufficient material (only kings)
var onlyKings = true;
for (var y = 0; y < 8; y++) {
for (var x = 0; x < 8; x++) {
var p = board.getPiece(x, y);
if (p && p.type !== 'king') onlyKings = false;
}
}
if (onlyKings) {
return {
over: true,
result: 'draw',
winner: null
};
}
return {
over: false
};
}
// --- Promotion Popup ---
function showPromotionPopup(piece, toX, toY, onSelect) {
if (promotionPopup) {
promotionPopup.destroy();
promotionPopup = null;
}
promotionPopup = new Container();
var popupW = squareSize * 4;
var popupH = squareSize * 1.2;
var popupX = boardOriginX + (toX - 1) * squareSize;
var popupY = boardOriginY + toY * squareSize - popupH / 2;
var bg = LK.getAsset('promotion_bg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
bg.alpha = 0.95;
promotionPopup.addChild(bg);
var types = ['queen', 'rook', 'bishop', 'knight'];
for (var i = 0; i < types.length; i++) {
var t = types[i];
var tempPiece = new ChessPiece();
tempPiece.init(t, piece.color, 0, 0);
tempPiece.x = squareSize * (i + 0.5);
tempPiece.y = popupH / 2;
tempPiece.pieceAsset.width = pieceSize * 0.9;
tempPiece.pieceAsset.height = pieceSize * 0.9;
(function (type) {
tempPiece.down = function (x, y, obj) {
if (promotionPopup) {
onSelect(type);
promotionPopup.destroy();
promotionPopup = null;
}
};
})(t);
promotionPopup.addChild(tempPiece);
}
promotionPopup.x = popupX;
promotionPopup.y = popupY;
game.addChild(promotionPopup);
}
// --- Piece Dragging ---
var draggingPiece = null;
var dragOffsetX = 0,
dragOffsetY = 0;
var dragLegalMoves = [];
// --- Event Handlers ---
// Handle touch/mouse down
game.down = function (x, y, obj) {
if (gameEnded) return;
if (promotionPopup) return; // Block input during promotion
var pos = screenToBoard(x, y);
if (!pos) return;
var p = board.getPiece(pos.x, pos.y);
if (p && p.color === currentTurn) {
selectedPiece = p;
draggingPiece = p;
dragLegalMoves = getLegalMoves(p, pos.x, pos.y, false);
board.showHighlights(dragLegalMoves);
// Offset for dragging
dragOffsetX = x - p.x;
dragOffsetY = y - p.y;
// Bring to front
p.parent.removeChild(p);
game.addChild(p);
}
};
// Handle touch/mouse move
game.move = function (x, y, obj) {
if (gameEnded) return;
if (promotionPopup) return;
if (draggingPiece) {
draggingPiece.x = x - dragOffsetX;
draggingPiece.y = y - dragOffsetY;
}
};
// Handle touch/mouse up
game.up = function (x, y, obj) {
if (gameEnded) return;
if (promotionPopup) return;
if (!draggingPiece) {
board.clearHighlights();
selectedPiece = null;
return;
}
var p = draggingPiece;
var fromX = p.boardX,
fromY = p.boardY;
var pos = screenToBoard(x, y);
var moved = false;
if (pos) {
// Is this a legal move?
for (var i = 0; i < dragLegalMoves.length; i++) {
var m = dragLegalMoves[i];
if (m.x === pos.x && m.y === pos.y) {
// Move piece
doMove(p, fromX, fromY, m.x, m.y, m.special);
moved = true;
break;
}
}
}
if (!moved) {
// Snap back
p.moveTo(fromX, fromY, true);
}
board.clearHighlights();
selectedPiece = null;
draggingPiece = null;
dragLegalMoves = [];
};
// --- Move Execution ---
function doMove(piece, fromX, fromY, toX, toY, special) {
var opp = piece.color === 'white' ? 'black' : 'white';
var captured = null;
var isPawnMove = piece.type === 'pawn';
var isCapture = false;
// Handle en passant
if (special === 'enpassant') {
var dir = piece.color === 'white' ? -1 : 1;
var capY = toY - dir;
captured = board.getPiece(toX, capY);
board.removePiece(toX, capY);
isCapture = true;
}
// Handle castling
if (special === 'castle_kingside') {
var row = piece.color === 'white' ? 7 : 0;
var rook = board.getPiece(7, row);
board.setPiece(5, row, rook);
board.setPiece(7, row, null);
rook.moveTo(5, row, true);
rook.hasMoved = true;
}
if (special === 'castle_queenside') {
var row = piece.color === 'white' ? 7 : 0;
var rook = board.getPiece(0, row);
board.setPiece(3, row, rook);
board.setPiece(0, row, null);
rook.moveTo(3, row, true);
rook.hasMoved = true;
}
// Remove captured piece
var target = board.getPiece(toX, toY);
if (target && target.color !== piece.color) {
captured = target;
board.removePiece(toX, toY);
isCapture = true;
}
// Move piece
board.setPiece(fromX, fromY, null);
board.setPiece(toX, toY, piece);
piece.moveTo(toX, toY, true);
piece.hasMoved = true;
// Pawn promotion
if (piece.type === 'pawn' && (toY === 0 || toY === 7)) {
showPromotionPopup(piece, toX, toY, function (newType) {
piece.type = newType;
piece.promoted = newType === 'queen';
piece.init(newType, piece.color, toX, toY);
endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture);
});
return;
}
endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture);
}
function endTurn(piece, fromX, fromY, toX, toY, special, captured, isPawnMove, isCapture) {
// Update en passant
if (piece.type === 'pawn' && Math.abs(toY - fromY) === 2) {
enPassantTarget = {
x: toX,
y: (fromY + toY) / 2
};
} else {
enPassantTarget = null;
}
// Update halfmove clock
if (isPawnMove || isCapture) {
halfmoveClock = 0;
} else {
halfmoveClock++;
}
// Update fullmove number
if (currentTurn === 'black') {
fullmoveNumber++;
}
// Save last move
lastMove = {
from: {
x: fromX,
y: fromY
},
to: {
x: toX,
y: toY
},
piece: piece,
captured: captured,
special: special
};
// Switch turn
currentTurn = currentTurn === 'white' ? 'black' : 'white';
turnText.setText((currentTurn === 'white' ? 'White' : 'Black') + ' to move');
// Check for game end
var end = checkGameEnd();
if (end.over) {
gameEnded = true;
if (end.result === 'checkmate') {
LK.effects.flashScreen(0x00ff00, 800);
LK.showYouWin(end.winner === 'white' ? 'White wins by checkmate!' : 'Black wins by checkmate!');
} else if (end.result === 'stalemate') {
LK.effects.flashScreen(0xffff00, 800);
LK.showYouWin('Draw by stalemate');
} else if (end.result === 'draw') {
LK.effects.flashScreen(0xffff00, 800);
LK.showYouWin('Draw');
}
}
}
// --- Game Update ---
game.update = function () {
// No per-frame logic needed for chess
};
// --- Reset on Game Over ---
LK.on('gameover', function () {
// Reset everything
board.reset();
currentTurn = 'white';
selectedPiece = null;
legalMoves = [];
lastMove = null;
enPassantTarget = null;
halfmoveClock = 0;
fullmoveNumber = 1;
gameEnded = false;
turnText.setText('White to move');
if (promotionPopup) {
promotionPopup.destroy();
promotionPopup = null;
}
}); ===================================================================
--- original.js
+++ change.js
@@ -343,42 +343,48 @@
}
}
// King moves (including castling)
else if (piece.type === 'king') {
- for (var dx = -1; dx <= 1; dx++) {
- for (var dy = -1; dy <= 1; dy++) {
- if (dx === 0 && dy === 0) continue;
- var tx = x + dx,
- ty = y + dy;
- if (isOnBoard(tx, ty)) {
- var target = board.getPiece(tx, ty);
- if (!target || target.color === opp) {
- moves.push({
- x: tx,
- y: ty
- });
+ // Prevent infinite recursion: when ignoreCheck is true, do NOT generate king moves
+ if (ignoreCheck) {
+ // Do not generate king moves when ignoreCheck is true (used for attack detection)
+ // This prevents infinite recursion between isInCheck and getLegalMoves
+ } else {
+ for (var dx = -1; dx <= 1; dx++) {
+ for (var dy = -1; dy <= 1; dy++) {
+ if (dx === 0 && dy === 0) continue;
+ var tx = x + dx,
+ ty = y + dy;
+ if (isOnBoard(tx, ty)) {
+ var target = board.getPiece(tx, ty);
+ if (!target || target.color === opp) {
+ moves.push({
+ x: tx,
+ y: ty
+ });
+ }
}
}
}
- }
- // Castling
- if (!piece.hasMoved && !isInCheck(color)) {
- // Kingside
- if (canCastle(color, 'kingside')) {
- moves.push({
- x: x + 2,
- y: y,
- special: 'castle_kingside'
- });
+ // Castling
+ if (!piece.hasMoved && !isInCheck(color)) {
+ // Kingside
+ if (canCastle(color, 'kingside')) {
+ moves.push({
+ x: x + 2,
+ y: y,
+ special: 'castle_kingside'
+ });
+ }
+ // Queenside
+ if (canCastle(color, 'queenside')) {
+ moves.push({
+ x: x - 2,
+ y: y,
+ special: 'castle_queenside'
+ });
+ }
}
- // Queenside
- if (canCastle(color, 'queenside')) {
- moves.push({
- x: x - 2,
- y: y,
- special: 'castle_queenside'
- });
- }
}
}
// Sliding pieces
else if (piece.type === 'rook' || piece.type === 'bishop' || piece.type === 'queen') {