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);
}
}
};