User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 803
User prompt
Please fix the following JavaScript ReferenceError in my chess game: Error: 'ReferenceError: getRawMoves is not defined' at line: var moves = getRawMoves(piece, row, col); Your task: - Insert a global function named getRawMoves that defines all legal moves for each chess piece. - Place this function at the correct scope so that it is available where var moves = getRawMoves(piece, row, col) is called. - Confirm that after adding this function, the ReferenceError is gone and the code runs without crashing. - After inserting the function, test a piece move to verify the function actually works. - If necessary, refactor the code to make sure getRawMoves is globally visible and accessible. Here is a simple template you must include inside the global scope: ```js function getRawMoves(piece, row, col) { let moves = []; const type = piece.type; switch (type) { case 'pawn': let dir = piece.color === 'white' ? -1 : 1; moves.push([row + dir, col]); moves.push([row + dir, col - 1]); moves.push([row + dir, col + 1]); break; case 'rook': for (let r=0; r<8; r++) if(r !== row) moves.push([r,col]); for (let c=0; c<8; c++) if(c !== col) moves.push([row,c]); break; case 'knight': const jumps = [ [row+2,col+1],[row+2,col-1],[row-2,col+1],[row-2,col-1], [row+1,col+2],[row+1,col-2],[row-1,col+2],[row-1,col-2] ]; moves.push(...jumps); break; case 'bishop': for (let i=1;i<8;i++){ moves.push([row+i,col+i]); moves.push([row-i,col-i]); moves.push([row+i,col-i]); moves.push([row-i,col+i]); } break; case 'queen': for (let r=0; r<8; r++) if(r !== row) moves.push([r,col]); for (let c=0; c<8; c++) if(c !== col) moves.push([row,c]); for (let i=1;i<8;i++){ moves.push([row+i,col+i]); moves.push([row-i,col-i]); moves.push([row+i,col-i]); moves.push([row-i,col+i]); } break; case 'king': for (let dr=-1; dr<=1; dr++){ for (let dc=-1; dc<=1; dc++){ if(dr!==0 || dc!==0) moves.push([row+dr,col+dc]); } } break; } return moves; }
User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 820
User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 820
User prompt
Please add the following missing function to my JavaScript chess code to fix the error 'ReferenceError: getRawMoves is not defined': ```js function getRawMoves(piece, row, col) { let moves = []; const type = piece.type; switch (type) { case 'pawn': // Pawn: move forward 1 (no capture), optionally 2 if on starting rank // capture diagonally let dir = piece.color === 'white' ? -1 : 1; moves.push([row + dir, col]); if ((piece.color === 'white' && row === 6) || (piece.color === 'black' && row === 1)) { moves.push([row + 2*dir, col]); } moves.push([row + dir, col - 1]); moves.push([row + dir, col + 1]); break; case 'rook': // rook: horizontal and vertical in all directions for (let r = 0; r < 8; r++) { if (r !== row) moves.push([r, col]); } for (let c = 0; c < 8; c++) { if (c !== col) moves.push([row, c]); } break; case 'knight': // knight: L-shaped const knightMoves = [ [row+2,col+1], [row+2,col-1], [row-2,col+1], [row-2,col-1], [row+1,col+2], [row+1,col-2], [row-1,col+2], [row-1,col-2], ]; moves.push(...knightMoves); break; case 'bishop': // bishop: diagonals for (let i=1; i<8; i++) { moves.push([row+i, col+i]); moves.push([row-i, col-i]); moves.push([row+i, col-i]); moves.push([row-i, col+i]); } break; case 'queen': // queen: rook + bishop for (let r = 0; r < 8; r++) { if (r !== row) moves.push([r, col]); } for (let c = 0; c < 8; c++) { if (c !== col) moves.push([row, c]); } for (let i=1; i<8; i++) { moves.push([row+i, col+i]); moves.push([row-i, col-i]); moves.push([row+i, col-i]); moves.push([row-i, col+i]); } break; case 'king': // king: one square any direction for (let dr=-1; dr<=1; dr++) { for (let dc=-1; dc<=1; dc++) { if (dr !== 0 || dc !== 0) moves.push([row+dr,col+dc]); } } break; } return moves; }
User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 820
User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 820
User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 820
User prompt
Please fix the bug: 'ReferenceError: getRawMoves is not defined' in or related to this line: 'var moves = getRawMoves(piece, row, col);' Line Number: 820
User prompt
Game ends while there is no check fix this
User prompt
Rakip taşı ilerlerken animasyon olsun dedim ama geldiği yönden değil rastgele yönden geliyor bunu düzelt taş neredeyse o anda olduğu yerden ilerlesin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Rakip (ai) bizim taşımızı yediğinde taşımız yok olmuyor bunu düzelt
User prompt
Daha smooth animasyonlar koy ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Oyunuc ve ai sırası geldiğinde sadece 1 hamle yapabilir
User prompt
Ai hamle yaparken taşları bir anda ışınlanmasın hareket ederek orayq ilerlesin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ben taşımı tutup hareket ettirip koymadan rakip hamle yapmasın
User prompt
Rakip yapay zeka hamle yapmadan önce 1 sn beklesin
User prompt
Pinleme (bağlama) kuralını ekle: Bir taş, hareket ettiğinde kendi şahını açıkta bırakıyorsa o taş hareket edemez. Pinli taş sadece şahı koruyacak yönde hamle yapabilir. Yapay zeka ve oyuncu bu kurala uymalıdır.
User prompt
Satranç tahtasında şah taşını asla yenme, şah mat ile bitir."
User prompt
Taşlara tıkladığımız zaman taşlar uzağa gitmesin tıkladığımız yerde kalsın ordan sürükleyelim
Code edit (1 edits merged)
Please save this source code
User prompt
Chess Master - 2D Classic Chess
Initial prompt
Bir 2D klasik satranç oyunu oluştur. Bu oyun tüm resmi satranç kurallarına uygun olmalı ve aşağıdaki kuralları eksiksiz uygulamalı: 1. **Tahta:** 8x8 klasik siyah-beyaz kareli satranç tahtası. 2. **Başlangıç Dizilimi:** Satranç kurallarına uygun olarak tüm taşlar doğru yerleştirilmeli. 3. **Taş Hareketleri:** Her taş, satranç kurallarına uygun şekilde hareket etmeli (piyon, at, fil, kale, vezir, şah). 4. **Özel Kurallar:** - Şah tehdidi (şah), şah mat, pat, rok (castle), piyon terfisi (promotion), en passant dahil tüm özel kurallar eksiksiz çalışmalı. 5. **Hamle Sırası:** Beyaz oyuncu başlar, sonra siyah hamle yapar. Oyuncu beyaz, yapay zeka siyahı kontrol eder. 6. **Oyuncu Kontrolleri:** Sürükle-bırak yöntemiyle taş hareket ettirme. 7. **Oyun Sonu:** - Şah mat olursa "Kazandın!" veya "Kaybettin!" mesajı gösterilmeli. - Pat olursa "Beraberlik!" mesajı gösterilmeli. --- 8. 🎮 **Zorluk Seçimi:** Oyuncu oyun başında aşağıdaki üç zorluk seviyesinden birini seçebilmeli: - **Kolay (Easy):** - Yapay zeka rastgele ama kurallara uygun hamleler yapar. - Kısa vadeli tehditleri görmez. - **Orta (Medium):** - Yapay zeka tehditleri analiz eder, taş koruması yapar. - Basit kombinasyonlar ve şah tehdidini engellemeye çalışır. - **Zor (Hard):** - Yapay zeka en iyi hamleyi seçmek için birden fazla hamle ileriye bakar (en az 2-3 hamle derinlikli). - Mat etme fırsatlarını değerlendirir, vezir kazanma veya piyon ilerletmeyi planlar. - Açıkta kalan taşlara saldırır ve gerektiğinde savunma yapar. Yapay zekanın mantığı seçilen zorluk seviyesine göre ayarlanmalı. Oyun başlamadan önce "Kolay", "Orta" ve "Zor" butonlarıyla bu seçim yapılabilmeli. Seçilen zorluk, yapay zekanın stratejik gücünü belirlemeli. --- 9. **Tasarım:** - 2 boyutlu sade, temiz ikonlar kullanılmalı. - Mobil uyumlu ve tüm ekran boyutlarına uygun olmalı. Sadece asset (taş görselleri, ses efektleri vs.) eksik olacak şekilde tam çalışan, zorluk seçilebilir bir satranç oyunu oluştur.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var ChessPiece = Container.expand(function (type, color, row, col) { var self = Container.call(this); self.pieceType = type; self.pieceColor = color; self.boardRow = row; self.boardCol = col; self.hasMoved = false; var assetId = color + type.charAt(0).toUpperCase() + type.slice(1); var pieceGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.updateBoardPosition = function (newRow, newCol) { self.boardRow = newRow; self.boardCol = newCol; self.hasMoved = true; }; return self; }); var ChessSquare = Container.expand(function (row, col) { var self = Container.call(this); self.row = row; self.col = col; self.piece = null; self.isHighlighted = false; var isLight = (row + col) % 2 === 0; var squareGraphics = self.attachAsset(isLight ? 'lightSquare' : 'darkSquare', { anchorX: 0.5, anchorY: 0.5 }); self.highlight = function () { if (!self.isHighlighted) { var highlight = LK.getAsset('highlightSquare', { anchorX: 0.5, anchorY: 0.5, alpha: 0, scaleX: 0.5, scaleY: 0.5 }); self.addChild(highlight); self.isHighlighted = true; self.highlightGraphics = highlight; // Animate highlight appearance tween(highlight, { alpha: 0.5, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } }; self.removeHighlight = function () { if (self.isHighlighted && self.highlightGraphics) { var highlightToRemove = self.highlightGraphics; self.isHighlighted = false; self.highlightGraphics = null; // Animate highlight disappearance tween(highlightToRemove, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 150, easing: tween.easeIn, onFinish: function onFinish() { self.removeChild(highlightToRemove); } }); } }; self.setPiece = function (piece) { if (self.piece) { self.removeChild(self.piece); } self.piece = piece; if (piece) { self.addChild(piece); piece.x = 0; piece.y = 0; } }; return self; }); var DifficultyButton = Container.expand(function (text, difficulty) { var self = Container.call(this); self.difficulty = difficulty; var buttonBg = self.attachAsset('difficultyButton', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2(text, { size: 60, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { selectedDifficulty = self.difficulty; startGame(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x8b4513 }); /**** * Game Code ****/ // Sound effects // UI elements // Board squares // Chess pieces - black pieces // Chess pieces - white pieces // Game state variables var gameState = 'difficulty'; // 'difficulty', 'playing', 'gameOver' var selectedDifficulty = 'medium'; var currentPlayer = 'white'; var board = []; var selectedSquare = null; var possibleMoves = []; var difficultyButtons = []; var draggedPiece = null; var dragOffset = { x: 0, y: 0 }; var aiHasMoved = false; var capturedWhitePieces = []; var capturedBlackPieces = []; var capturedPiecesContainer = null; var checkedKing = null; // Track the currently checked king for highlighting // Create explosion effect for captures function createExplosionEffect(x, y) { var particles = []; var numParticles = 6; // Reduced by 50% var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844, 0xff6666]; // Explosive colors // Create main explosion particles for (var i = 0; i < numParticles; i++) { var particle = LK.getAsset('highlightSquare', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2 + Math.random() * 0.4, // Varied sizes scaleY: 0.2 + Math.random() * 0.4, alpha: 0.9 }); particle.x = x; particle.y = y; particle.tint = colors[Math.floor(Math.random() * colors.length)]; // Random explosion color game.addChild(particle); particles.push(particle); // Random direction for each particle with slightly reduced variation var angle = i / numParticles * Math.PI * 2 + (Math.random() - 0.5) * 0.5; var speed = 28 + Math.random() * 40; // Reduced speeds by 50% (28-68 range) var targetX = x + Math.cos(angle) * speed; var targetY = y + Math.sin(angle) * speed; // Add rotation and bounce effect var rotationSpeed = (Math.random() - 0.5) * 8; // Initial burst animation with rotation tween(particle, { x: targetX, y: targetY, rotation: rotationSpeed, scaleX: 0.8 + Math.random() * 0.4, scaleY: 0.8 + Math.random() * 0.4 }, { duration: 200, easing: tween.easeOut, onFinish: function (currentParticle) { // Second phase: fade and shrink tween(currentParticle, { scaleX: 0, scaleY: 0, alpha: 0, rotation: currentParticle.rotation + rotationSpeed * 2 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { game.removeChild(currentParticle); } }); }.bind(null, particle) }); } // Create additional flash effect var flashRing = LK.getAsset('highlightSquare', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 1 }); flashRing.x = x; flashRing.y = y; flashRing.tint = 0xffffff; // Bright white flash game.addChild(flashRing); // Flash ring expansion and fade (slightly smaller) tween(flashRing, { scaleX: 1.25, // Reduced by 50% scaleY: 1.25, // Reduced by 50% alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(flashRing); } }); // Create sparks effect (reduced count) for (var j = 0; j < 3; j++) { // Reduced by 50% var spark = LK.getAsset('highlightSquare', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 1 }); spark.x = x; spark.y = y; spark.tint = 0xffff88; // Bright yellow sparks game.addChild(spark); var sparkAngle = Math.random() * Math.PI * 2; var sparkDistance = 20 + Math.random() * 24; // Reduced by 50% (20-44 range) var sparkTargetX = x + Math.cos(sparkAngle) * sparkDistance; var sparkTargetY = y + Math.sin(sparkAngle) * sparkDistance; // Animate sparks with trail effect tween(spark, { x: sparkTargetX, y: sparkTargetY, scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300 + Math.random() * 200, easing: tween.easeOut, onFinish: function (currentSpark) { game.removeChild(currentSpark); }.bind(null, spark) }); } } // Highlight the king when in check function highlightCheckedKing(color) { // Find the king of the specified color for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceType === 'king' && piece.pieceColor === color) { checkedKing = piece; // Apply red tint to the king with pulsing animation tween(piece, { tint: 0xff0000 }, { duration: 300, easing: tween.easeOut }); // Add pulsing scale effect to make it more visible tween(piece, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(piece, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut }); } }); return; } } } } // Remove highlight from king function removeKingHighlight() { if (checkedKing) { // Reset tint and scale to normal tween(checkedKing, { tint: 0xffffff, scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut }); checkedKing = null; } } // Update captured pieces display function updateCapturedPiecesDisplay() { // Clear existing captured pieces display (except label) while (capturedPiecesContainer.children.length > 1) { capturedPiecesContainer.removeChild(capturedPiecesContainer.children[1]); } var yOffset = 20; var pieceSize = 80; var spacing = 90; // Display captured white pieces for (var i = 0; i < capturedWhitePieces.length; i++) { var piece = capturedWhitePieces[i]; var displayPiece = new ChessPiece(piece.pieceType, piece.pieceColor, 0, 0); displayPiece.x = i % 8 * spacing; displayPiece.y = yOffset + Math.floor(i / 8) * spacing; displayPiece.scaleX = 0.8; displayPiece.scaleY = 0.8; capturedPiecesContainer.addChild(displayPiece); } // Display captured black pieces below white pieces var blackStartY = yOffset + Math.ceil(capturedWhitePieces.length / 8) * spacing + 30; for (var j = 0; j < capturedBlackPieces.length; j++) { var piece = capturedBlackPieces[j]; var displayPiece = new ChessPiece(piece.pieceType, piece.pieceColor, 0, 0); displayPiece.x = j % 8 * spacing; displayPiece.y = blackStartY + Math.floor(j / 8) * spacing; displayPiece.scaleX = 0.8; displayPiece.scaleY = 0.8; capturedPiecesContainer.addChild(displayPiece); } } // Board constants var BOARD_SIZE = 8; var SQUARE_SIZE = 230; var BOARD_START_X = 2048 / 2 - BOARD_SIZE * SQUARE_SIZE / 2; var BOARD_START_Y = 2732 / 2 - BOARD_SIZE * SQUARE_SIZE / 2; // Initialize difficulty selection function initializeDifficultySelection() { var easyButton = new DifficultyButton('EASY', 'easy'); easyButton.x = 2048 / 2; easyButton.y = 2732 / 2 - 200; game.addChild(easyButton); difficultyButtons.push(easyButton); var mediumButton = new DifficultyButton('MEDIUM', 'medium'); mediumButton.x = 2048 / 2; mediumButton.y = 2732 / 2; game.addChild(mediumButton); difficultyButtons.push(mediumButton); var hardButton = new DifficultyButton('HARD', 'hard'); hardButton.x = 2048 / 2; hardButton.y = 2732 / 2 + 200; game.addChild(hardButton); difficultyButtons.push(hardButton); var titleText = new Text2('Select Difficulty', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 2732 / 2 - 400; game.addChild(titleText); } // Start the game after difficulty selection function startGame() { // Remove difficulty buttons for (var i = 0; i < difficultyButtons.length; i++) { game.removeChild(difficultyButtons[i]); } difficultyButtons = []; // Remove title for (var j = game.children.length - 1; j >= 0; j--) { var child = game.children[j]; if (child instanceof Text2) { game.removeChild(child); } } gameState = 'playing'; initializeBoard(); setupInitialPieces(); // Initialize captured pieces area capturedPiecesContainer = new Container(); capturedPiecesContainer.x = 350; capturedPiecesContainer.y = 150; game.addChild(capturedPiecesContainer); // Add labels for captured pieces var capturedLabel = new Text2('Captured Pieces', { size: 70, fill: 0xFFFFFF }); capturedLabel.anchor.set(0, 0); capturedLabel.x = 0; capturedLabel.y = -120; capturedPiecesContainer.addChild(capturedLabel); } // Initialize the chess board function initializeBoard() { board = []; for (var row = 0; row < BOARD_SIZE; row++) { board[row] = []; for (var col = 0; col < BOARD_SIZE; col++) { var square = new ChessSquare(row, col); square.x = BOARD_START_X + col * SQUARE_SIZE + SQUARE_SIZE / 2; square.y = BOARD_START_Y + row * SQUARE_SIZE + SQUARE_SIZE / 2; game.addChild(square); board[row][col] = square; } } } // Setup initial piece positions function setupInitialPieces() { var pieceOrder = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook']; // Black pieces (top of board) for (var col = 0; col < 8; col++) { var blackPiece = new ChessPiece(pieceOrder[col], 'black', 0, col); board[0][col].setPiece(blackPiece); var blackPawn = new ChessPiece('pawn', 'black', 1, col); board[1][col].setPiece(blackPawn); } // White pieces (bottom of board) for (var col = 0; col < 8; col++) { var whitePawn = new ChessPiece('pawn', 'white', 6, col); board[6][col].setPiece(whitePawn); var whitePiece = new ChessPiece(pieceOrder[col], 'white', 7, col); board[7][col].setPiece(whitePiece); } } // Get all pseudo-legal moves for a piece (ignores pins and king safety) function getRawMoves(piece, fromRow, fromCol) { var moves = []; var type = piece.pieceType; var color = piece.pieceColor; if (type === 'pawn') { var direction = color === 'white' ? -1 : 1; var startRow = color === 'white' ? 6 : 1; // Move forward 1 square (only if empty) if (isValidPosition(fromRow + direction, fromCol) && !board[fromRow + direction][fromCol].piece) { moves.push({ row: fromRow + direction, col: fromCol }); // Move forward 2 squares from starting position (only if both squares are empty) if (fromRow === startRow && isValidPosition(fromRow + 2 * direction, fromCol) && !board[fromRow + 2 * direction][fromCol].piece) { moves.push({ row: fromRow + 2 * direction, col: fromCol }); } } // Pawn captures diagonally (only if there's an opponent piece) for (var dc = -1; dc <= 1; dc += 2) { if (isValidPosition(fromRow + direction, fromCol + dc)) { var targetPiece = board[fromRow + direction][fromCol + dc].piece; if (targetPiece && targetPiece.pieceColor !== color) { moves.push({ row: fromRow + direction, col: fromCol + dc }); } } } } else if (type === 'rook') { var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]; for (var d = 0; d < directions.length; d++) { var dr = directions[d][0]; var dc = directions[d][1]; for (var i = 1; i < 8; i++) { var newRow = fromRow + dr * i; var newCol = fromCol + dc * i; if (!isValidPosition(newRow, newCol)) break; moves.push({ row: newRow, col: newCol }); var targetPiece = board[newRow][newCol].piece; if (targetPiece) { break; } } } } else if (type === 'bishop') { var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var dr = directions[d][0]; var dc = directions[d][1]; for (var i = 1; i < 8; i++) { var newRow = fromRow + dr * i; var newCol = fromCol + dc * i; if (!isValidPosition(newRow, newCol)) break; moves.push({ row: newRow, col: newCol }); var targetPiece = board[newRow][newCol].piece; if (targetPiece) { break; } } } } else if (type === 'queen') { var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var dr = directions[d][0]; var dc = directions[d][1]; for (var i = 1; i < 8; i++) { var newRow = fromRow + dr * i; var newCol = fromCol + dc * i; if (!isValidPosition(newRow, newCol)) break; moves.push({ row: newRow, col: newCol }); var targetPiece = board[newRow][newCol].piece; if (targetPiece) { break; } } } } else if (type === 'king') { var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var newRow = fromRow + directions[d][0]; var newCol = fromCol + directions[d][1]; if (isValidPosition(newRow, newCol)) { moves.push({ row: newRow, col: newCol }); } } } else if (type === 'knight') { var knightMoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]; for (var m = 0; m < knightMoves.length; m++) { var newRow = fromRow + knightMoves[m][0]; var newCol = fromCol + knightMoves[m][1]; if (isValidPosition(newRow, newCol)) { moves.push({ row: newRow, col: newCol }); } } } return moves; } // Get legal moves for a piece function getLegalMoves(piece, fromRow, fromCol) { var moves = []; var type = piece.pieceType; var color = piece.pieceColor; if (type === 'pawn') { var direction = color === 'white' ? -1 : 1; var startRow = color === 'white' ? 6 : 1; // Forward move if (isValidPosition(fromRow + direction, fromCol) && !board[fromRow + direction][fromCol].piece) { moves.push({ row: fromRow + direction, col: fromCol }); // Two squares forward from starting position if (fromRow === startRow && !board[fromRow + 2 * direction][fromCol].piece) { moves.push({ row: fromRow + 2 * direction, col: fromCol }); } } // Diagonal captures for (var dc = -1; dc <= 1; dc += 2) { if (isValidPosition(fromRow + direction, fromCol + dc)) { var targetPiece = board[fromRow + direction][fromCol + dc].piece; if (targetPiece && targetPiece.pieceColor !== color) { moves.push({ row: fromRow + direction, col: fromCol + dc }); } } } } else if (type === 'rook') { var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]; for (var d = 0; d < directions.length; d++) { var dr = directions[d][0]; var dc = directions[d][1]; for (var i = 1; i < 8; i++) { var newRow = fromRow + dr * i; var newCol = fromCol + dc * i; if (!isValidPosition(newRow, newCol)) break; var targetPiece = board[newRow][newCol].piece; if (targetPiece) { if (targetPiece.pieceColor !== color) { moves.push({ row: newRow, col: newCol }); } break; } else { moves.push({ row: newRow, col: newCol }); } } } } else if (type === 'bishop') { var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var dr = directions[d][0]; var dc = directions[d][1]; for (var i = 1; i < 8; i++) { var newRow = fromRow + dr * i; var newCol = fromCol + dc * i; if (!isValidPosition(newRow, newCol)) break; var targetPiece = board[newRow][newCol].piece; if (targetPiece) { if (targetPiece.pieceColor !== color) { moves.push({ row: newRow, col: newCol }); } break; } else { moves.push({ row: newRow, col: newCol }); } } } } else if (type === 'queen') { var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var dr = directions[d][0]; var dc = directions[d][1]; for (var i = 1; i < 8; i++) { var newRow = fromRow + dr * i; var newCol = fromCol + dc * i; if (!isValidPosition(newRow, newCol)) break; var targetPiece = board[newRow][newCol].piece; if (targetPiece) { if (targetPiece.pieceColor !== color) { moves.push({ row: newRow, col: newCol }); } break; } else { moves.push({ row: newRow, col: newCol }); } } } } else if (type === 'king') { var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var newRow = fromRow + directions[d][0]; var newCol = fromCol + directions[d][1]; if (isValidPosition(newRow, newCol)) { var targetPiece = board[newRow][newCol].piece; if (!targetPiece || targetPiece.pieceColor !== color) { moves.push({ row: newRow, col: newCol }); } } } } else if (type === 'knight') { var knightMoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]]; for (var m = 0; m < knightMoves.length; m++) { var newRow = fromRow + knightMoves[m][0]; var newCol = fromCol + knightMoves[m][1]; if (isValidPosition(newRow, newCol)) { var targetPiece = board[newRow][newCol].piece; if (!targetPiece || targetPiece.pieceColor !== color) { moves.push({ row: newRow, col: newCol }); } } } } // Filter out moves that would leave own king in check (pin rule) var legalMoves = []; var _loop = function _loop() { move = moves[i]; // Simulate the move fromPiece = board[fromRow][fromCol].piece; toPiece = board[move.row][move.col].piece; // Temporarily move the piece board[fromRow][fromCol].setPiece(null); board[move.row][move.col].setPiece(fromPiece); kingSafe = true; // Find own king position after move kingRow = -1, kingCol = -1; for (r = 0; r < BOARD_SIZE; r++) { for (c = 0; c < BOARD_SIZE; c++) { p = board[r][c].piece; if (p && p.pieceType === 'king' && p.pieceColor === color) { kingRow = r; kingCol = c; } } } // If this piece is the king, update kingRow/kingCol to new position if (type === 'king') { kingRow = move.row; kingCol = move.col; } // Check if any enemy piece can attack the king after this move for (r = 0; r < BOARD_SIZE; r++) { for (c = 0; c < BOARD_SIZE; c++) { enemy = board[r][c].piece; if (enemy && enemy.pieceColor !== color) { enemyMoves = getRawMoves(enemy, r, c); for (j = 0; j < enemyMoves.length; j++) { if (enemyMoves[j].row === kingRow && enemyMoves[j].col === kingCol) { kingSafe = false; break; } } } if (!kingSafe) break; } if (!kingSafe) break; } // Undo the move board[move.row][move.col].setPiece(toPiece); board[fromRow][fromCol].setPiece(fromPiece); if (kingSafe) { legalMoves.push(move); } }, move, fromPiece, toPiece, kingSafe, kingRow, kingCol, r, c, p, r, c, enemy, enemyMoves, j; for (var i = 0; i < moves.length; i++) { _loop(); } return legalMoves; } // Check if position is valid on board function isValidPosition(row, col) { return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE; } // Highlight possible moves function highlightMoves(moves) { for (var i = 0; i < moves.length; i++) { board[moves[i].row][moves[i].col].highlight(); } } // Clear all highlights function clearHighlights() { for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { board[row][col].removeHighlight(); } } } // Make a move function makeMove(fromRow, fromCol, toRow, toCol) { var piece = board[fromRow][fromCol].piece; var capturedPiece = board[toRow][toCol].piece; // Prevent capturing the king if (capturedPiece && capturedPiece.pieceType === 'king') { // Invalid move: cannot capture king, revert and return // Return piece to original position if dragged if (draggedPiece) { game.removeChild(draggedPiece); board[fromRow][fromCol].setPiece(draggedPiece); } clearHighlights(); draggedPiece = null; selectedSquare = null; possibleMoves = []; return; } // Calculate target position var targetX = BOARD_START_X + toCol * SQUARE_SIZE + SQUARE_SIZE / 2; var targetY = BOARD_START_Y + toRow * SQUARE_SIZE + SQUARE_SIZE / 2; // Check if this is an AI move (piece is black and not being dragged) var isAIMove = piece.pieceColor === 'black' && !draggedPiece; if (isAIMove) { // For AI moves, animate the piece movement // First, bring piece to game level for animation var currentSquare = board[fromRow][fromCol]; var currentGlobalPos = currentSquare.toGlobal(piece.position); currentSquare.removeChild(piece); game.addChild(piece); piece.x = currentGlobalPos.x; piece.y = currentGlobalPos.y; // Remove piece from old position on board board[fromRow][fromCol].setPiece(null); // Handle captured piece animation if there's a capture if (capturedPiece) { // Create explosion effect at capture location var explosionX = BOARD_START_X + toCol * SQUARE_SIZE + SQUARE_SIZE / 2; var explosionY = BOARD_START_Y + toRow * SQUARE_SIZE + SQUARE_SIZE / 2; createExplosionEffect(explosionX, explosionY); // Add to captured pieces array if (capturedPiece.pieceColor === 'white') { capturedWhitePieces.push({ pieceType: capturedPiece.pieceType, pieceColor: capturedPiece.pieceColor }); } else { capturedBlackPieces.push({ pieceType: capturedPiece.pieceType, pieceColor: capturedPiece.pieceColor }); } // Remove captured piece from board immediately board[toRow][toCol].setPiece(null); // Animate captured piece moving to captured area var capturedTargetX = capturedPiecesContainer.x; var capturedTargetY = capturedPiecesContainer.y + 100; // First animate to captured area, then scale down tween(capturedPiece, { x: capturedTargetX, y: capturedTargetY, scaleX: 0.6, scaleY: 0.6 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Then fade out and destroy tween(capturedPiece, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { // Destroy the captured piece and update display capturedPiece.destroy(); updateCapturedPiecesDisplay(); } }); } }); } // Set piece in new position but don't add to square yet board[toRow][toCol].piece = piece; piece.updateBoardPosition(toRow, toCol); // Animate piece to target position tween(piece, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Move piece from game to target square game.removeChild(piece); board[toRow][toCol].setPiece(piece); // Play sound after animation if (capturedPiece) { LK.getSound('captureSound').play(); } else { LK.getSound('moveSound').play(); } // Check for pawn promotion if (piece.pieceType === 'pawn') { if (piece.pieceColor === 'white' && toRow === 0 || piece.pieceColor === 'black' && toRow === 7) { // Promote to queen board[toRow][toCol].setPiece(null); var promotedQueen = new ChessPiece('queen', piece.pieceColor, toRow, toCol); board[toRow][toCol].setPiece(promotedQueen); } } // Switch turns currentPlayer = currentPlayer === 'white' ? 'black' : 'white'; // Remove previous king highlight if king is no longer in check if (checkedKing && !isInCheck(checkedKing.pieceColor)) { removeKingHighlight(); } // Reset AI move flag when switching turns if (currentPlayer === 'black') { aiHasMoved = false; } // Reset dragged piece to null to re-enable piece interaction draggedPiece = null; // Check for game end conditions first if (isCheckmate(currentPlayer)) { // Highlight the checkmated king highlightCheckedKing(currentPlayer); // Play checkmate sound LK.getSound('checkmateSound').play(); // Create rainbow checkmate text var checkmateText = new Text2('Check Mate!', { size: 150, fill: 0xff0000 // Start with red }); checkmateText.anchor.set(0.5, 0.5); checkmateText.x = 2048 / 2; checkmateText.y = 300; game.addChild(checkmateText); // Rainbow color animation - cycle through colors var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff]; var colorIndex = 0; var colorTimer = LK.setInterval(function () { colorIndex = (colorIndex + 1) % colors.length; checkmateText.tint = colors[colorIndex]; }, 100); // Fade out the text slowly tween(checkmateText, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { LK.clearInterval(colorTimer); game.removeChild(checkmateText); } }); // End game 1 second after checkmate text appears LK.setTimeout(function () { if (currentPlayer === 'white') { LK.showGameOver(); } else { LK.showYouWin(); } gameState = 'gameOver'; }, 1000); } else if (isStalemate(currentPlayer)) { LK.showGameOver(); // Show as draw gameState = 'gameOver'; } else if (isInCheck(currentPlayer)) { // Highlight the checked king highlightCheckedKing(currentPlayer); // Play check sound LK.getSound('checkSound').play(); // Create rainbow check text var checkText = new Text2('Check!', { size: 120, fill: 0xff0000 // Start with red }); checkText.anchor.set(0.5, 0.5); checkText.x = 2048 / 2; checkText.y = 300; game.addChild(checkText); // Rainbow color animation - cycle through colors var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff]; var colorIndex = 0; var colorTimer = LK.setInterval(function () { colorIndex = (colorIndex + 1) % colors.length; checkText.tint = colors[colorIndex]; }, 100); // Fade out the text slowly tween(checkText, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { LK.clearInterval(colorTimer); game.removeChild(checkText); } }); } } }); } else { // For player moves, animate the piece smoothly to target position // Remove piece from old position board[fromRow][fromCol].setPiece(null); // Set piece in new position but don't add to square yet board[toRow][toCol].piece = piece; piece.updateBoardPosition(toRow, toCol); // Add capture animation if there's a captured piece if (capturedPiece) { // Create explosion effect at capture location createExplosionEffect(targetX, targetY); // Add to captured pieces array if (capturedPiece.pieceColor === 'white') { capturedWhitePieces.push({ pieceType: capturedPiece.pieceType, pieceColor: capturedPiece.pieceColor }); } else { capturedBlackPieces.push({ pieceType: capturedPiece.pieceType, pieceColor: capturedPiece.pieceColor }); } // Animate captured piece moving to captured area first var capturedTargetX = capturedPiecesContainer.x; var capturedTargetY = capturedPiecesContainer.y + 100; tween(capturedPiece, { x: capturedTargetX, y: capturedTargetY, scaleX: 0.6, scaleY: 0.6 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Then scale down the captured piece before removing tween(capturedPiece, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { // Captured piece animation complete updateCapturedPiecesDisplay(); } }); } }); } // Animate piece to target position tween(piece, { x: targetX, y: targetY }, { duration: 250, easing: tween.easeOut, onFinish: function onFinish() { // Move piece from game to target square game.removeChild(piece); board[toRow][toCol].setPiece(piece); // Play sound after animation if (capturedPiece) { LK.getSound('captureSound').play(); } else { LK.getSound('moveSound').play(); } // Check for pawn promotion if (piece.pieceType === 'pawn') { if (piece.pieceColor === 'white' && toRow === 0 || piece.pieceColor === 'black' && toRow === 7) { // Promote to queen board[toRow][toCol].setPiece(null); var promotedQueen = new ChessPiece('queen', piece.pieceColor, toRow, toCol); board[toRow][toCol].setPiece(promotedQueen); } } // Switch turns currentPlayer = currentPlayer === 'white' ? 'black' : 'white'; // Remove previous king highlight if king is no longer in check if (checkedKing && !isInCheck(checkedKing.pieceColor)) { removeKingHighlight(); } // Reset AI move flag when switching turns if (currentPlayer === 'black') { aiHasMoved = false; } // Reset dragged piece to null to re-enable piece interaction draggedPiece = null; // Check for game end conditions first if (isCheckmate(currentPlayer)) { // Highlight the checkmated king highlightCheckedKing(currentPlayer); // Play checkmate sound LK.getSound('checkmateSound').play(); // Create rainbow checkmate text var checkmateText = new Text2('Check Mate!', { size: 150, fill: 0xff0000 // Start with red }); checkmateText.anchor.set(0.5, 0.5); checkmateText.x = 2048 / 2; checkmateText.y = 300; game.addChild(checkmateText); // Rainbow color animation - cycle through colors var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff]; var colorIndex = 0; var colorTimer = LK.setInterval(function () { colorIndex = (colorIndex + 1) % colors.length; checkmateText.tint = colors[colorIndex]; }, 100); // Fade out the text slowly tween(checkmateText, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { LK.clearInterval(colorTimer); game.removeChild(checkmateText); } }); // End game 1 second after checkmate text appears LK.setTimeout(function () { if (currentPlayer === 'white') { LK.showGameOver(); } else { LK.showYouWin(); } gameState = 'gameOver'; }, 1000); } else if (isStalemate(currentPlayer)) { LK.showGameOver(); // Show as draw gameState = 'gameOver'; } else if (isInCheck(currentPlayer)) { // Highlight the checked king highlightCheckedKing(currentPlayer); // Play check sound LK.getSound('checkSound').play(); // Create rainbow check text var checkText = new Text2('Check!', { size: 120, fill: 0xff0000 // Start with red }); checkText.anchor.set(0.5, 0.5); checkText.x = 2048 / 2; checkText.y = 300; game.addChild(checkText); // Rainbow color animation - cycle through colors var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff]; var colorIndex = 0; var colorTimer = LK.setInterval(function () { colorIndex = (colorIndex + 1) % colors.length; checkText.tint = colors[colorIndex]; }, 100); // Fade out the text slowly tween(checkText, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { LK.clearInterval(colorTimer); game.removeChild(checkText); } }); } } }); } } // Check if a king is in check function isInCheck(color) { // Find king position var kingPos = null; for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceType === 'king' && piece.pieceColor === color) { kingPos = { row: row, col: col }; break; } } if (kingPos) break; } if (!kingPos) return false; // No king found // Check if any enemy piece can attack the king for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceColor !== color) { var moves = getRawMoves(piece, row, col); for (var i = 0; i < moves.length; i++) { if (moves[i].row === kingPos.row && moves[i].col === kingPos.col) { return true; // King is under attack } } } } } return false; // King is safe } // Simple checkmate detection - king must be in check AND have no legal moves function isCheckmate(color) { // First check if king is in check if (!isInCheck(color)) { return false; // Not checkmate if king is not in check } // Find king var kingPos = null; for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceType === 'king' && piece.pieceColor === color) { kingPos = { row: row, col: col }; break; } } if (kingPos) break; } if (!kingPos) return true; // No king found // Check if any piece can make a legal move for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceColor === color) { var moves = getLegalMoves(piece, row, col); if (moves.length > 0) { return false; // Found a legal move } } } } return true; // No legal moves found and king is in check } // Simple stalemate detection - king is NOT in check but has no legal moves function isStalemate(color) { // First check if king is in check if (isInCheck(color)) { return false; // Not stalemate if king is in check } // Check if any piece can make a legal move for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceColor === color) { var moves = getLegalMoves(piece, row, col); if (moves.length > 0) { return false; // Found a legal move } } } } return true; // No legal moves found but king is not in check } // AI move selection based on difficulty function getAIMove() { var allMoves = []; // Get all possible moves for AI (black pieces) for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { var piece = board[row][col].piece; if (piece && piece.pieceColor === 'black') { var moves = getLegalMoves(piece, row, col); for (var m = 0; m < moves.length; m++) { // Prevent AI from selecting a move that would capture the king var target = board[moves[m].row][moves[m].col].piece; if (target && target.pieceType === 'king') { continue; } allMoves.push({ fromRow: row, fromCol: col, toRow: moves[m].row, toCol: moves[m].col, piece: piece }); } } } } if (allMoves.length === 0) return null; if (selectedDifficulty === 'easy') { // Random move return allMoves[Math.floor(Math.random() * allMoves.length)]; } else if (selectedDifficulty === 'medium') { // Prefer captures var captures = []; for (var i = 0; i < allMoves.length; i++) { var move = allMoves[i]; if (board[move.toRow][move.toCol].piece) { captures.push(move); } } if (captures.length > 0) { return captures[Math.floor(Math.random() * captures.length)]; } return allMoves[Math.floor(Math.random() * allMoves.length)]; } else { // Hard: prefer captures, then center moves var captures = []; var centerMoves = []; for (var i = 0; i < allMoves.length; i++) { var move = allMoves[i]; if (board[move.toRow][move.toCol].piece) { captures.push(move); } else if (move.toRow >= 3 && move.toRow <= 4 && move.toCol >= 3 && move.toCol <= 4) { centerMoves.push(move); } } if (captures.length > 0) { return captures[Math.floor(Math.random() * captures.length)]; } if (centerMoves.length > 0) { return centerMoves[Math.floor(Math.random() * centerMoves.length)]; } return allMoves[Math.floor(Math.random() * allMoves.length)]; } } // Get board position from screen coordinates function getBoardPosition(x, y) { var col = Math.floor((x - BOARD_START_X) / SQUARE_SIZE); var row = Math.floor((y - BOARD_START_Y) / SQUARE_SIZE); if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE) { return { row: row, col: col }; } return null; } // Handle mouse/touch down game.down = function (x, y, obj) { if (gameState !== 'playing' || currentPlayer !== 'white') return; var pos = getBoardPosition(x, y); if (!pos) return; var square = board[pos.row][pos.col]; var piece = square.piece; if (piece && piece.pieceColor === 'white') { // Start dragging draggedPiece = piece; // Set drag offset to zero so piece stays at click position dragOffset.x = 0; dragOffset.y = 0; // Clear previous highlights clearHighlights(); // Highlight possible moves possibleMoves = getLegalMoves(piece, pos.row, pos.col); highlightMoves(possibleMoves); selectedSquare = { row: pos.row, col: pos.col }; // Bring piece to front but keep it at current position var tempParent = piece.parent; var currentGlobalPos = tempParent.toGlobal(piece.position); tempParent.removeChild(piece); game.addChild(piece); piece.x = currentGlobalPos.x; piece.y = currentGlobalPos.y; // Add selection animation tween(piece, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150, easing: tween.easeOut }); } }; // Handle mouse/touch move game.move = function (x, y, obj) { if (draggedPiece) { draggedPiece.x = x; draggedPiece.y = y; } }; // Handle mouse/touch up game.up = function (x, y, obj) { if (!draggedPiece || gameState !== 'playing') return; var pos = getBoardPosition(x, y); var validMove = false; if (pos && selectedSquare) { // Check if this is a valid move for (var i = 0; i < possibleMoves.length; i++) { if (possibleMoves[i].row === pos.row && possibleMoves[i].col === pos.col) { validMove = true; break; } } if (validMove) { // Prevent player from capturing the king var targetPiece = board[pos.row][pos.col].piece; if (targetPiece && targetPiece.pieceType === 'king') { // Invalid move: cannot capture king, revert and return game.removeChild(draggedPiece); board[selectedSquare.row][selectedSquare.col].setPiece(draggedPiece); clearHighlights(); draggedPiece = null; selectedSquare = null; possibleMoves = []; return; } // Make the move makeMove(selectedSquare.row, selectedSquare.col, pos.row, pos.col); // Clear selection state after valid move selectedSquare = null; possibleMoves = []; } } if (!validMove && selectedSquare) { // Return piece to original position with animation var originalSquare = board[selectedSquare.row][selectedSquare.col]; var originalX = BOARD_START_X + selectedSquare.col * SQUARE_SIZE + SQUARE_SIZE / 2; var originalY = BOARD_START_Y + selectedSquare.row * SQUARE_SIZE + SQUARE_SIZE / 2; // Reset scale and animate back to original position tween(draggedPiece, { x: originalX, y: originalY, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(draggedPiece); originalSquare.setPiece(draggedPiece); // Reset dragging state after animation completes draggedPiece = null; selectedSquare = null; possibleMoves = []; } }); // Clear highlights immediately clearHighlights(); } else { // Reset scale for valid moves if (draggedPiece) { tween(draggedPiece, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); } // Clean up for valid moves clearHighlights(); draggedPiece = null; selectedSquare = null; possibleMoves = []; } }; // Game update loop game.update = function () { if (gameState === 'playing' && currentPlayer === 'black' && !draggedPiece && !aiHasMoved) { // AI turn - only if player is not currently dragging a piece and AI hasn't moved yet if (LK.ticks % 60 === 0) { // Wait 1 second before AI move aiHasMoved = true; // Set flag immediately to prevent multiple moves LK.setTimeout(function () { var aiMove = getAIMove(); if (aiMove) { makeMove(aiMove.fromRow, aiMove.fromCol, aiMove.toRow, aiMove.toCol); } }, 1000); } } }; // Play background music LK.playMusic('Game_music'); // Initialize the game if (gameState === 'difficulty') { initializeDifficultySelection(); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ChessPiece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.pieceType = type;
self.pieceColor = color;
self.boardRow = row;
self.boardCol = col;
self.hasMoved = false;
var assetId = color + type.charAt(0).toUpperCase() + type.slice(1);
var pieceGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.updateBoardPosition = function (newRow, newCol) {
self.boardRow = newRow;
self.boardCol = newCol;
self.hasMoved = true;
};
return self;
});
var ChessSquare = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.piece = null;
self.isHighlighted = false;
var isLight = (row + col) % 2 === 0;
var squareGraphics = self.attachAsset(isLight ? 'lightSquare' : 'darkSquare', {
anchorX: 0.5,
anchorY: 0.5
});
self.highlight = function () {
if (!self.isHighlighted) {
var highlight = LK.getAsset('highlightSquare', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.addChild(highlight);
self.isHighlighted = true;
self.highlightGraphics = highlight;
// Animate highlight appearance
tween(highlight, {
alpha: 0.5,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.removeHighlight = function () {
if (self.isHighlighted && self.highlightGraphics) {
var highlightToRemove = self.highlightGraphics;
self.isHighlighted = false;
self.highlightGraphics = null;
// Animate highlight disappearance
tween(highlightToRemove, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
self.removeChild(highlightToRemove);
}
});
}
};
self.setPiece = function (piece) {
if (self.piece) {
self.removeChild(self.piece);
}
self.piece = piece;
if (piece) {
self.addChild(piece);
piece.x = 0;
piece.y = 0;
}
};
return self;
});
var DifficultyButton = Container.expand(function (text, difficulty) {
var self = Container.call(this);
self.difficulty = difficulty;
var buttonBg = self.attachAsset('difficultyButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 60,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function (x, y, obj) {
selectedDifficulty = self.difficulty;
startGame();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x8b4513
});
/****
* Game Code
****/
// Sound effects
// UI elements
// Board squares
// Chess pieces - black pieces
// Chess pieces - white pieces
// Game state variables
var gameState = 'difficulty'; // 'difficulty', 'playing', 'gameOver'
var selectedDifficulty = 'medium';
var currentPlayer = 'white';
var board = [];
var selectedSquare = null;
var possibleMoves = [];
var difficultyButtons = [];
var draggedPiece = null;
var dragOffset = {
x: 0,
y: 0
};
var aiHasMoved = false;
var capturedWhitePieces = [];
var capturedBlackPieces = [];
var capturedPiecesContainer = null;
var checkedKing = null; // Track the currently checked king for highlighting
// Create explosion effect for captures
function createExplosionEffect(x, y) {
var particles = [];
var numParticles = 6; // Reduced by 50%
var colors = [0xff4444, 0xffaa44, 0xffff44, 0xff8844, 0xff6666]; // Explosive colors
// Create main explosion particles
for (var i = 0; i < numParticles; i++) {
var particle = LK.getAsset('highlightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.4,
// Varied sizes
scaleY: 0.2 + Math.random() * 0.4,
alpha: 0.9
});
particle.x = x;
particle.y = y;
particle.tint = colors[Math.floor(Math.random() * colors.length)]; // Random explosion color
game.addChild(particle);
particles.push(particle);
// Random direction for each particle with slightly reduced variation
var angle = i / numParticles * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var speed = 28 + Math.random() * 40; // Reduced speeds by 50% (28-68 range)
var targetX = x + Math.cos(angle) * speed;
var targetY = y + Math.sin(angle) * speed;
// Add rotation and bounce effect
var rotationSpeed = (Math.random() - 0.5) * 8;
// Initial burst animation with rotation
tween(particle, {
x: targetX,
y: targetY,
rotation: rotationSpeed,
scaleX: 0.8 + Math.random() * 0.4,
scaleY: 0.8 + Math.random() * 0.4
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function (currentParticle) {
// Second phase: fade and shrink
tween(currentParticle, {
scaleX: 0,
scaleY: 0,
alpha: 0,
rotation: currentParticle.rotation + rotationSpeed * 2
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
game.removeChild(currentParticle);
}
});
}.bind(null, particle)
});
}
// Create additional flash effect
var flashRing = LK.getAsset('highlightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
});
flashRing.x = x;
flashRing.y = y;
flashRing.tint = 0xffffff; // Bright white flash
game.addChild(flashRing);
// Flash ring expansion and fade (slightly smaller)
tween(flashRing, {
scaleX: 1.25,
// Reduced by 50%
scaleY: 1.25,
// Reduced by 50%
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(flashRing);
}
});
// Create sparks effect (reduced count)
for (var j = 0; j < 3; j++) {
// Reduced by 50%
var spark = LK.getAsset('highlightSquare', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
});
spark.x = x;
spark.y = y;
spark.tint = 0xffff88; // Bright yellow sparks
game.addChild(spark);
var sparkAngle = Math.random() * Math.PI * 2;
var sparkDistance = 20 + Math.random() * 24; // Reduced by 50% (20-44 range)
var sparkTargetX = x + Math.cos(sparkAngle) * sparkDistance;
var sparkTargetY = y + Math.sin(sparkAngle) * sparkDistance;
// Animate sparks with trail effect
tween(spark, {
x: sparkTargetX,
y: sparkTargetY,
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function (currentSpark) {
game.removeChild(currentSpark);
}.bind(null, spark)
});
}
}
// Highlight the king when in check
function highlightCheckedKing(color) {
// Find the king of the specified color
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceType === 'king' && piece.pieceColor === color) {
checkedKing = piece;
// Apply red tint to the king with pulsing animation
tween(piece, {
tint: 0xff0000
}, {
duration: 300,
easing: tween.easeOut
});
// Add pulsing scale effect to make it more visible
tween(piece, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(piece, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
return;
}
}
}
}
// Remove highlight from king
function removeKingHighlight() {
if (checkedKing) {
// Reset tint and scale to normal
tween(checkedKing, {
tint: 0xffffff,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
checkedKing = null;
}
}
// Update captured pieces display
function updateCapturedPiecesDisplay() {
// Clear existing captured pieces display (except label)
while (capturedPiecesContainer.children.length > 1) {
capturedPiecesContainer.removeChild(capturedPiecesContainer.children[1]);
}
var yOffset = 20;
var pieceSize = 80;
var spacing = 90;
// Display captured white pieces
for (var i = 0; i < capturedWhitePieces.length; i++) {
var piece = capturedWhitePieces[i];
var displayPiece = new ChessPiece(piece.pieceType, piece.pieceColor, 0, 0);
displayPiece.x = i % 8 * spacing;
displayPiece.y = yOffset + Math.floor(i / 8) * spacing;
displayPiece.scaleX = 0.8;
displayPiece.scaleY = 0.8;
capturedPiecesContainer.addChild(displayPiece);
}
// Display captured black pieces below white pieces
var blackStartY = yOffset + Math.ceil(capturedWhitePieces.length / 8) * spacing + 30;
for (var j = 0; j < capturedBlackPieces.length; j++) {
var piece = capturedBlackPieces[j];
var displayPiece = new ChessPiece(piece.pieceType, piece.pieceColor, 0, 0);
displayPiece.x = j % 8 * spacing;
displayPiece.y = blackStartY + Math.floor(j / 8) * spacing;
displayPiece.scaleX = 0.8;
displayPiece.scaleY = 0.8;
capturedPiecesContainer.addChild(displayPiece);
}
}
// Board constants
var BOARD_SIZE = 8;
var SQUARE_SIZE = 230;
var BOARD_START_X = 2048 / 2 - BOARD_SIZE * SQUARE_SIZE / 2;
var BOARD_START_Y = 2732 / 2 - BOARD_SIZE * SQUARE_SIZE / 2;
// Initialize difficulty selection
function initializeDifficultySelection() {
var easyButton = new DifficultyButton('EASY', 'easy');
easyButton.x = 2048 / 2;
easyButton.y = 2732 / 2 - 200;
game.addChild(easyButton);
difficultyButtons.push(easyButton);
var mediumButton = new DifficultyButton('MEDIUM', 'medium');
mediumButton.x = 2048 / 2;
mediumButton.y = 2732 / 2;
game.addChild(mediumButton);
difficultyButtons.push(mediumButton);
var hardButton = new DifficultyButton('HARD', 'hard');
hardButton.x = 2048 / 2;
hardButton.y = 2732 / 2 + 200;
game.addChild(hardButton);
difficultyButtons.push(hardButton);
var titleText = new Text2('Select Difficulty', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 2732 / 2 - 400;
game.addChild(titleText);
}
// Start the game after difficulty selection
function startGame() {
// Remove difficulty buttons
for (var i = 0; i < difficultyButtons.length; i++) {
game.removeChild(difficultyButtons[i]);
}
difficultyButtons = [];
// Remove title
for (var j = game.children.length - 1; j >= 0; j--) {
var child = game.children[j];
if (child instanceof Text2) {
game.removeChild(child);
}
}
gameState = 'playing';
initializeBoard();
setupInitialPieces();
// Initialize captured pieces area
capturedPiecesContainer = new Container();
capturedPiecesContainer.x = 350;
capturedPiecesContainer.y = 150;
game.addChild(capturedPiecesContainer);
// Add labels for captured pieces
var capturedLabel = new Text2('Captured Pieces', {
size: 70,
fill: 0xFFFFFF
});
capturedLabel.anchor.set(0, 0);
capturedLabel.x = 0;
capturedLabel.y = -120;
capturedPiecesContainer.addChild(capturedLabel);
}
// Initialize the chess board
function initializeBoard() {
board = [];
for (var row = 0; row < BOARD_SIZE; row++) {
board[row] = [];
for (var col = 0; col < BOARD_SIZE; col++) {
var square = new ChessSquare(row, col);
square.x = BOARD_START_X + col * SQUARE_SIZE + SQUARE_SIZE / 2;
square.y = BOARD_START_Y + row * SQUARE_SIZE + SQUARE_SIZE / 2;
game.addChild(square);
board[row][col] = square;
}
}
}
// Setup initial piece positions
function setupInitialPieces() {
var pieceOrder = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'];
// Black pieces (top of board)
for (var col = 0; col < 8; col++) {
var blackPiece = new ChessPiece(pieceOrder[col], 'black', 0, col);
board[0][col].setPiece(blackPiece);
var blackPawn = new ChessPiece('pawn', 'black', 1, col);
board[1][col].setPiece(blackPawn);
}
// White pieces (bottom of board)
for (var col = 0; col < 8; col++) {
var whitePawn = new ChessPiece('pawn', 'white', 6, col);
board[6][col].setPiece(whitePawn);
var whitePiece = new ChessPiece(pieceOrder[col], 'white', 7, col);
board[7][col].setPiece(whitePiece);
}
}
// Get all pseudo-legal moves for a piece (ignores pins and king safety)
function getRawMoves(piece, fromRow, fromCol) {
var moves = [];
var type = piece.pieceType;
var color = piece.pieceColor;
if (type === 'pawn') {
var direction = color === 'white' ? -1 : 1;
var startRow = color === 'white' ? 6 : 1;
// Move forward 1 square (only if empty)
if (isValidPosition(fromRow + direction, fromCol) && !board[fromRow + direction][fromCol].piece) {
moves.push({
row: fromRow + direction,
col: fromCol
});
// Move forward 2 squares from starting position (only if both squares are empty)
if (fromRow === startRow && isValidPosition(fromRow + 2 * direction, fromCol) && !board[fromRow + 2 * direction][fromCol].piece) {
moves.push({
row: fromRow + 2 * direction,
col: fromCol
});
}
}
// Pawn captures diagonally (only if there's an opponent piece)
for (var dc = -1; dc <= 1; dc += 2) {
if (isValidPosition(fromRow + direction, fromCol + dc)) {
var targetPiece = board[fromRow + direction][fromCol + dc].piece;
if (targetPiece && targetPiece.pieceColor !== color) {
moves.push({
row: fromRow + direction,
col: fromCol + dc
});
}
}
}
} else if (type === 'rook') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
for (var d = 0; d < directions.length; d++) {
var dr = directions[d][0];
var dc = directions[d][1];
for (var i = 1; i < 8; i++) {
var newRow = fromRow + dr * i;
var newCol = fromCol + dc * i;
if (!isValidPosition(newRow, newCol)) break;
moves.push({
row: newRow,
col: newCol
});
var targetPiece = board[newRow][newCol].piece;
if (targetPiece) {
break;
}
}
}
} else if (type === 'bishop') {
var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var dr = directions[d][0];
var dc = directions[d][1];
for (var i = 1; i < 8; i++) {
var newRow = fromRow + dr * i;
var newCol = fromCol + dc * i;
if (!isValidPosition(newRow, newCol)) break;
moves.push({
row: newRow,
col: newCol
});
var targetPiece = board[newRow][newCol].piece;
if (targetPiece) {
break;
}
}
}
} else if (type === 'queen') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var dr = directions[d][0];
var dc = directions[d][1];
for (var i = 1; i < 8; i++) {
var newRow = fromRow + dr * i;
var newCol = fromCol + dc * i;
if (!isValidPosition(newRow, newCol)) break;
moves.push({
row: newRow,
col: newCol
});
var targetPiece = board[newRow][newCol].piece;
if (targetPiece) {
break;
}
}
}
} else if (type === 'king') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var newRow = fromRow + directions[d][0];
var newCol = fromCol + directions[d][1];
if (isValidPosition(newRow, newCol)) {
moves.push({
row: newRow,
col: newCol
});
}
}
} else if (type === 'knight') {
var knightMoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]];
for (var m = 0; m < knightMoves.length; m++) {
var newRow = fromRow + knightMoves[m][0];
var newCol = fromCol + knightMoves[m][1];
if (isValidPosition(newRow, newCol)) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
return moves;
}
// Get legal moves for a piece
function getLegalMoves(piece, fromRow, fromCol) {
var moves = [];
var type = piece.pieceType;
var color = piece.pieceColor;
if (type === 'pawn') {
var direction = color === 'white' ? -1 : 1;
var startRow = color === 'white' ? 6 : 1;
// Forward move
if (isValidPosition(fromRow + direction, fromCol) && !board[fromRow + direction][fromCol].piece) {
moves.push({
row: fromRow + direction,
col: fromCol
});
// Two squares forward from starting position
if (fromRow === startRow && !board[fromRow + 2 * direction][fromCol].piece) {
moves.push({
row: fromRow + 2 * direction,
col: fromCol
});
}
}
// Diagonal captures
for (var dc = -1; dc <= 1; dc += 2) {
if (isValidPosition(fromRow + direction, fromCol + dc)) {
var targetPiece = board[fromRow + direction][fromCol + dc].piece;
if (targetPiece && targetPiece.pieceColor !== color) {
moves.push({
row: fromRow + direction,
col: fromCol + dc
});
}
}
}
} else if (type === 'rook') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
for (var d = 0; d < directions.length; d++) {
var dr = directions[d][0];
var dc = directions[d][1];
for (var i = 1; i < 8; i++) {
var newRow = fromRow + dr * i;
var newCol = fromCol + dc * i;
if (!isValidPosition(newRow, newCol)) break;
var targetPiece = board[newRow][newCol].piece;
if (targetPiece) {
if (targetPiece.pieceColor !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
} else {
moves.push({
row: newRow,
col: newCol
});
}
}
}
} else if (type === 'bishop') {
var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var dr = directions[d][0];
var dc = directions[d][1];
for (var i = 1; i < 8; i++) {
var newRow = fromRow + dr * i;
var newCol = fromCol + dc * i;
if (!isValidPosition(newRow, newCol)) break;
var targetPiece = board[newRow][newCol].piece;
if (targetPiece) {
if (targetPiece.pieceColor !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
} else {
moves.push({
row: newRow,
col: newCol
});
}
}
}
} else if (type === 'queen') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var dr = directions[d][0];
var dc = directions[d][1];
for (var i = 1; i < 8; i++) {
var newRow = fromRow + dr * i;
var newCol = fromCol + dc * i;
if (!isValidPosition(newRow, newCol)) break;
var targetPiece = board[newRow][newCol].piece;
if (targetPiece) {
if (targetPiece.pieceColor !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
} else {
moves.push({
row: newRow,
col: newCol
});
}
}
}
} else if (type === 'king') {
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var newRow = fromRow + directions[d][0];
var newCol = fromCol + directions[d][1];
if (isValidPosition(newRow, newCol)) {
var targetPiece = board[newRow][newCol].piece;
if (!targetPiece || targetPiece.pieceColor !== color) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
} else if (type === 'knight') {
var knightMoves = [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]];
for (var m = 0; m < knightMoves.length; m++) {
var newRow = fromRow + knightMoves[m][0];
var newCol = fromCol + knightMoves[m][1];
if (isValidPosition(newRow, newCol)) {
var targetPiece = board[newRow][newCol].piece;
if (!targetPiece || targetPiece.pieceColor !== color) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
}
// Filter out moves that would leave own king in check (pin rule)
var legalMoves = [];
var _loop = function _loop() {
move = moves[i]; // Simulate the move
fromPiece = board[fromRow][fromCol].piece;
toPiece = board[move.row][move.col].piece; // Temporarily move the piece
board[fromRow][fromCol].setPiece(null);
board[move.row][move.col].setPiece(fromPiece);
kingSafe = true; // Find own king position after move
kingRow = -1, kingCol = -1;
for (r = 0; r < BOARD_SIZE; r++) {
for (c = 0; c < BOARD_SIZE; c++) {
p = board[r][c].piece;
if (p && p.pieceType === 'king' && p.pieceColor === color) {
kingRow = r;
kingCol = c;
}
}
}
// If this piece is the king, update kingRow/kingCol to new position
if (type === 'king') {
kingRow = move.row;
kingCol = move.col;
}
// Check if any enemy piece can attack the king after this move
for (r = 0; r < BOARD_SIZE; r++) {
for (c = 0; c < BOARD_SIZE; c++) {
enemy = board[r][c].piece;
if (enemy && enemy.pieceColor !== color) {
enemyMoves = getRawMoves(enemy, r, c);
for (j = 0; j < enemyMoves.length; j++) {
if (enemyMoves[j].row === kingRow && enemyMoves[j].col === kingCol) {
kingSafe = false;
break;
}
}
}
if (!kingSafe) break;
}
if (!kingSafe) break;
}
// Undo the move
board[move.row][move.col].setPiece(toPiece);
board[fromRow][fromCol].setPiece(fromPiece);
if (kingSafe) {
legalMoves.push(move);
}
},
move,
fromPiece,
toPiece,
kingSafe,
kingRow,
kingCol,
r,
c,
p,
r,
c,
enemy,
enemyMoves,
j;
for (var i = 0; i < moves.length; i++) {
_loop();
}
return legalMoves;
}
// Check if position is valid on board
function isValidPosition(row, col) {
return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
}
// Highlight possible moves
function highlightMoves(moves) {
for (var i = 0; i < moves.length; i++) {
board[moves[i].row][moves[i].col].highlight();
}
}
// Clear all highlights
function clearHighlights() {
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
board[row][col].removeHighlight();
}
}
}
// Make a move
function makeMove(fromRow, fromCol, toRow, toCol) {
var piece = board[fromRow][fromCol].piece;
var capturedPiece = board[toRow][toCol].piece;
// Prevent capturing the king
if (capturedPiece && capturedPiece.pieceType === 'king') {
// Invalid move: cannot capture king, revert and return
// Return piece to original position if dragged
if (draggedPiece) {
game.removeChild(draggedPiece);
board[fromRow][fromCol].setPiece(draggedPiece);
}
clearHighlights();
draggedPiece = null;
selectedSquare = null;
possibleMoves = [];
return;
}
// Calculate target position
var targetX = BOARD_START_X + toCol * SQUARE_SIZE + SQUARE_SIZE / 2;
var targetY = BOARD_START_Y + toRow * SQUARE_SIZE + SQUARE_SIZE / 2;
// Check if this is an AI move (piece is black and not being dragged)
var isAIMove = piece.pieceColor === 'black' && !draggedPiece;
if (isAIMove) {
// For AI moves, animate the piece movement
// First, bring piece to game level for animation
var currentSquare = board[fromRow][fromCol];
var currentGlobalPos = currentSquare.toGlobal(piece.position);
currentSquare.removeChild(piece);
game.addChild(piece);
piece.x = currentGlobalPos.x;
piece.y = currentGlobalPos.y;
// Remove piece from old position on board
board[fromRow][fromCol].setPiece(null);
// Handle captured piece animation if there's a capture
if (capturedPiece) {
// Create explosion effect at capture location
var explosionX = BOARD_START_X + toCol * SQUARE_SIZE + SQUARE_SIZE / 2;
var explosionY = BOARD_START_Y + toRow * SQUARE_SIZE + SQUARE_SIZE / 2;
createExplosionEffect(explosionX, explosionY);
// Add to captured pieces array
if (capturedPiece.pieceColor === 'white') {
capturedWhitePieces.push({
pieceType: capturedPiece.pieceType,
pieceColor: capturedPiece.pieceColor
});
} else {
capturedBlackPieces.push({
pieceType: capturedPiece.pieceType,
pieceColor: capturedPiece.pieceColor
});
}
// Remove captured piece from board immediately
board[toRow][toCol].setPiece(null);
// Animate captured piece moving to captured area
var capturedTargetX = capturedPiecesContainer.x;
var capturedTargetY = capturedPiecesContainer.y + 100;
// First animate to captured area, then scale down
tween(capturedPiece, {
x: capturedTargetX,
y: capturedTargetY,
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Then fade out and destroy
tween(capturedPiece, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
// Destroy the captured piece and update display
capturedPiece.destroy();
updateCapturedPiecesDisplay();
}
});
}
});
}
// Set piece in new position but don't add to square yet
board[toRow][toCol].piece = piece;
piece.updateBoardPosition(toRow, toCol);
// Animate piece to target position
tween(piece, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Move piece from game to target square
game.removeChild(piece);
board[toRow][toCol].setPiece(piece);
// Play sound after animation
if (capturedPiece) {
LK.getSound('captureSound').play();
} else {
LK.getSound('moveSound').play();
}
// Check for pawn promotion
if (piece.pieceType === 'pawn') {
if (piece.pieceColor === 'white' && toRow === 0 || piece.pieceColor === 'black' && toRow === 7) {
// Promote to queen
board[toRow][toCol].setPiece(null);
var promotedQueen = new ChessPiece('queen', piece.pieceColor, toRow, toCol);
board[toRow][toCol].setPiece(promotedQueen);
}
}
// Switch turns
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
// Remove previous king highlight if king is no longer in check
if (checkedKing && !isInCheck(checkedKing.pieceColor)) {
removeKingHighlight();
}
// Reset AI move flag when switching turns
if (currentPlayer === 'black') {
aiHasMoved = false;
}
// Reset dragged piece to null to re-enable piece interaction
draggedPiece = null;
// Check for game end conditions first
if (isCheckmate(currentPlayer)) {
// Highlight the checkmated king
highlightCheckedKing(currentPlayer);
// Play checkmate sound
LK.getSound('checkmateSound').play();
// Create rainbow checkmate text
var checkmateText = new Text2('Check Mate!', {
size: 150,
fill: 0xff0000 // Start with red
});
checkmateText.anchor.set(0.5, 0.5);
checkmateText.x = 2048 / 2;
checkmateText.y = 300;
game.addChild(checkmateText);
// Rainbow color animation - cycle through colors
var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff];
var colorIndex = 0;
var colorTimer = LK.setInterval(function () {
colorIndex = (colorIndex + 1) % colors.length;
checkmateText.tint = colors[colorIndex];
}, 100);
// Fade out the text slowly
tween(checkmateText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.clearInterval(colorTimer);
game.removeChild(checkmateText);
}
});
// End game 1 second after checkmate text appears
LK.setTimeout(function () {
if (currentPlayer === 'white') {
LK.showGameOver();
} else {
LK.showYouWin();
}
gameState = 'gameOver';
}, 1000);
} else if (isStalemate(currentPlayer)) {
LK.showGameOver(); // Show as draw
gameState = 'gameOver';
} else if (isInCheck(currentPlayer)) {
// Highlight the checked king
highlightCheckedKing(currentPlayer);
// Play check sound
LK.getSound('checkSound').play();
// Create rainbow check text
var checkText = new Text2('Check!', {
size: 120,
fill: 0xff0000 // Start with red
});
checkText.anchor.set(0.5, 0.5);
checkText.x = 2048 / 2;
checkText.y = 300;
game.addChild(checkText);
// Rainbow color animation - cycle through colors
var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff];
var colorIndex = 0;
var colorTimer = LK.setInterval(function () {
colorIndex = (colorIndex + 1) % colors.length;
checkText.tint = colors[colorIndex];
}, 100);
// Fade out the text slowly
tween(checkText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.clearInterval(colorTimer);
game.removeChild(checkText);
}
});
}
}
});
} else {
// For player moves, animate the piece smoothly to target position
// Remove piece from old position
board[fromRow][fromCol].setPiece(null);
// Set piece in new position but don't add to square yet
board[toRow][toCol].piece = piece;
piece.updateBoardPosition(toRow, toCol);
// Add capture animation if there's a captured piece
if (capturedPiece) {
// Create explosion effect at capture location
createExplosionEffect(targetX, targetY);
// Add to captured pieces array
if (capturedPiece.pieceColor === 'white') {
capturedWhitePieces.push({
pieceType: capturedPiece.pieceType,
pieceColor: capturedPiece.pieceColor
});
} else {
capturedBlackPieces.push({
pieceType: capturedPiece.pieceType,
pieceColor: capturedPiece.pieceColor
});
}
// Animate captured piece moving to captured area first
var capturedTargetX = capturedPiecesContainer.x;
var capturedTargetY = capturedPiecesContainer.y + 100;
tween(capturedPiece, {
x: capturedTargetX,
y: capturedTargetY,
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Then scale down the captured piece before removing
tween(capturedPiece, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
// Captured piece animation complete
updateCapturedPiecesDisplay();
}
});
}
});
}
// Animate piece to target position
tween(piece, {
x: targetX,
y: targetY
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
// Move piece from game to target square
game.removeChild(piece);
board[toRow][toCol].setPiece(piece);
// Play sound after animation
if (capturedPiece) {
LK.getSound('captureSound').play();
} else {
LK.getSound('moveSound').play();
}
// Check for pawn promotion
if (piece.pieceType === 'pawn') {
if (piece.pieceColor === 'white' && toRow === 0 || piece.pieceColor === 'black' && toRow === 7) {
// Promote to queen
board[toRow][toCol].setPiece(null);
var promotedQueen = new ChessPiece('queen', piece.pieceColor, toRow, toCol);
board[toRow][toCol].setPiece(promotedQueen);
}
}
// Switch turns
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
// Remove previous king highlight if king is no longer in check
if (checkedKing && !isInCheck(checkedKing.pieceColor)) {
removeKingHighlight();
}
// Reset AI move flag when switching turns
if (currentPlayer === 'black') {
aiHasMoved = false;
}
// Reset dragged piece to null to re-enable piece interaction
draggedPiece = null;
// Check for game end conditions first
if (isCheckmate(currentPlayer)) {
// Highlight the checkmated king
highlightCheckedKing(currentPlayer);
// Play checkmate sound
LK.getSound('checkmateSound').play();
// Create rainbow checkmate text
var checkmateText = new Text2('Check Mate!', {
size: 150,
fill: 0xff0000 // Start with red
});
checkmateText.anchor.set(0.5, 0.5);
checkmateText.x = 2048 / 2;
checkmateText.y = 300;
game.addChild(checkmateText);
// Rainbow color animation - cycle through colors
var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff];
var colorIndex = 0;
var colorTimer = LK.setInterval(function () {
colorIndex = (colorIndex + 1) % colors.length;
checkmateText.tint = colors[colorIndex];
}, 100);
// Fade out the text slowly
tween(checkmateText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.clearInterval(colorTimer);
game.removeChild(checkmateText);
}
});
// End game 1 second after checkmate text appears
LK.setTimeout(function () {
if (currentPlayer === 'white') {
LK.showGameOver();
} else {
LK.showYouWin();
}
gameState = 'gameOver';
}, 1000);
} else if (isStalemate(currentPlayer)) {
LK.showGameOver(); // Show as draw
gameState = 'gameOver';
} else if (isInCheck(currentPlayer)) {
// Highlight the checked king
highlightCheckedKing(currentPlayer);
// Play check sound
LK.getSound('checkSound').play();
// Create rainbow check text
var checkText = new Text2('Check!', {
size: 120,
fill: 0xff0000 // Start with red
});
checkText.anchor.set(0.5, 0.5);
checkText.x = 2048 / 2;
checkText.y = 300;
game.addChild(checkText);
// Rainbow color animation - cycle through colors
var colors = [0xff0000, 0xff8800, 0xffff00, 0x00ff00, 0x0088ff, 0x0000ff, 0x8800ff];
var colorIndex = 0;
var colorTimer = LK.setInterval(function () {
colorIndex = (colorIndex + 1) % colors.length;
checkText.tint = colors[colorIndex];
}, 100);
// Fade out the text slowly
tween(checkText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.clearInterval(colorTimer);
game.removeChild(checkText);
}
});
}
}
});
}
}
// Check if a king is in check
function isInCheck(color) {
// Find king position
var kingPos = null;
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceType === 'king' && piece.pieceColor === color) {
kingPos = {
row: row,
col: col
};
break;
}
}
if (kingPos) break;
}
if (!kingPos) return false; // No king found
// Check if any enemy piece can attack the king
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceColor !== color) {
var moves = getRawMoves(piece, row, col);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === kingPos.row && moves[i].col === kingPos.col) {
return true; // King is under attack
}
}
}
}
}
return false; // King is safe
}
// Simple checkmate detection - king must be in check AND have no legal moves
function isCheckmate(color) {
// First check if king is in check
if (!isInCheck(color)) {
return false; // Not checkmate if king is not in check
}
// Find king
var kingPos = null;
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceType === 'king' && piece.pieceColor === color) {
kingPos = {
row: row,
col: col
};
break;
}
}
if (kingPos) break;
}
if (!kingPos) return true; // No king found
// Check if any piece can make a legal move
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceColor === color) {
var moves = getLegalMoves(piece, row, col);
if (moves.length > 0) {
return false; // Found a legal move
}
}
}
}
return true; // No legal moves found and king is in check
}
// Simple stalemate detection - king is NOT in check but has no legal moves
function isStalemate(color) {
// First check if king is in check
if (isInCheck(color)) {
return false; // Not stalemate if king is in check
}
// Check if any piece can make a legal move
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceColor === color) {
var moves = getLegalMoves(piece, row, col);
if (moves.length > 0) {
return false; // Found a legal move
}
}
}
}
return true; // No legal moves found but king is not in check
}
// AI move selection based on difficulty
function getAIMove() {
var allMoves = [];
// Get all possible moves for AI (black pieces)
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
var piece = board[row][col].piece;
if (piece && piece.pieceColor === 'black') {
var moves = getLegalMoves(piece, row, col);
for (var m = 0; m < moves.length; m++) {
// Prevent AI from selecting a move that would capture the king
var target = board[moves[m].row][moves[m].col].piece;
if (target && target.pieceType === 'king') {
continue;
}
allMoves.push({
fromRow: row,
fromCol: col,
toRow: moves[m].row,
toCol: moves[m].col,
piece: piece
});
}
}
}
}
if (allMoves.length === 0) return null;
if (selectedDifficulty === 'easy') {
// Random move
return allMoves[Math.floor(Math.random() * allMoves.length)];
} else if (selectedDifficulty === 'medium') {
// Prefer captures
var captures = [];
for (var i = 0; i < allMoves.length; i++) {
var move = allMoves[i];
if (board[move.toRow][move.toCol].piece) {
captures.push(move);
}
}
if (captures.length > 0) {
return captures[Math.floor(Math.random() * captures.length)];
}
return allMoves[Math.floor(Math.random() * allMoves.length)];
} else {
// Hard: prefer captures, then center moves
var captures = [];
var centerMoves = [];
for (var i = 0; i < allMoves.length; i++) {
var move = allMoves[i];
if (board[move.toRow][move.toCol].piece) {
captures.push(move);
} else if (move.toRow >= 3 && move.toRow <= 4 && move.toCol >= 3 && move.toCol <= 4) {
centerMoves.push(move);
}
}
if (captures.length > 0) {
return captures[Math.floor(Math.random() * captures.length)];
}
if (centerMoves.length > 0) {
return centerMoves[Math.floor(Math.random() * centerMoves.length)];
}
return allMoves[Math.floor(Math.random() * allMoves.length)];
}
}
// Get board position from screen coordinates
function getBoardPosition(x, y) {
var col = Math.floor((x - BOARD_START_X) / SQUARE_SIZE);
var row = Math.floor((y - BOARD_START_Y) / SQUARE_SIZE);
if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE) {
return {
row: row,
col: col
};
}
return null;
}
// Handle mouse/touch down
game.down = function (x, y, obj) {
if (gameState !== 'playing' || currentPlayer !== 'white') return;
var pos = getBoardPosition(x, y);
if (!pos) return;
var square = board[pos.row][pos.col];
var piece = square.piece;
if (piece && piece.pieceColor === 'white') {
// Start dragging
draggedPiece = piece;
// Set drag offset to zero so piece stays at click position
dragOffset.x = 0;
dragOffset.y = 0;
// Clear previous highlights
clearHighlights();
// Highlight possible moves
possibleMoves = getLegalMoves(piece, pos.row, pos.col);
highlightMoves(possibleMoves);
selectedSquare = {
row: pos.row,
col: pos.col
};
// Bring piece to front but keep it at current position
var tempParent = piece.parent;
var currentGlobalPos = tempParent.toGlobal(piece.position);
tempParent.removeChild(piece);
game.addChild(piece);
piece.x = currentGlobalPos.x;
piece.y = currentGlobalPos.y;
// Add selection animation
tween(piece, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150,
easing: tween.easeOut
});
}
};
// Handle mouse/touch move
game.move = function (x, y, obj) {
if (draggedPiece) {
draggedPiece.x = x;
draggedPiece.y = y;
}
};
// Handle mouse/touch up
game.up = function (x, y, obj) {
if (!draggedPiece || gameState !== 'playing') return;
var pos = getBoardPosition(x, y);
var validMove = false;
if (pos && selectedSquare) {
// Check if this is a valid move
for (var i = 0; i < possibleMoves.length; i++) {
if (possibleMoves[i].row === pos.row && possibleMoves[i].col === pos.col) {
validMove = true;
break;
}
}
if (validMove) {
// Prevent player from capturing the king
var targetPiece = board[pos.row][pos.col].piece;
if (targetPiece && targetPiece.pieceType === 'king') {
// Invalid move: cannot capture king, revert and return
game.removeChild(draggedPiece);
board[selectedSquare.row][selectedSquare.col].setPiece(draggedPiece);
clearHighlights();
draggedPiece = null;
selectedSquare = null;
possibleMoves = [];
return;
}
// Make the move
makeMove(selectedSquare.row, selectedSquare.col, pos.row, pos.col);
// Clear selection state after valid move
selectedSquare = null;
possibleMoves = [];
}
}
if (!validMove && selectedSquare) {
// Return piece to original position with animation
var originalSquare = board[selectedSquare.row][selectedSquare.col];
var originalX = BOARD_START_X + selectedSquare.col * SQUARE_SIZE + SQUARE_SIZE / 2;
var originalY = BOARD_START_Y + selectedSquare.row * SQUARE_SIZE + SQUARE_SIZE / 2;
// Reset scale and animate back to original position
tween(draggedPiece, {
x: originalX,
y: originalY,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(draggedPiece);
originalSquare.setPiece(draggedPiece);
// Reset dragging state after animation completes
draggedPiece = null;
selectedSquare = null;
possibleMoves = [];
}
});
// Clear highlights immediately
clearHighlights();
} else {
// Reset scale for valid moves
if (draggedPiece) {
tween(draggedPiece, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
// Clean up for valid moves
clearHighlights();
draggedPiece = null;
selectedSquare = null;
possibleMoves = [];
}
};
// Game update loop
game.update = function () {
if (gameState === 'playing' && currentPlayer === 'black' && !draggedPiece && !aiHasMoved) {
// AI turn - only if player is not currently dragging a piece and AI hasn't moved yet
if (LK.ticks % 60 === 0) {
// Wait 1 second before AI move
aiHasMoved = true; // Set flag immediately to prevent multiple moves
LK.setTimeout(function () {
var aiMove = getAIMove();
if (aiMove) {
makeMove(aiMove.fromRow, aiMove.fromCol, aiMove.toRow, aiMove.toCol);
}
}, 1000);
}
}
};
// Play background music
LK.playMusic('Game_music');
// Initialize the game
if (gameState === 'difficulty') {
initializeDifficultySelection();
}
Chess pawn View from above. In-Game asset. 2d. High contrast. No shadows
Chess king view from above. In-Game asset. 2d. High contrast. No shadows
Chess White king view from top. In-Game asset. 2d. High contrast. No shadows
Chess queen white View from above. In-Game asset. 2d. High contrast. No shadows
Chess black bishop. In-Game asset. 2d. High contrast. No shadows
Chess black queen. In-Game asset. 2d. High contrast. No shadows
Chess black knight. In-Game asset. 2d. High contrast. No shadows
Chess rook view from above. In-Game asset. 2d. High contrast. No shadows
Chess bishop white view frome above. In-Game asset. 2d. High contrast. No shadows
Şimdi içini beyaz renkle doldur