Code edit (1 edits merged)
Please save this source code
User prompt
Star Chess Arena
Initial prompt
Create a two-player chess game mobile app using Flutter (for Android and iOS). Each player starts with 10 stars. Before each game, both players bet any number of stars from 0 to 10. The winner takes all the stars that were bet. Update each player's star count accordingly. The app should allow real-time multiplayer via online matchmaking or QR code pairing. Make the UI clean, modern, and mobile-friendly.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var ChessPiece = Container.expand(function (type, color, row, col) { var self = Container.call(this); self.pieceType = type; self.color = color; self.row = row; self.col = col; self.hasMoved = false; var pieceTypeMap = { 'pawn': color === 'white' ? 'beyazPiyon' : 'siyahPiyon', 'rook': color === 'white' ? 'beyazKale' : 'siyahKale', 'knight': color === 'white' ? 'beyazAt' : 'siyahAt', 'bishop': color === 'white' ? 'beyazFil' : 'siyahFil', 'queen': color === 'white' ? 'beyazVezir' : 'siyahVezir', 'king': color === 'white' ? 'beyazSah' : 'siyahSah' }; var assetId = pieceTypeMap[type]; var pieceGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { if (gameState !== 'playing' || isAiTurn) return; if (currentPlayer === self.color) { // Select this piece if it belongs to current player selectedPiece = self; selectedSquare = { row: self.row, col: self.col }; validMoves = getValidMoves(self); updateBoardDisplay(); } else if (selectedPiece && isValidMove(selectedPiece.row, selectedPiece.col, self.row, self.col)) { // If clicking on opponent piece and it's a valid capture move movePiece(selectedPiece, self.row, self.col); } }; return self; }); var Square = Container.expand(function (row, col, isLight) { var self = Container.call(this); self.row = row; self.col = col; self.isLight = isLight; self.piece = null; var squareGraphics = self.attachAsset(isLight ? 'lightSquare' : 'darkSquare', { anchorX: 0, anchorY: 0 }); self.down = function (x, y, obj) { if (gameState !== 'playing' || isAiTurn) return; if (selectedPiece && isValidMove(selectedPiece.row, selectedPiece.col, self.row, self.col)) { movePiece(selectedPiece, self.row, self.col); } else { // Check if there's a piece on this square that belongs to current player var pieceOnSquare = board[self.row][self.col]; if (pieceOnSquare && pieceOnSquare.color === currentPlayer) { // Select this piece if it belongs to current player selectedPiece = pieceOnSquare; selectedSquare = { row: self.row, col: self.col }; validMoves = getValidMoves(pieceOnSquare); updateBoardDisplay(); } else { clearSelection(); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1e293b }); /**** * Game Code ****/ // Game state variables var gameState = 'difficultySelection'; // 'difficultySelection', 'betting', 'playing', 'gameOver' var currentPlayer = 'white'; var selectedPiece = null; var selectedSquare = null; var validMoves = []; var board = []; var pieces = []; // Player data var playerStars = storage.playerStars || 10; var opponentStars = storage.opponentStars || 10; var playerBet = 0; var opponentBet = 0; var betPhase = 'playerBetting'; // 'playerBetting', 'opponentBetting', 'waitingForOpponent' // AI system var aiDifficulty = storage.aiDifficulty || 1; // 1-5 difficulty levels var aiThinkingTime = 1000; // Base thinking time in milliseconds var isAiTurn = false; // UI elements var boardContainer = new Container(); var squareOverlays = []; var starDisplay, betDisplay, gameStatusDisplay, difficultyUI = []; // Initialize chess board function initializeBoard() { board = []; pieces = []; // Create 8x8 board for (var row = 0; row < 8; row++) { board[row] = []; for (var col = 0; col < 8; col++) { board[row][col] = null; } } // Setup initial piece positions - standard chess layout var backRankSetup = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook']; // Place black pieces (rows 0-1, top of board) // Row 0: Black back rank for (var col = 0; col < 8; col++) { var piece = new ChessPiece(backRankSetup[col], 'black', 0, col); pieces.push(piece); board[0][col] = piece; boardContainer.addChild(piece); piece.x = col * 225 + 112.5; piece.y = 0 * 225 + 112.5; } // Row 1: Black pawns for (var col = 0; col < 8; col++) { var piece = new ChessPiece('pawn', 'black', 1, col); pieces.push(piece); board[1][col] = piece; boardContainer.addChild(piece); piece.x = col * 225 + 112.5; piece.y = 1 * 225 + 112.5; } // Place white pieces (rows 6-7, bottom of board) // Row 6: White pawns for (var col = 0; col < 8; col++) { var piece = new ChessPiece('pawn', 'white', 6, col); pieces.push(piece); board[6][col] = piece; boardContainer.addChild(piece); piece.x = col * 225 + 112.5; piece.y = 6 * 225 + 112.5; } // Row 7: White back rank for (var col = 0; col < 8; col++) { var piece = new ChessPiece(backRankSetup[col], 'white', 7, col); pieces.push(piece); board[7][col] = piece; boardContainer.addChild(piece); piece.x = col * 225 + 112.5; piece.y = 7 * 225 + 112.5; } } // Create visual board squares function createBoardDisplay() { boardContainer.x = 124; boardContainer.y = 466; game.addChild(boardContainer); // Create board background var boardBg = boardContainer.attachAsset('chessBoard', { anchorX: 0, anchorY: 0 }); // Create squares for (var row = 0; row < 8; row++) { squareOverlays[row] = []; for (var col = 0; col < 8; col++) { var isLight = (row + col) % 2 === 0; var square = new Square(row, col, isLight); square.x = col * 225; square.y = row * 225; boardContainer.addChild(square); squareOverlays[row][col] = square; } } } // Get raw moves for a piece without check validation (to prevent infinite recursion) function getRawMoves(piece) { var moves = []; if (piece.pieceType === 'pawn') { var direction = piece.color === 'white' ? -1 : 1; var startRow = piece.color === 'white' ? 6 : 1; // Forward move if (isValidSquare(piece.row + direction, piece.col) && !board[piece.row + direction][piece.col]) { moves.push({ row: piece.row + direction, col: piece.col }); // Double move from start if (piece.row === startRow && !board[piece.row + 2 * direction][piece.col]) { moves.push({ row: piece.row + 2 * direction, col: piece.col }); } } // Captures for (var dc = -1; dc <= 1; dc += 2) { var newRow = piece.row + direction; var newCol = piece.col + dc; if (isValidSquare(newRow, newCol) && board[newRow][newCol] && board[newRow][newCol].color !== piece.color) { moves.push({ row: newRow, col: newCol }); } } } else if (piece.pieceType === 'rook') { // Horizontal and vertical moves var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]; for (var d = 0; d < directions.length; d++) { var dir = directions[d]; for (var i = 1; i < 8; i++) { var newRow = piece.row + dir[0] * i; var newCol = piece.col + dir[1] * i; if (!isValidSquare(newRow, newCol)) break; var targetPiece = board[newRow][newCol]; if (!targetPiece) { moves.push({ row: newRow, col: newCol }); } else { if (targetPiece.color !== piece.color) { moves.push({ row: newRow, col: newCol }); } break; } } } } else if (piece.pieceType === 'bishop') { // Diagonal moves var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]]; for (var d = 0; d < directions.length; d++) { var dir = directions[d]; for (var i = 1; i < 8; i++) { var newRow = piece.row + dir[0] * i; var newCol = piece.col + dir[1] * i; if (!isValidSquare(newRow, newCol)) break; var targetPiece = board[newRow][newCol]; if (!targetPiece) { moves.push({ row: newRow, col: newCol }); } else { if (targetPiece.color !== piece.color) { moves.push({ row: newRow, col: newCol }); } break; } } } } else if (piece.pieceType === 'queen') { // Combination of rook and bishop moves 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 dir = directions[d]; for (var i = 1; i < 8; i++) { var newRow = piece.row + dir[0] * i; var newCol = piece.col + dir[1] * i; if (!isValidSquare(newRow, newCol)) break; var targetPiece = board[newRow][newCol]; if (!targetPiece) { moves.push({ row: newRow, col: newCol }); } else { if (targetPiece.color !== piece.color) { moves.push({ row: newRow, col: newCol }); } break; } } } } else if (piece.pieceType === 'king') { // One square in any direction 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 dir = directions[d]; var newRow = piece.row + dir[0]; var newCol = piece.col + dir[1]; if (isValidSquare(newRow, newCol)) { var targetPiece = board[newRow][newCol]; if (!targetPiece || targetPiece.color !== piece.color) { moves.push({ row: newRow, col: newCol }); } } } // Castling moves if (!piece.hasMoved) { var kingRow = piece.row; // Kingside castling (short castling) var kingsideRook = board[kingRow][7]; if (kingsideRook && kingsideRook.pieceType === 'rook' && kingsideRook.color === piece.color && !kingsideRook.hasMoved) { // Check if squares between king and rook are empty if (!board[kingRow][5] && !board[kingRow][6]) { // For now, add the move (should also check if king passes through check) moves.push({ row: kingRow, col: 6, isCastling: true, castlingType: 'kingside' }); } } // Queenside castling (long castling) var queensideRook = board[kingRow][0]; if (queensideRook && queensideRook.pieceType === 'rook' && queensideRook.color === piece.color && !queensideRook.hasMoved) { // Check if squares between king and rook are empty if (!board[kingRow][1] && !board[kingRow][2] && !board[kingRow][3]) { // For now, add the move (should also check if king passes through check) moves.push({ row: kingRow, col: 2, isCastling: true, castlingType: 'queenside' }); } } } } else if (piece.pieceType === 'knight') { // L-shaped moves var knightMoves = [[2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2]]; for (var m = 0; m < knightMoves.length; m++) { var move = knightMoves[m]; var newRow = piece.row + move[0]; var newCol = piece.col + move[1]; if (isValidSquare(newRow, newCol)) { var targetPiece = board[newRow][newCol]; if (!targetPiece || targetPiece.color !== piece.color) { moves.push({ row: newRow, col: newCol }); } } } } return moves; } // Get valid moves for a piece function getValidMoves(piece) { var moves = getRawMoves(piece); // Filter out moves that would leave the king in check var legalMoves = []; for (var i = 0; i < moves.length; i++) { var move = moves[i]; if (!wouldMoveLeaveKingInCheck(piece, move.row, move.col)) { legalMoves.push(move); } } return legalMoves; } function isValidSquare(row, col) { return row >= 0 && row < 8 && col >= 0 && col < 8; } function isInCheck(playerColor) { // Find the king of the specified color var king = null; for (var i = 0; i < pieces.length; i++) { if (pieces[i].pieceType === 'king' && pieces[i].color === playerColor) { king = pieces[i]; break; } } if (!king) return false; // Check if any opponent piece can attack the king for (var i = 0; i < pieces.length; i++) { var piece = pieces[i]; if (piece.color !== playerColor) { var moves = getRawMoves(piece); for (var j = 0; j < moves.length; j++) { if (moves[j].row === king.row && moves[j].col === king.col) { return true; } } } } return false; } function wouldMoveLeaveKingInCheck(piece, toRow, toCol) { // Save current state var originalRow = piece.row; var originalCol = piece.col; var capturedPiece = board[toRow][toCol]; var wasInPiecesArray = false; var capturedIndex = -1; // Find captured piece index if it exists if (capturedPiece) { for (var i = 0; i < pieces.length; i++) { if (pieces[i] === capturedPiece) { capturedIndex = i; wasInPiecesArray = true; break; } } } // Temporarily make the move board[originalRow][originalCol] = null; board[toRow][toCol] = piece; piece.row = toRow; piece.col = toCol; // Remove captured piece from pieces array temporarily if (capturedPiece && wasInPiecesArray) { pieces.splice(capturedIndex, 1); } // Check if this move leaves the king in check var kingInCheck = isInCheck(piece.color); // Restore original state board[originalRow][originalCol] = piece; board[toRow][toCol] = capturedPiece; piece.row = originalRow; piece.col = originalCol; // Restore captured piece to pieces array if (capturedPiece && wasInPiecesArray) { pieces.splice(capturedIndex, 0, capturedPiece); } return kingInCheck; } function isValidMove(fromRow, fromCol, toRow, toCol) { // The validMoves array is already filtered by getValidMoves to exclude moves that leave king in check for (var i = 0; i < validMoves.length; i++) { if (validMoves[i].row === toRow && validMoves[i].col === toCol) { return true; } } return false; } function movePiece(piece, newRow, newCol) { // Check if this is a castling move var isCastlingMove = false; var castlingType = ''; if (piece.pieceType === 'king' && !piece.hasMoved && Math.abs(newCol - piece.col) === 2) { isCastlingMove = true; castlingType = newCol > piece.col ? 'kingside' : 'queenside'; } var capturedPiece = board[newRow][newCol]; // Handle capture first (before moving the piece) if (capturedPiece && capturedPiece.color !== piece.color) { // Remove captured piece from pieces array for (var i = pieces.length - 1; i >= 0; i--) { if (pieces[i] === capturedPiece) { pieces.splice(i, 1); break; } } // Remove captured piece from board container if (capturedPiece.parent) { capturedPiece.parent.removeChild(capturedPiece); } // Destroy the visual representation capturedPiece.destroy(); LK.getSound('yeme').play(); } else { LK.getSound('hareket').play(); } // Remove piece from old position on board board[piece.row][piece.col] = null; // Update piece position data piece.row = newRow; piece.col = newCol; piece.hasMoved = true; // Place piece in new position on board board[newRow][newCol] = piece; // Handle castling - move the rook if (isCastlingMove) { LK.getSound('rok').play(); var rookOldCol, rookNewCol; if (castlingType === 'kingside') { rookOldCol = 7; rookNewCol = 5; } else { // queenside rookOldCol = 0; rookNewCol = 3; } var rook = board[newRow][rookOldCol]; if (rook) { // Remove rook from old position board[newRow][rookOldCol] = null; // Update rook position rook.row = newRow; rook.col = rookNewCol; rook.hasMoved = true; // Place rook in new position board[newRow][rookNewCol] = rook; // Animate rook movement tween(rook, { x: rookNewCol * 225 + 112.5, y: newRow * 225 + 112.5 }, { duration: 300, easing: tween.easeOut }); } } // Animate piece movement tween(piece, { x: newCol * 225 + 112.5, y: newRow * 225 + 112.5 }, { duration: 300, easing: tween.easeOut }); // Clear selection clearSelection(); // Switch turns currentPlayer = currentPlayer === 'white' ? 'black' : 'white'; // Check if the current player is in check if (isInCheck(currentPlayer)) { LK.getSound('sah').play(); } updateGameStatus(); // Check for pawn promotion if (piece.pieceType === 'pawn' && (piece.row === 0 || piece.row === 7)) { LK.getSound('terfi').play(); if (piece.color === 'black') { // AI auto-promotes to queen promotePiece(piece, 'queen'); } else { showPromotionDialog(piece); } } // Check for game over conditions checkGameOver(); // Trigger AI move if it's AI's turn if (currentPlayer === 'black' && gameState === 'playing') { makeAIMove(); } } function clearSelection() { selectedPiece = null; selectedSquare = null; validMoves = []; updateBoardDisplay(); } function updateBoardDisplay() { // Clear all overlays for (var row = 0; row < 8; row++) { for (var col = 0; col < 8; col++) { var square = squareOverlays[row][col]; square.removeChildren(); var isLight = (row + col) % 2 === 0; var squareGraphics = square.attachAsset(isLight ? 'lightSquare' : 'darkSquare', { anchorX: 0, anchorY: 0 }); } } // Show selected square if (selectedSquare) { var selectedSquareOverlay = squareOverlays[selectedSquare.row][selectedSquare.col]; selectedSquareOverlay.removeChildren(); var selectedGraphics = selectedSquareOverlay.attachAsset('selectedSquare', { anchorX: 0, anchorY: 0 }); } // Show valid moves for (var i = 0; i < validMoves.length; i++) { var move = validMoves[i]; var moveSquare = squareOverlays[move.row][move.col]; moveSquare.removeChildren(); var moveGraphics = moveSquare.attachAsset('validMoveSquare', { anchorX: 0, anchorY: 0 }); } } function checkGameOver() { // Simple game over check - if king is captured var whiteKingExists = false; var blackKingExists = false; for (var i = 0; i < pieces.length; i++) { var piece = pieces[i]; if (piece.pieceType === 'king') { if (piece.color === 'white') whiteKingExists = true; if (piece.color === 'black') blackKingExists = true; } } if (!whiteKingExists) { endGame('black'); } else if (!blackKingExists) { endGame('white'); } else { // Check for checkmate - player in check with no legal moves if (isInCheck(currentPlayer)) { var hasLegalMoves = false; for (var i = 0; i < pieces.length && !hasLegalMoves; i++) { var piece = pieces[i]; if (piece.color === currentPlayer) { var legalMoves = getValidMoves(piece); if (legalMoves.length > 0) { hasLegalMoves = true; } } } if (!hasLegalMoves) { // Checkmate - current player loses var winner = currentPlayer === 'white' ? 'black' : 'white'; endGame(winner); } } } } function endGame(winner) { gameState = 'gameOver'; LK.getSound('bitis').play(); // Award stars if (winner === 'white') { playerStars += opponentBet; opponentStars -= opponentBet; } else { playerStars -= playerBet; opponentStars += playerBet; } // Save to storage storage.playerStars = playerStars; storage.opponentStars = opponentStars; updateStarDisplay(); if (winner === 'white') { LK.showYouWin(); } else { LK.showGameOver(); } } function createUI() { // Star display starDisplay = new Text2('Yıldızlar: ' + playerStars, { size: 60, fill: 0xFFFFFF }); starDisplay.anchor.set(0.5, 0); LK.gui.top.addChild(starDisplay); starDisplay.y = 100; // Game status display gameStatusDisplay = new Text2('AI zorluk seviyesi seçin', { size: 50, fill: 0xFFFFFF }); gameStatusDisplay.anchor.set(0.5, 0); LK.gui.top.addChild(gameStatusDisplay); gameStatusDisplay.y = 180; // Start with difficulty selection createDifficultySelectionUI(); } function createDifficultySelectionUI() { // Skip difficulty selection, go directly to betting gameState = 'betting'; createBettingUI(); updateGameStatus(); } function createBettingUI() { // Bet amount display betDisplay = new Text2('Bahis: ' + playerBet + ' yıldız', { size: 50, fill: 0xFFFFFF }); betDisplay.anchor.set(0.5, 1); LK.gui.bottom.addChild(betDisplay); betDisplay.y = -200; // Bet buttons var decreaseBetBtn = LK.getAsset('betButton', { anchorX: 0.5, anchorY: 0.5 }); var increaseBetBtn = LK.getAsset('betButton', { anchorX: 0.5, anchorY: 0.5 }); var confirmBetBtn = LK.getAsset('betButton', { anchorX: 0.5, anchorY: 0.5 }); LK.gui.bottom.addChild(decreaseBetBtn); LK.gui.bottom.addChild(increaseBetBtn); LK.gui.bottom.addChild(confirmBetBtn); decreaseBetBtn.x = -200; decreaseBetBtn.y = -100; increaseBetBtn.x = 0; increaseBetBtn.y = -100; confirmBetBtn.x = 200; confirmBetBtn.y = -100; var decreaseText = new Text2('-', { size: 40, fill: 0xFFFFFF }); decreaseText.anchor.set(0.5, 0.5); decreaseBetBtn.addChild(decreaseText); var increaseText = new Text2('+', { size: 40, fill: 0xFFFFFF }); increaseText.anchor.set(0.5, 0.5); increaseBetBtn.addChild(increaseText); var confirmText = new Text2('Onayla', { size: 30, fill: 0xFFFFFF }); confirmText.anchor.set(0.5, 0.5); confirmBetBtn.addChild(confirmText); // Button interactions decreaseBetBtn.down = function () { if (playerBet > 0) { playerBet--; updateBetDisplay(); } }; increaseBetBtn.down = function () { if (playerBet < playerStars) { playerBet++; updateBetDisplay(); } }; confirmBetBtn.down = function () { if (gameState === 'betting') { confirmBet(); } }; } function updateBetDisplay() { betDisplay.setText('Bahis: ' + playerBet + ' yıldız'); updateGameStatus(); // Update status to show difficulty preview } function updateStarDisplay() { starDisplay.setText('Yıldızlar: ' + playerStars); } function updateGameStatus() { if (gameState === 'difficultySelection') { gameStatusDisplay.setText('AI zorluk seviyesi seçin'); } else if (gameState === 'betting') { var difficultyPreview = ''; if (playerBet >= 1 && playerBet <= 3) { difficultyPreview = 'Başlangıç (1-3 yıldız)'; } else if (playerBet >= 4 && playerBet <= 7) { difficultyPreview = 'Orta (4-7 yıldız)'; } else if (playerBet >= 8 && playerBet <= 10) { difficultyPreview = 'Uzman (8-10 yıldız)'; } else { difficultyPreview = 'Rastgele'; } gameStatusDisplay.setText('Bahis: ' + playerBet + ' yıldız (AI: ' + difficultyPreview + ')'); } else if (gameState === 'playing') { if (isAiTurn) { gameStatusDisplay.setText('AI düşünüyor...'); } else { var playerName = currentPlayer === 'white' ? 'Siz' : 'AI'; gameStatusDisplay.setText(playerName + ' sırası'); } } } function confirmBet() { // Map stars to difficulty names for display var difficultyName = ''; if (playerBet >= 1 && playerBet <= 3) { difficultyName = 'Başlangıç'; // Beginner } else if (playerBet >= 4 && playerBet <= 7) { difficultyName = 'Orta'; // Intermediate } else if (playerBet >= 8 && playerBet <= 10) { difficultyName = 'Uzman'; // Expert } else { difficultyName = 'Rastgele'; // Random fallback } // Store bet amount for AI logic (we use playerBet directly in AI) storage.playerBet = playerBet; // For now, simulate opponent bet (random between 0 and their stars) opponentBet = Math.floor(Math.random() * (Math.min(opponentStars, 10) + 1)); gameState = 'playing'; updateGameStatus(); // Hide betting UI LK.gui.bottom.removeChildren(); // Show bet results with difficulty level var betResultText = new Text2('Bahis: ' + playerBet + ' | Rakip: ' + opponentBet + ' | AI: ' + difficultyName, { size: 35, fill: 0xFFFFFF }); betResultText.anchor.set(0.5, 1); LK.gui.bottom.addChild(betResultText); betResultText.y = -50; } function showPromotionDialog(piece) { // Create dialog background var dialogBg = LK.getAsset('chessBoard', { anchorX: 0.5, anchorY: 0.5 }); dialogBg.x = 1024; dialogBg.y = 1366; dialogBg.width = 800; dialogBg.height = 600; dialogBg.tint = 0x444444; game.addChild(dialogBg); // Dialog title var titleText = new Text2('Taş Seçin', { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1200; game.addChild(titleText); // Promotion options var promotionOptions = ['queen', 'rook', 'bishop', 'knight']; var optionNames = ['Vezir', 'Kale', 'Fil', 'At']; var buttons = []; for (var i = 0; i < promotionOptions.length; i++) { var button = LK.getAsset('betButton', { anchorX: 0.5, anchorY: 0.5 }); button.x = 1024; button.y = 1300 + i * 100; button.width = 300; button.height = 80; game.addChild(button); var buttonText = new Text2(optionNames[i], { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); buttonText.x = 1024; buttonText.y = 1300 + i * 100; game.addChild(buttonText); // Store piece type for this button button.pieceType = promotionOptions[i]; button.dialogElements = [dialogBg, titleText, buttonText]; // Add all buttons to cleanup list for (var j = 0; j < buttons.length; j++) { button.dialogElements.push(buttons[j]); button.dialogElements.push(buttons[j].textElement); } button.down = function () { // Promote the piece promotePiece(piece, this.pieceType); // Clean up dialog for (var k = 0; k < this.dialogElements.length; k++) { if (this.dialogElements[k].parent) { this.dialogElements[k].parent.removeChild(this.dialogElements[k]); } this.dialogElements[k].destroy(); } // Clean up remaining buttons for (var l = 0; l < buttons.length; l++) { if (buttons[l].parent) { buttons[l].parent.removeChild(buttons[l]); } if (buttons[l].textElement && buttons[l].textElement.parent) { buttons[l].textElement.parent.removeChild(buttons[l].textElement); } buttons[l].destroy(); if (buttons[l].textElement) { buttons[l].textElement.destroy(); } } }; button.textElement = buttonText; buttons.push(button); } } function promotePiece(piece, newType) { // Update piece type piece.pieceType = newType; // Update the visual representation piece.removeChildren(); var pieceTypeMap = { 'pawn': piece.color === 'white' ? 'beyazPiyon' : 'siyahPiyon', 'rook': piece.color === 'white' ? 'beyazKale' : 'siyahKale', 'knight': piece.color === 'white' ? 'beyazAt' : 'siyahAt', 'bishop': piece.color === 'white' ? 'beyazFil' : 'siyahFil', 'queen': piece.color === 'white' ? 'beyazVezir' : 'siyahVezir', 'king': piece.color === 'white' ? 'beyazSah' : 'siyahSah' }; var assetId = pieceTypeMap[newType]; var pieceGraphics = piece.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); } // AI Functions function getPieceValue(pieceType) { var values = { 'pawn': 1, 'knight': 3, 'bishop': 3, 'rook': 5, 'queen': 9, 'king': 1000 }; return values[pieceType] || 0; } function evaluatePosition() { var score = 0; for (var i = 0; i < pieces.length; i++) { var piece = pieces[i]; var value = getPieceValue(piece.pieceType); if (piece.color === 'black') { score += value; } else { score -= value; } } return score; } function getAllPossibleMoves(color) { var allMoves = []; for (var i = 0; i < pieces.length; i++) { var piece = pieces[i]; if (piece.color === color) { var moves = getValidMoves(piece); for (var j = 0; j < moves.length; j++) { allMoves.push({ piece: piece, move: moves[j], fromRow: piece.row, fromCol: piece.col, toRow: moves[j].row, toCol: moves[j].col }); } } } return allMoves; } function makeAIMove() { if (currentPlayer !== 'black' || gameState !== 'playing') return; isAiTurn = true; // Thinking time based on star investment: more stars = longer thinking time var thinkingTime = aiThinkingTime; if (playerBet >= 1 && playerBet <= 3) { thinkingTime = 500; // Quick moves for beginner } else if (playerBet >= 4 && playerBet <= 7) { thinkingTime = 1000; // Normal thinking for intermediate } else if (playerBet >= 8 && playerBet <= 10) { thinkingTime = 1500; // Longer thinking for expert } LK.setTimeout(function () { var bestMove = selectBestMove(); if (bestMove) { // Simulate the move movePiece(bestMove.piece, bestMove.toRow, bestMove.toCol); } isAiTurn = false; }, thinkingTime); } function selectBestMove() { var possibleMoves = getAllPossibleMoves('black'); if (possibleMoves.length === 0) return null; var bestMove = null; var bestScore = -Infinity; // Stars 1-3: Beginner level - make simple moves, occasional blunders if (playerBet >= 1 && playerBet <= 3) { // 30% chance of making a random move (blunder) if (Math.random() < 0.3) { return possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; } // Otherwise make simple evaluation for (var i = 0; i < possibleMoves.length; i++) { var move = possibleMoves[i]; var score = evaluateBasicMove(move); // Add significant randomness for beginner score += (Math.random() - 0.5) * 20; if (score > bestScore) { bestScore = score; bestMove = move; } } } // Stars 4-7: Intermediate level - solid play, avoid obvious mistakes else if (playerBet >= 4 && playerBet <= 7) { for (var i = 0; i < possibleMoves.length; i++) { var move = possibleMoves[i]; var score = evaluateIntermediateMove(move); // Add moderate randomness for intermediate score += (Math.random() - 0.5) * 8; if (score > bestScore) { bestScore = score; bestMove = move; } } } // Stars 8-10: Expert level - strong tactical play, think ahead else if (playerBet >= 8 && playerBet <= 10) { for (var i = 0; i < possibleMoves.length; i++) { var move = possibleMoves[i]; var score = evaluateMove(move); // Full evaluation // Minimal randomness for expert level score += (Math.random() - 0.5) * 2; if (score > bestScore) { bestScore = score; bestMove = move; } } } // Fallback for edge cases else { return possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; } return bestMove; } function evaluateMove(move) { var score = 0; var targetPiece = board[move.toRow][move.toCol]; var piece = move.piece; // Priority 1: King safety - if in check, prioritize getting out of check if (isInCheck('black')) { score += 50; // High priority for moves that get out of check } // Priority 2: Capture evaluation with piece values if (targetPiece && targetPiece.color !== piece.color) { var captureValue = getPieceValue(targetPiece.pieceType); var attackerValue = getPieceValue(piece.pieceType); // Favorable trades get higher scores if (captureValue >= attackerValue) { score += captureValue * 15; // Very good capture } else { score += captureValue * 8; // Still valuable but less so } } // Priority 3: Threaten opponent pieces var threatenedPieces = getThreatenedPieces(move); for (var t = 0; t < threatenedPieces.length; t++) { var threatenedValue = getPieceValue(threatenedPieces[t].pieceType); score += threatenedValue * 3; // Bonus for threatening valuable pieces } // Position bonuses based on difficulty if (aiDifficulty >= 2) { // Basic positional evaluation if (piece.pieceType === 'pawn') { // Pawn advancement bonus score += (7 - move.toRow) * 1.2; // Avoid doubled pawns if (hasPawnInColumn(move.toCol, 'black', piece)) { score -= 3; } } // Control center squares bonus if (move.toRow >= 3 && move.toRow <= 4 && move.toCol >= 3 && move.toCol <= 4) { score += 4; } } if (aiDifficulty >= 3) { // King safety evaluation if (piece.pieceType === 'king') { // Penalty for exposing king early if (!piece.hasMoved && move.toRow > 2) { score -= 8; } // Castling bonus if (move.isCastling) { score += 6; } } // Piece development if ((piece.pieceType === 'knight' || piece.pieceType === 'bishop') && move.fromRow === 0) { score += 5; // Develop pieces from back rank } // Avoid moving same piece twice in opening if (piece.hasMoved && getTotalMoves() < 10) { score -= 2; } } if (aiDifficulty >= 4) { // Advanced tactical evaluation // Check if move creates discovered attacks if (createsDiscoveredAttack(move)) { score += 8; } // Piece coordination - pieces supporting each other var supportValue = calculatePieceSupport(move); score += supportValue * 2; // Control important squares (around enemy king) var enemyKing = findKing('white'); if (enemyKing && isNearKing(move.toRow, move.toCol, enemyKing)) { score += 6; } } if (aiDifficulty === 5) { // Expert level evaluation // Pin enemy pieces if (createsPinOrSkewer(move)) { score += 12; } // Fork opportunities (attacking multiple pieces) var forkValue = calculateForkValue(move); score += forkValue * 4; // Endgame evaluation if (isEndgame()) { score += evaluateEndgameMove(move); } // Advanced piece protection var isProtected = isPieceProtected(move.toRow, move.toCol, 'black'); var isAttacked = isPieceAttacked(move.toRow, move.toCol, 'white'); if (isProtected && !isAttacked) { score += 3; } else if (isAttacked && !isProtected) { score -= getPieceValue(piece.pieceType) * 2; } } return score; } // Basic move evaluation for beginner AI (stars 1-3) function evaluateBasicMove(move) { var score = 0; var targetPiece = board[move.toRow][move.toCol]; var piece = move.piece; // Only consider immediate captures if (targetPiece && targetPiece.color !== piece.color) { score += getPieceValue(targetPiece.pieceType) * 10; } // Very basic king safety - avoid obvious checks if (wouldMoveLeaveKingInCheck(piece, move.toRow, move.toCol)) { score -= 50; } return score; } // Intermediate move evaluation for intermediate AI (stars 4-7) function evaluateIntermediateMove(move) { var score = 0; var targetPiece = board[move.toRow][move.toCol]; var piece = move.piece; // King safety is priority if (isInCheck('black')) { score += 40; } // Capture evaluation if (targetPiece && targetPiece.color !== piece.color) { var captureValue = getPieceValue(targetPiece.pieceType); var attackerValue = getPieceValue(piece.pieceType); if (captureValue >= attackerValue) { score += captureValue * 12; } else { score += captureValue * 6; } } // Basic piece development if ((piece.pieceType === 'knight' || piece.pieceType === 'bishop') && move.fromRow === 0) { score += 4; } // Control center if (move.toRow >= 3 && move.toRow <= 4 && move.toCol >= 3 && move.toCol <= 4) { score += 3; } // Defend pieces under attack if (isPieceAttacked(piece.row, piece.col, 'white') && !isPieceAttacked(move.toRow, move.toCol, 'white')) { score += getPieceValue(piece.pieceType) * 5; } return score; } // AI Helper Functions function getThreatenedPieces(move) { var threatened = []; var tempRow = move.piece.row; var tempCol = move.piece.col; // Temporarily move piece to see what it threatens move.piece.row = move.toRow; move.piece.col = move.toCol; var tempBoard = board[move.toRow][move.toCol]; board[move.toRow][move.toCol] = move.piece; board[tempRow][tempCol] = null; var possibleAttacks = getRawMoves(move.piece); for (var i = 0; i < possibleAttacks.length; i++) { var attackTarget = board[possibleAttacks[i].row][possibleAttacks[i].col]; if (attackTarget && attackTarget.color === 'white') { threatened.push(attackTarget); } } // Restore position move.piece.row = tempRow; move.piece.col = tempCol; board[tempRow][tempCol] = move.piece; board[move.toRow][move.toCol] = tempBoard; return threatened; } function hasPawnInColumn(col, color, excludePiece) { for (var row = 0; row < 8; row++) { var piece = board[row][col]; if (piece && piece.pieceType === 'pawn' && piece.color === color && piece !== excludePiece) { return true; } } return false; } function getTotalMoves() { var moveCount = 0; for (var i = 0; i < pieces.length; i++) { if (pieces[i].hasMoved) moveCount++; } return moveCount; } function createsDiscoveredAttack(move) { // Check if moving this piece reveals an attack from another piece var piece = move.piece; var originalRow = piece.row; var originalCol = piece.col; // Temporarily remove piece board[originalRow][originalCol] = null; // Check if any black piece now attacks a white piece through the original square for (var i = 0; i < pieces.length; i++) { if (pieces[i].color === 'black' && pieces[i] !== piece) { var attacks = getRawMoves(pieces[i]); for (var j = 0; j < attacks.length; j++) { var target = board[attacks[j].row][attacks[j].col]; if (target && target.color === 'white') { // Check if the attack line passes through the original square if (isOnLine(pieces[i].row, pieces[i].col, attacks[j].row, attacks[j].col, originalRow, originalCol)) { board[originalRow][originalCol] = piece; // Restore return true; } } } } } board[originalRow][originalCol] = piece; // Restore return false; } function calculatePieceSupport(move) { var support = 0; // Count how many friendly pieces can defend this square for (var i = 0; i < pieces.length; i++) { if (pieces[i].color === 'black' && pieces[i] !== move.piece) { var supportMoves = getRawMoves(pieces[i]); for (var j = 0; j < supportMoves.length; j++) { if (supportMoves[j].row === move.toRow && supportMoves[j].col === move.toCol) { support++; break; } } } } return support; } function findKing(color) { for (var i = 0; i < pieces.length; i++) { if (pieces[i].pieceType === 'king' && pieces[i].color === color) { return pieces[i]; } } return null; } function isNearKing(row, col, king) { var rowDiff = Math.abs(row - king.row); var colDiff = Math.abs(col - king.col); return rowDiff <= 2 && colDiff <= 2; } function createsPinOrSkewer(move) { // Simplified pin/skewer detection var piece = move.piece; if (piece.pieceType !== 'rook' && piece.pieceType !== 'bishop' && piece.pieceType !== 'queen') { return false; } return false; // Simplified for now } function calculateForkValue(move) { var forkValue = 0; var piece = move.piece; if (piece.pieceType === 'knight') { // Temporarily place knight and count attacks var tempRow = piece.row; var tempCol = piece.col; piece.row = move.toRow; piece.col = move.toCol; var attacks = getRawMoves(piece); var attackedPieces = 0; var totalValue = 0; for (var i = 0; i < attacks.length; i++) { var target = board[attacks[i].row][attacks[i].col]; if (target && target.color === 'white') { attackedPieces++; totalValue += getPieceValue(target.pieceType); } } piece.row = tempRow; piece.col = tempCol; if (attackedPieces >= 2) forkValue = totalValue; } return forkValue; } function isEndgame() { // Simple endgame detection - few pieces left return pieces.length <= 12; } function evaluateEndgameMove(move) { var score = 0; var piece = move.piece; if (piece.pieceType === 'king') { // In endgame, king should be active score += 2; // Move towards enemy king var enemyKing = findKing('white'); if (enemyKing) { var oldDistance = Math.abs(piece.row - enemyKing.row) + Math.abs(piece.col - enemyKing.col); var newDistance = Math.abs(move.toRow - enemyKing.row) + Math.abs(move.toCol - enemyKing.col); if (newDistance < oldDistance) score += 3; } } return score; } function isPieceProtected(row, col, color) { for (var i = 0; i < pieces.length; i++) { if (pieces[i].color === color) { var protectMoves = getRawMoves(pieces[i]); for (var j = 0; j < protectMoves.length; j++) { if (protectMoves[j].row === row && protectMoves[j].col === col) { return true; } } } } return false; } function isPieceAttacked(row, col, byColor) { for (var i = 0; i < pieces.length; i++) { if (pieces[i].color === byColor) { var attackMoves = getRawMoves(pieces[i]); for (var j = 0; j < attackMoves.length; j++) { if (attackMoves[j].row === row && attackMoves[j].col === col) { return true; } } } } return false; } function isOnLine(x1, y1, x2, y2, px, py) { // Check if point (px, py) is on line from (x1, y1) to (x2, y2) if (x1 === x2) return px === x1 && (py > y1 && py < y2 || py > y2 && py < y1); if (y1 === y2) return py === y1 && (px > x1 && px < x2 || px > x2 && px < x1); // Diagonal check var dx = x2 - x1; var dy = y2 - y1; if (Math.abs(dx) !== Math.abs(dy)) return false; // Not diagonal var stepX = dx > 0 ? 1 : -1; var stepY = dy > 0 ? 1 : -1; var steps = Math.abs(dx); for (var i = 1; i < steps; i++) { if (x1 + i * stepX === px && y1 + i * stepY === py) return true; } return false; } // Initialize everything createBoardDisplay(); initializeBoard(); createUI(); updateBoardDisplay(); game.update = function () { // Prevent player input during AI turn if (isAiTurn) { // Visual indicator that AI is thinking if (LK.ticks % 30 === 0) { var thinkingText = 'AI düşünüyor'; for (var i = 0; i < Math.floor(LK.ticks / 30) % 4; i++) { thinkingText += '.'; } gameStatusDisplay.setText(thinkingText); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ChessPiece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.pieceType = type;
self.color = color;
self.row = row;
self.col = col;
self.hasMoved = false;
var pieceTypeMap = {
'pawn': color === 'white' ? 'beyazPiyon' : 'siyahPiyon',
'rook': color === 'white' ? 'beyazKale' : 'siyahKale',
'knight': color === 'white' ? 'beyazAt' : 'siyahAt',
'bishop': color === 'white' ? 'beyazFil' : 'siyahFil',
'queen': color === 'white' ? 'beyazVezir' : 'siyahVezir',
'king': color === 'white' ? 'beyazSah' : 'siyahSah'
};
var assetId = pieceTypeMap[type];
var pieceGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
if (gameState !== 'playing' || isAiTurn) return;
if (currentPlayer === self.color) {
// Select this piece if it belongs to current player
selectedPiece = self;
selectedSquare = {
row: self.row,
col: self.col
};
validMoves = getValidMoves(self);
updateBoardDisplay();
} else if (selectedPiece && isValidMove(selectedPiece.row, selectedPiece.col, self.row, self.col)) {
// If clicking on opponent piece and it's a valid capture move
movePiece(selectedPiece, self.row, self.col);
}
};
return self;
});
var Square = Container.expand(function (row, col, isLight) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.isLight = isLight;
self.piece = null;
var squareGraphics = self.attachAsset(isLight ? 'lightSquare' : 'darkSquare', {
anchorX: 0,
anchorY: 0
});
self.down = function (x, y, obj) {
if (gameState !== 'playing' || isAiTurn) return;
if (selectedPiece && isValidMove(selectedPiece.row, selectedPiece.col, self.row, self.col)) {
movePiece(selectedPiece, self.row, self.col);
} else {
// Check if there's a piece on this square that belongs to current player
var pieceOnSquare = board[self.row][self.col];
if (pieceOnSquare && pieceOnSquare.color === currentPlayer) {
// Select this piece if it belongs to current player
selectedPiece = pieceOnSquare;
selectedSquare = {
row: self.row,
col: self.col
};
validMoves = getValidMoves(pieceOnSquare);
updateBoardDisplay();
} else {
clearSelection();
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1e293b
});
/****
* Game Code
****/
// Game state variables
var gameState = 'difficultySelection'; // 'difficultySelection', 'betting', 'playing', 'gameOver'
var currentPlayer = 'white';
var selectedPiece = null;
var selectedSquare = null;
var validMoves = [];
var board = [];
var pieces = [];
// Player data
var playerStars = storage.playerStars || 10;
var opponentStars = storage.opponentStars || 10;
var playerBet = 0;
var opponentBet = 0;
var betPhase = 'playerBetting'; // 'playerBetting', 'opponentBetting', 'waitingForOpponent'
// AI system
var aiDifficulty = storage.aiDifficulty || 1; // 1-5 difficulty levels
var aiThinkingTime = 1000; // Base thinking time in milliseconds
var isAiTurn = false;
// UI elements
var boardContainer = new Container();
var squareOverlays = [];
var starDisplay,
betDisplay,
gameStatusDisplay,
difficultyUI = [];
// Initialize chess board
function initializeBoard() {
board = [];
pieces = [];
// Create 8x8 board
for (var row = 0; row < 8; row++) {
board[row] = [];
for (var col = 0; col < 8; col++) {
board[row][col] = null;
}
}
// Setup initial piece positions - standard chess layout
var backRankSetup = ['rook', 'knight', 'bishop', 'queen', 'king', 'bishop', 'knight', 'rook'];
// Place black pieces (rows 0-1, top of board)
// Row 0: Black back rank
for (var col = 0; col < 8; col++) {
var piece = new ChessPiece(backRankSetup[col], 'black', 0, col);
pieces.push(piece);
board[0][col] = piece;
boardContainer.addChild(piece);
piece.x = col * 225 + 112.5;
piece.y = 0 * 225 + 112.5;
}
// Row 1: Black pawns
for (var col = 0; col < 8; col++) {
var piece = new ChessPiece('pawn', 'black', 1, col);
pieces.push(piece);
board[1][col] = piece;
boardContainer.addChild(piece);
piece.x = col * 225 + 112.5;
piece.y = 1 * 225 + 112.5;
}
// Place white pieces (rows 6-7, bottom of board)
// Row 6: White pawns
for (var col = 0; col < 8; col++) {
var piece = new ChessPiece('pawn', 'white', 6, col);
pieces.push(piece);
board[6][col] = piece;
boardContainer.addChild(piece);
piece.x = col * 225 + 112.5;
piece.y = 6 * 225 + 112.5;
}
// Row 7: White back rank
for (var col = 0; col < 8; col++) {
var piece = new ChessPiece(backRankSetup[col], 'white', 7, col);
pieces.push(piece);
board[7][col] = piece;
boardContainer.addChild(piece);
piece.x = col * 225 + 112.5;
piece.y = 7 * 225 + 112.5;
}
}
// Create visual board squares
function createBoardDisplay() {
boardContainer.x = 124;
boardContainer.y = 466;
game.addChild(boardContainer);
// Create board background
var boardBg = boardContainer.attachAsset('chessBoard', {
anchorX: 0,
anchorY: 0
});
// Create squares
for (var row = 0; row < 8; row++) {
squareOverlays[row] = [];
for (var col = 0; col < 8; col++) {
var isLight = (row + col) % 2 === 0;
var square = new Square(row, col, isLight);
square.x = col * 225;
square.y = row * 225;
boardContainer.addChild(square);
squareOverlays[row][col] = square;
}
}
}
// Get raw moves for a piece without check validation (to prevent infinite recursion)
function getRawMoves(piece) {
var moves = [];
if (piece.pieceType === 'pawn') {
var direction = piece.color === 'white' ? -1 : 1;
var startRow = piece.color === 'white' ? 6 : 1;
// Forward move
if (isValidSquare(piece.row + direction, piece.col) && !board[piece.row + direction][piece.col]) {
moves.push({
row: piece.row + direction,
col: piece.col
});
// Double move from start
if (piece.row === startRow && !board[piece.row + 2 * direction][piece.col]) {
moves.push({
row: piece.row + 2 * direction,
col: piece.col
});
}
}
// Captures
for (var dc = -1; dc <= 1; dc += 2) {
var newRow = piece.row + direction;
var newCol = piece.col + dc;
if (isValidSquare(newRow, newCol) && board[newRow][newCol] && board[newRow][newCol].color !== piece.color) {
moves.push({
row: newRow,
col: newCol
});
}
}
} else if (piece.pieceType === 'rook') {
// Horizontal and vertical moves
var directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
for (var d = 0; d < directions.length; d++) {
var dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = piece.row + dir[0] * i;
var newCol = piece.col + dir[1] * i;
if (!isValidSquare(newRow, newCol)) break;
var targetPiece = board[newRow][newCol];
if (!targetPiece) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (targetPiece.color !== piece.color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
} else if (piece.pieceType === 'bishop') {
// Diagonal moves
var directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]];
for (var d = 0; d < directions.length; d++) {
var dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = piece.row + dir[0] * i;
var newCol = piece.col + dir[1] * i;
if (!isValidSquare(newRow, newCol)) break;
var targetPiece = board[newRow][newCol];
if (!targetPiece) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (targetPiece.color !== piece.color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
} else if (piece.pieceType === 'queen') {
// Combination of rook and bishop moves
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 dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = piece.row + dir[0] * i;
var newCol = piece.col + dir[1] * i;
if (!isValidSquare(newRow, newCol)) break;
var targetPiece = board[newRow][newCol];
if (!targetPiece) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (targetPiece.color !== piece.color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
} else if (piece.pieceType === 'king') {
// One square in any direction
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 dir = directions[d];
var newRow = piece.row + dir[0];
var newCol = piece.col + dir[1];
if (isValidSquare(newRow, newCol)) {
var targetPiece = board[newRow][newCol];
if (!targetPiece || targetPiece.color !== piece.color) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Castling moves
if (!piece.hasMoved) {
var kingRow = piece.row;
// Kingside castling (short castling)
var kingsideRook = board[kingRow][7];
if (kingsideRook && kingsideRook.pieceType === 'rook' && kingsideRook.color === piece.color && !kingsideRook.hasMoved) {
// Check if squares between king and rook are empty
if (!board[kingRow][5] && !board[kingRow][6]) {
// For now, add the move (should also check if king passes through check)
moves.push({
row: kingRow,
col: 6,
isCastling: true,
castlingType: 'kingside'
});
}
}
// Queenside castling (long castling)
var queensideRook = board[kingRow][0];
if (queensideRook && queensideRook.pieceType === 'rook' && queensideRook.color === piece.color && !queensideRook.hasMoved) {
// Check if squares between king and rook are empty
if (!board[kingRow][1] && !board[kingRow][2] && !board[kingRow][3]) {
// For now, add the move (should also check if king passes through check)
moves.push({
row: kingRow,
col: 2,
isCastling: true,
castlingType: 'queenside'
});
}
}
}
} else if (piece.pieceType === 'knight') {
// L-shaped moves
var knightMoves = [[2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2]];
for (var m = 0; m < knightMoves.length; m++) {
var move = knightMoves[m];
var newRow = piece.row + move[0];
var newCol = piece.col + move[1];
if (isValidSquare(newRow, newCol)) {
var targetPiece = board[newRow][newCol];
if (!targetPiece || targetPiece.color !== piece.color) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
}
return moves;
}
// Get valid moves for a piece
function getValidMoves(piece) {
var moves = getRawMoves(piece);
// Filter out moves that would leave the king in check
var legalMoves = [];
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
if (!wouldMoveLeaveKingInCheck(piece, move.row, move.col)) {
legalMoves.push(move);
}
}
return legalMoves;
}
function isValidSquare(row, col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
}
function isInCheck(playerColor) {
// Find the king of the specified color
var king = null;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceType === 'king' && pieces[i].color === playerColor) {
king = pieces[i];
break;
}
}
if (!king) return false;
// Check if any opponent piece can attack the king
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.color !== playerColor) {
var moves = getRawMoves(piece);
for (var j = 0; j < moves.length; j++) {
if (moves[j].row === king.row && moves[j].col === king.col) {
return true;
}
}
}
}
return false;
}
function wouldMoveLeaveKingInCheck(piece, toRow, toCol) {
// Save current state
var originalRow = piece.row;
var originalCol = piece.col;
var capturedPiece = board[toRow][toCol];
var wasInPiecesArray = false;
var capturedIndex = -1;
// Find captured piece index if it exists
if (capturedPiece) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] === capturedPiece) {
capturedIndex = i;
wasInPiecesArray = true;
break;
}
}
}
// Temporarily make the move
board[originalRow][originalCol] = null;
board[toRow][toCol] = piece;
piece.row = toRow;
piece.col = toCol;
// Remove captured piece from pieces array temporarily
if (capturedPiece && wasInPiecesArray) {
pieces.splice(capturedIndex, 1);
}
// Check if this move leaves the king in check
var kingInCheck = isInCheck(piece.color);
// Restore original state
board[originalRow][originalCol] = piece;
board[toRow][toCol] = capturedPiece;
piece.row = originalRow;
piece.col = originalCol;
// Restore captured piece to pieces array
if (capturedPiece && wasInPiecesArray) {
pieces.splice(capturedIndex, 0, capturedPiece);
}
return kingInCheck;
}
function isValidMove(fromRow, fromCol, toRow, toCol) {
// The validMoves array is already filtered by getValidMoves to exclude moves that leave king in check
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].row === toRow && validMoves[i].col === toCol) {
return true;
}
}
return false;
}
function movePiece(piece, newRow, newCol) {
// Check if this is a castling move
var isCastlingMove = false;
var castlingType = '';
if (piece.pieceType === 'king' && !piece.hasMoved && Math.abs(newCol - piece.col) === 2) {
isCastlingMove = true;
castlingType = newCol > piece.col ? 'kingside' : 'queenside';
}
var capturedPiece = board[newRow][newCol];
// Handle capture first (before moving the piece)
if (capturedPiece && capturedPiece.color !== piece.color) {
// Remove captured piece from pieces array
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === capturedPiece) {
pieces.splice(i, 1);
break;
}
}
// Remove captured piece from board container
if (capturedPiece.parent) {
capturedPiece.parent.removeChild(capturedPiece);
}
// Destroy the visual representation
capturedPiece.destroy();
LK.getSound('yeme').play();
} else {
LK.getSound('hareket').play();
}
// Remove piece from old position on board
board[piece.row][piece.col] = null;
// Update piece position data
piece.row = newRow;
piece.col = newCol;
piece.hasMoved = true;
// Place piece in new position on board
board[newRow][newCol] = piece;
// Handle castling - move the rook
if (isCastlingMove) {
LK.getSound('rok').play();
var rookOldCol, rookNewCol;
if (castlingType === 'kingside') {
rookOldCol = 7;
rookNewCol = 5;
} else {
// queenside
rookOldCol = 0;
rookNewCol = 3;
}
var rook = board[newRow][rookOldCol];
if (rook) {
// Remove rook from old position
board[newRow][rookOldCol] = null;
// Update rook position
rook.row = newRow;
rook.col = rookNewCol;
rook.hasMoved = true;
// Place rook in new position
board[newRow][rookNewCol] = rook;
// Animate rook movement
tween(rook, {
x: rookNewCol * 225 + 112.5,
y: newRow * 225 + 112.5
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Animate piece movement
tween(piece, {
x: newCol * 225 + 112.5,
y: newRow * 225 + 112.5
}, {
duration: 300,
easing: tween.easeOut
});
// Clear selection
clearSelection();
// Switch turns
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
// Check if the current player is in check
if (isInCheck(currentPlayer)) {
LK.getSound('sah').play();
}
updateGameStatus();
// Check for pawn promotion
if (piece.pieceType === 'pawn' && (piece.row === 0 || piece.row === 7)) {
LK.getSound('terfi').play();
if (piece.color === 'black') {
// AI auto-promotes to queen
promotePiece(piece, 'queen');
} else {
showPromotionDialog(piece);
}
}
// Check for game over conditions
checkGameOver();
// Trigger AI move if it's AI's turn
if (currentPlayer === 'black' && gameState === 'playing') {
makeAIMove();
}
}
function clearSelection() {
selectedPiece = null;
selectedSquare = null;
validMoves = [];
updateBoardDisplay();
}
function updateBoardDisplay() {
// Clear all overlays
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var square = squareOverlays[row][col];
square.removeChildren();
var isLight = (row + col) % 2 === 0;
var squareGraphics = square.attachAsset(isLight ? 'lightSquare' : 'darkSquare', {
anchorX: 0,
anchorY: 0
});
}
}
// Show selected square
if (selectedSquare) {
var selectedSquareOverlay = squareOverlays[selectedSquare.row][selectedSquare.col];
selectedSquareOverlay.removeChildren();
var selectedGraphics = selectedSquareOverlay.attachAsset('selectedSquare', {
anchorX: 0,
anchorY: 0
});
}
// Show valid moves
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
var moveSquare = squareOverlays[move.row][move.col];
moveSquare.removeChildren();
var moveGraphics = moveSquare.attachAsset('validMoveSquare', {
anchorX: 0,
anchorY: 0
});
}
}
function checkGameOver() {
// Simple game over check - if king is captured
var whiteKingExists = false;
var blackKingExists = false;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.pieceType === 'king') {
if (piece.color === 'white') whiteKingExists = true;
if (piece.color === 'black') blackKingExists = true;
}
}
if (!whiteKingExists) {
endGame('black');
} else if (!blackKingExists) {
endGame('white');
} else {
// Check for checkmate - player in check with no legal moves
if (isInCheck(currentPlayer)) {
var hasLegalMoves = false;
for (var i = 0; i < pieces.length && !hasLegalMoves; i++) {
var piece = pieces[i];
if (piece.color === currentPlayer) {
var legalMoves = getValidMoves(piece);
if (legalMoves.length > 0) {
hasLegalMoves = true;
}
}
}
if (!hasLegalMoves) {
// Checkmate - current player loses
var winner = currentPlayer === 'white' ? 'black' : 'white';
endGame(winner);
}
}
}
}
function endGame(winner) {
gameState = 'gameOver';
LK.getSound('bitis').play();
// Award stars
if (winner === 'white') {
playerStars += opponentBet;
opponentStars -= opponentBet;
} else {
playerStars -= playerBet;
opponentStars += playerBet;
}
// Save to storage
storage.playerStars = playerStars;
storage.opponentStars = opponentStars;
updateStarDisplay();
if (winner === 'white') {
LK.showYouWin();
} else {
LK.showGameOver();
}
}
function createUI() {
// Star display
starDisplay = new Text2('Yıldızlar: ' + playerStars, {
size: 60,
fill: 0xFFFFFF
});
starDisplay.anchor.set(0.5, 0);
LK.gui.top.addChild(starDisplay);
starDisplay.y = 100;
// Game status display
gameStatusDisplay = new Text2('AI zorluk seviyesi seçin', {
size: 50,
fill: 0xFFFFFF
});
gameStatusDisplay.anchor.set(0.5, 0);
LK.gui.top.addChild(gameStatusDisplay);
gameStatusDisplay.y = 180;
// Start with difficulty selection
createDifficultySelectionUI();
}
function createDifficultySelectionUI() {
// Skip difficulty selection, go directly to betting
gameState = 'betting';
createBettingUI();
updateGameStatus();
}
function createBettingUI() {
// Bet amount display
betDisplay = new Text2('Bahis: ' + playerBet + ' yıldız', {
size: 50,
fill: 0xFFFFFF
});
betDisplay.anchor.set(0.5, 1);
LK.gui.bottom.addChild(betDisplay);
betDisplay.y = -200;
// Bet buttons
var decreaseBetBtn = LK.getAsset('betButton', {
anchorX: 0.5,
anchorY: 0.5
});
var increaseBetBtn = LK.getAsset('betButton', {
anchorX: 0.5,
anchorY: 0.5
});
var confirmBetBtn = LK.getAsset('betButton', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.bottom.addChild(decreaseBetBtn);
LK.gui.bottom.addChild(increaseBetBtn);
LK.gui.bottom.addChild(confirmBetBtn);
decreaseBetBtn.x = -200;
decreaseBetBtn.y = -100;
increaseBetBtn.x = 0;
increaseBetBtn.y = -100;
confirmBetBtn.x = 200;
confirmBetBtn.y = -100;
var decreaseText = new Text2('-', {
size: 40,
fill: 0xFFFFFF
});
decreaseText.anchor.set(0.5, 0.5);
decreaseBetBtn.addChild(decreaseText);
var increaseText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
increaseText.anchor.set(0.5, 0.5);
increaseBetBtn.addChild(increaseText);
var confirmText = new Text2('Onayla', {
size: 30,
fill: 0xFFFFFF
});
confirmText.anchor.set(0.5, 0.5);
confirmBetBtn.addChild(confirmText);
// Button interactions
decreaseBetBtn.down = function () {
if (playerBet > 0) {
playerBet--;
updateBetDisplay();
}
};
increaseBetBtn.down = function () {
if (playerBet < playerStars) {
playerBet++;
updateBetDisplay();
}
};
confirmBetBtn.down = function () {
if (gameState === 'betting') {
confirmBet();
}
};
}
function updateBetDisplay() {
betDisplay.setText('Bahis: ' + playerBet + ' yıldız');
updateGameStatus(); // Update status to show difficulty preview
}
function updateStarDisplay() {
starDisplay.setText('Yıldızlar: ' + playerStars);
}
function updateGameStatus() {
if (gameState === 'difficultySelection') {
gameStatusDisplay.setText('AI zorluk seviyesi seçin');
} else if (gameState === 'betting') {
var difficultyPreview = '';
if (playerBet >= 1 && playerBet <= 3) {
difficultyPreview = 'Başlangıç (1-3 yıldız)';
} else if (playerBet >= 4 && playerBet <= 7) {
difficultyPreview = 'Orta (4-7 yıldız)';
} else if (playerBet >= 8 && playerBet <= 10) {
difficultyPreview = 'Uzman (8-10 yıldız)';
} else {
difficultyPreview = 'Rastgele';
}
gameStatusDisplay.setText('Bahis: ' + playerBet + ' yıldız (AI: ' + difficultyPreview + ')');
} else if (gameState === 'playing') {
if (isAiTurn) {
gameStatusDisplay.setText('AI düşünüyor...');
} else {
var playerName = currentPlayer === 'white' ? 'Siz' : 'AI';
gameStatusDisplay.setText(playerName + ' sırası');
}
}
}
function confirmBet() {
// Map stars to difficulty names for display
var difficultyName = '';
if (playerBet >= 1 && playerBet <= 3) {
difficultyName = 'Başlangıç'; // Beginner
} else if (playerBet >= 4 && playerBet <= 7) {
difficultyName = 'Orta'; // Intermediate
} else if (playerBet >= 8 && playerBet <= 10) {
difficultyName = 'Uzman'; // Expert
} else {
difficultyName = 'Rastgele'; // Random fallback
}
// Store bet amount for AI logic (we use playerBet directly in AI)
storage.playerBet = playerBet;
// For now, simulate opponent bet (random between 0 and their stars)
opponentBet = Math.floor(Math.random() * (Math.min(opponentStars, 10) + 1));
gameState = 'playing';
updateGameStatus();
// Hide betting UI
LK.gui.bottom.removeChildren();
// Show bet results with difficulty level
var betResultText = new Text2('Bahis: ' + playerBet + ' | Rakip: ' + opponentBet + ' | AI: ' + difficultyName, {
size: 35,
fill: 0xFFFFFF
});
betResultText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(betResultText);
betResultText.y = -50;
}
function showPromotionDialog(piece) {
// Create dialog background
var dialogBg = LK.getAsset('chessBoard', {
anchorX: 0.5,
anchorY: 0.5
});
dialogBg.x = 1024;
dialogBg.y = 1366;
dialogBg.width = 800;
dialogBg.height = 600;
dialogBg.tint = 0x444444;
game.addChild(dialogBg);
// Dialog title
var titleText = new Text2('Taş Seçin', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1200;
game.addChild(titleText);
// Promotion options
var promotionOptions = ['queen', 'rook', 'bishop', 'knight'];
var optionNames = ['Vezir', 'Kale', 'Fil', 'At'];
var buttons = [];
for (var i = 0; i < promotionOptions.length; i++) {
var button = LK.getAsset('betButton', {
anchorX: 0.5,
anchorY: 0.5
});
button.x = 1024;
button.y = 1300 + i * 100;
button.width = 300;
button.height = 80;
game.addChild(button);
var buttonText = new Text2(optionNames[i], {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 1024;
buttonText.y = 1300 + i * 100;
game.addChild(buttonText);
// Store piece type for this button
button.pieceType = promotionOptions[i];
button.dialogElements = [dialogBg, titleText, buttonText];
// Add all buttons to cleanup list
for (var j = 0; j < buttons.length; j++) {
button.dialogElements.push(buttons[j]);
button.dialogElements.push(buttons[j].textElement);
}
button.down = function () {
// Promote the piece
promotePiece(piece, this.pieceType);
// Clean up dialog
for (var k = 0; k < this.dialogElements.length; k++) {
if (this.dialogElements[k].parent) {
this.dialogElements[k].parent.removeChild(this.dialogElements[k]);
}
this.dialogElements[k].destroy();
}
// Clean up remaining buttons
for (var l = 0; l < buttons.length; l++) {
if (buttons[l].parent) {
buttons[l].parent.removeChild(buttons[l]);
}
if (buttons[l].textElement && buttons[l].textElement.parent) {
buttons[l].textElement.parent.removeChild(buttons[l].textElement);
}
buttons[l].destroy();
if (buttons[l].textElement) {
buttons[l].textElement.destroy();
}
}
};
button.textElement = buttonText;
buttons.push(button);
}
}
function promotePiece(piece, newType) {
// Update piece type
piece.pieceType = newType;
// Update the visual representation
piece.removeChildren();
var pieceTypeMap = {
'pawn': piece.color === 'white' ? 'beyazPiyon' : 'siyahPiyon',
'rook': piece.color === 'white' ? 'beyazKale' : 'siyahKale',
'knight': piece.color === 'white' ? 'beyazAt' : 'siyahAt',
'bishop': piece.color === 'white' ? 'beyazFil' : 'siyahFil',
'queen': piece.color === 'white' ? 'beyazVezir' : 'siyahVezir',
'king': piece.color === 'white' ? 'beyazSah' : 'siyahSah'
};
var assetId = pieceTypeMap[newType];
var pieceGraphics = piece.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
}
// AI Functions
function getPieceValue(pieceType) {
var values = {
'pawn': 1,
'knight': 3,
'bishop': 3,
'rook': 5,
'queen': 9,
'king': 1000
};
return values[pieceType] || 0;
}
function evaluatePosition() {
var score = 0;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
var value = getPieceValue(piece.pieceType);
if (piece.color === 'black') {
score += value;
} else {
score -= value;
}
}
return score;
}
function getAllPossibleMoves(color) {
var allMoves = [];
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece.color === color) {
var moves = getValidMoves(piece);
for (var j = 0; j < moves.length; j++) {
allMoves.push({
piece: piece,
move: moves[j],
fromRow: piece.row,
fromCol: piece.col,
toRow: moves[j].row,
toCol: moves[j].col
});
}
}
}
return allMoves;
}
function makeAIMove() {
if (currentPlayer !== 'black' || gameState !== 'playing') return;
isAiTurn = true;
// Thinking time based on star investment: more stars = longer thinking time
var thinkingTime = aiThinkingTime;
if (playerBet >= 1 && playerBet <= 3) {
thinkingTime = 500; // Quick moves for beginner
} else if (playerBet >= 4 && playerBet <= 7) {
thinkingTime = 1000; // Normal thinking for intermediate
} else if (playerBet >= 8 && playerBet <= 10) {
thinkingTime = 1500; // Longer thinking for expert
}
LK.setTimeout(function () {
var bestMove = selectBestMove();
if (bestMove) {
// Simulate the move
movePiece(bestMove.piece, bestMove.toRow, bestMove.toCol);
}
isAiTurn = false;
}, thinkingTime);
}
function selectBestMove() {
var possibleMoves = getAllPossibleMoves('black');
if (possibleMoves.length === 0) return null;
var bestMove = null;
var bestScore = -Infinity;
// Stars 1-3: Beginner level - make simple moves, occasional blunders
if (playerBet >= 1 && playerBet <= 3) {
// 30% chance of making a random move (blunder)
if (Math.random() < 0.3) {
return possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
}
// Otherwise make simple evaluation
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var score = evaluateBasicMove(move);
// Add significant randomness for beginner
score += (Math.random() - 0.5) * 20;
if (score > bestScore) {
bestScore = score;
bestMove = move;
}
}
}
// Stars 4-7: Intermediate level - solid play, avoid obvious mistakes
else if (playerBet >= 4 && playerBet <= 7) {
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var score = evaluateIntermediateMove(move);
// Add moderate randomness for intermediate
score += (Math.random() - 0.5) * 8;
if (score > bestScore) {
bestScore = score;
bestMove = move;
}
}
}
// Stars 8-10: Expert level - strong tactical play, think ahead
else if (playerBet >= 8 && playerBet <= 10) {
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var score = evaluateMove(move); // Full evaluation
// Minimal randomness for expert level
score += (Math.random() - 0.5) * 2;
if (score > bestScore) {
bestScore = score;
bestMove = move;
}
}
}
// Fallback for edge cases
else {
return possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
}
return bestMove;
}
function evaluateMove(move) {
var score = 0;
var targetPiece = board[move.toRow][move.toCol];
var piece = move.piece;
// Priority 1: King safety - if in check, prioritize getting out of check
if (isInCheck('black')) {
score += 50; // High priority for moves that get out of check
}
// Priority 2: Capture evaluation with piece values
if (targetPiece && targetPiece.color !== piece.color) {
var captureValue = getPieceValue(targetPiece.pieceType);
var attackerValue = getPieceValue(piece.pieceType);
// Favorable trades get higher scores
if (captureValue >= attackerValue) {
score += captureValue * 15; // Very good capture
} else {
score += captureValue * 8; // Still valuable but less so
}
}
// Priority 3: Threaten opponent pieces
var threatenedPieces = getThreatenedPieces(move);
for (var t = 0; t < threatenedPieces.length; t++) {
var threatenedValue = getPieceValue(threatenedPieces[t].pieceType);
score += threatenedValue * 3; // Bonus for threatening valuable pieces
}
// Position bonuses based on difficulty
if (aiDifficulty >= 2) {
// Basic positional evaluation
if (piece.pieceType === 'pawn') {
// Pawn advancement bonus
score += (7 - move.toRow) * 1.2;
// Avoid doubled pawns
if (hasPawnInColumn(move.toCol, 'black', piece)) {
score -= 3;
}
}
// Control center squares bonus
if (move.toRow >= 3 && move.toRow <= 4 && move.toCol >= 3 && move.toCol <= 4) {
score += 4;
}
}
if (aiDifficulty >= 3) {
// King safety evaluation
if (piece.pieceType === 'king') {
// Penalty for exposing king early
if (!piece.hasMoved && move.toRow > 2) {
score -= 8;
}
// Castling bonus
if (move.isCastling) {
score += 6;
}
}
// Piece development
if ((piece.pieceType === 'knight' || piece.pieceType === 'bishop') && move.fromRow === 0) {
score += 5; // Develop pieces from back rank
}
// Avoid moving same piece twice in opening
if (piece.hasMoved && getTotalMoves() < 10) {
score -= 2;
}
}
if (aiDifficulty >= 4) {
// Advanced tactical evaluation
// Check if move creates discovered attacks
if (createsDiscoveredAttack(move)) {
score += 8;
}
// Piece coordination - pieces supporting each other
var supportValue = calculatePieceSupport(move);
score += supportValue * 2;
// Control important squares (around enemy king)
var enemyKing = findKing('white');
if (enemyKing && isNearKing(move.toRow, move.toCol, enemyKing)) {
score += 6;
}
}
if (aiDifficulty === 5) {
// Expert level evaluation
// Pin enemy pieces
if (createsPinOrSkewer(move)) {
score += 12;
}
// Fork opportunities (attacking multiple pieces)
var forkValue = calculateForkValue(move);
score += forkValue * 4;
// Endgame evaluation
if (isEndgame()) {
score += evaluateEndgameMove(move);
}
// Advanced piece protection
var isProtected = isPieceProtected(move.toRow, move.toCol, 'black');
var isAttacked = isPieceAttacked(move.toRow, move.toCol, 'white');
if (isProtected && !isAttacked) {
score += 3;
} else if (isAttacked && !isProtected) {
score -= getPieceValue(piece.pieceType) * 2;
}
}
return score;
}
// Basic move evaluation for beginner AI (stars 1-3)
function evaluateBasicMove(move) {
var score = 0;
var targetPiece = board[move.toRow][move.toCol];
var piece = move.piece;
// Only consider immediate captures
if (targetPiece && targetPiece.color !== piece.color) {
score += getPieceValue(targetPiece.pieceType) * 10;
}
// Very basic king safety - avoid obvious checks
if (wouldMoveLeaveKingInCheck(piece, move.toRow, move.toCol)) {
score -= 50;
}
return score;
}
// Intermediate move evaluation for intermediate AI (stars 4-7)
function evaluateIntermediateMove(move) {
var score = 0;
var targetPiece = board[move.toRow][move.toCol];
var piece = move.piece;
// King safety is priority
if (isInCheck('black')) {
score += 40;
}
// Capture evaluation
if (targetPiece && targetPiece.color !== piece.color) {
var captureValue = getPieceValue(targetPiece.pieceType);
var attackerValue = getPieceValue(piece.pieceType);
if (captureValue >= attackerValue) {
score += captureValue * 12;
} else {
score += captureValue * 6;
}
}
// Basic piece development
if ((piece.pieceType === 'knight' || piece.pieceType === 'bishop') && move.fromRow === 0) {
score += 4;
}
// Control center
if (move.toRow >= 3 && move.toRow <= 4 && move.toCol >= 3 && move.toCol <= 4) {
score += 3;
}
// Defend pieces under attack
if (isPieceAttacked(piece.row, piece.col, 'white') && !isPieceAttacked(move.toRow, move.toCol, 'white')) {
score += getPieceValue(piece.pieceType) * 5;
}
return score;
}
// AI Helper Functions
function getThreatenedPieces(move) {
var threatened = [];
var tempRow = move.piece.row;
var tempCol = move.piece.col;
// Temporarily move piece to see what it threatens
move.piece.row = move.toRow;
move.piece.col = move.toCol;
var tempBoard = board[move.toRow][move.toCol];
board[move.toRow][move.toCol] = move.piece;
board[tempRow][tempCol] = null;
var possibleAttacks = getRawMoves(move.piece);
for (var i = 0; i < possibleAttacks.length; i++) {
var attackTarget = board[possibleAttacks[i].row][possibleAttacks[i].col];
if (attackTarget && attackTarget.color === 'white') {
threatened.push(attackTarget);
}
}
// Restore position
move.piece.row = tempRow;
move.piece.col = tempCol;
board[tempRow][tempCol] = move.piece;
board[move.toRow][move.toCol] = tempBoard;
return threatened;
}
function hasPawnInColumn(col, color, excludePiece) {
for (var row = 0; row < 8; row++) {
var piece = board[row][col];
if (piece && piece.pieceType === 'pawn' && piece.color === color && piece !== excludePiece) {
return true;
}
}
return false;
}
function getTotalMoves() {
var moveCount = 0;
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].hasMoved) moveCount++;
}
return moveCount;
}
function createsDiscoveredAttack(move) {
// Check if moving this piece reveals an attack from another piece
var piece = move.piece;
var originalRow = piece.row;
var originalCol = piece.col;
// Temporarily remove piece
board[originalRow][originalCol] = null;
// Check if any black piece now attacks a white piece through the original square
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].color === 'black' && pieces[i] !== piece) {
var attacks = getRawMoves(pieces[i]);
for (var j = 0; j < attacks.length; j++) {
var target = board[attacks[j].row][attacks[j].col];
if (target && target.color === 'white') {
// Check if the attack line passes through the original square
if (isOnLine(pieces[i].row, pieces[i].col, attacks[j].row, attacks[j].col, originalRow, originalCol)) {
board[originalRow][originalCol] = piece; // Restore
return true;
}
}
}
}
}
board[originalRow][originalCol] = piece; // Restore
return false;
}
function calculatePieceSupport(move) {
var support = 0;
// Count how many friendly pieces can defend this square
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].color === 'black' && pieces[i] !== move.piece) {
var supportMoves = getRawMoves(pieces[i]);
for (var j = 0; j < supportMoves.length; j++) {
if (supportMoves[j].row === move.toRow && supportMoves[j].col === move.toCol) {
support++;
break;
}
}
}
}
return support;
}
function findKing(color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].pieceType === 'king' && pieces[i].color === color) {
return pieces[i];
}
}
return null;
}
function isNearKing(row, col, king) {
var rowDiff = Math.abs(row - king.row);
var colDiff = Math.abs(col - king.col);
return rowDiff <= 2 && colDiff <= 2;
}
function createsPinOrSkewer(move) {
// Simplified pin/skewer detection
var piece = move.piece;
if (piece.pieceType !== 'rook' && piece.pieceType !== 'bishop' && piece.pieceType !== 'queen') {
return false;
}
return false; // Simplified for now
}
function calculateForkValue(move) {
var forkValue = 0;
var piece = move.piece;
if (piece.pieceType === 'knight') {
// Temporarily place knight and count attacks
var tempRow = piece.row;
var tempCol = piece.col;
piece.row = move.toRow;
piece.col = move.toCol;
var attacks = getRawMoves(piece);
var attackedPieces = 0;
var totalValue = 0;
for (var i = 0; i < attacks.length; i++) {
var target = board[attacks[i].row][attacks[i].col];
if (target && target.color === 'white') {
attackedPieces++;
totalValue += getPieceValue(target.pieceType);
}
}
piece.row = tempRow;
piece.col = tempCol;
if (attackedPieces >= 2) forkValue = totalValue;
}
return forkValue;
}
function isEndgame() {
// Simple endgame detection - few pieces left
return pieces.length <= 12;
}
function evaluateEndgameMove(move) {
var score = 0;
var piece = move.piece;
if (piece.pieceType === 'king') {
// In endgame, king should be active
score += 2;
// Move towards enemy king
var enemyKing = findKing('white');
if (enemyKing) {
var oldDistance = Math.abs(piece.row - enemyKing.row) + Math.abs(piece.col - enemyKing.col);
var newDistance = Math.abs(move.toRow - enemyKing.row) + Math.abs(move.toCol - enemyKing.col);
if (newDistance < oldDistance) score += 3;
}
}
return score;
}
function isPieceProtected(row, col, color) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].color === color) {
var protectMoves = getRawMoves(pieces[i]);
for (var j = 0; j < protectMoves.length; j++) {
if (protectMoves[j].row === row && protectMoves[j].col === col) {
return true;
}
}
}
}
return false;
}
function isPieceAttacked(row, col, byColor) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].color === byColor) {
var attackMoves = getRawMoves(pieces[i]);
for (var j = 0; j < attackMoves.length; j++) {
if (attackMoves[j].row === row && attackMoves[j].col === col) {
return true;
}
}
}
}
return false;
}
function isOnLine(x1, y1, x2, y2, px, py) {
// Check if point (px, py) is on line from (x1, y1) to (x2, y2)
if (x1 === x2) return px === x1 && (py > y1 && py < y2 || py > y2 && py < y1);
if (y1 === y2) return py === y1 && (px > x1 && px < x2 || px > x2 && px < x1);
// Diagonal check
var dx = x2 - x1;
var dy = y2 - y1;
if (Math.abs(dx) !== Math.abs(dy)) return false; // Not diagonal
var stepX = dx > 0 ? 1 : -1;
var stepY = dy > 0 ? 1 : -1;
var steps = Math.abs(dx);
for (var i = 1; i < steps; i++) {
if (x1 + i * stepX === px && y1 + i * stepY === py) return true;
}
return false;
}
// Initialize everything
createBoardDisplay();
initializeBoard();
createUI();
updateBoardDisplay();
game.update = function () {
// Prevent player input during AI turn
if (isAiTurn) {
// Visual indicator that AI is thinking
if (LK.ticks % 30 === 0) {
var thinkingText = 'AI düşünüyor';
for (var i = 0; i < Math.floor(LK.ticks / 30) % 4; i++) {
thinkingText += '.';
}
gameStatusDisplay.setText(thinkingText);
}
}
};