/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1", {
playerELO: 1200,
gamesPlayed: 0,
wins: 0,
losses: 0,
draws: 0,
username: "",
userId: "",
friends: [],
friendRequests: [],
onlineMatches: [],
isLoggedIn: false,
soundVolume: 100,
musicVolume: 100,
boardTheme: "klasik",
aiDifficulty: 5
});
/****
* Classes
****/
var ChessPiece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.pieceType = type;
self.pieceColor = color;
self.boardRow = row;
self.boardCol = col;
self.hasMoved = false;
// Get asset name based on current theme
var assetName;
if (storage.boardTheme === 'azami') {
// Create bordered piece for azami theme
var borderAssetName = 'azami' + color + type + 'Border';
var fillAssetName = 'azami' + color + type;
// Add border first (larger)
var borderGraphics = self.attachAsset(borderAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Add fill on top (smaller)
var pieceGraphics = self.attachAsset(fillAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
} else {
assetName = color + type; // Classic theme
var pieceGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
}
self.moveTo = function (newRow, newCol) {
self.boardRow = newRow;
self.boardCol = newCol;
self.hasMoved = true;
self.x = boardStartX + newCol * squareSize + squareSize / 2;
self.y = boardStartY + newRow * squareSize + squareSize / 2;
};
return self;
});
var ChessSquare = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.isLight = (row + col) % 2 === 0;
self.piece = null;
self.isSelected = false;
self.isPossibleMove = false;
var squareColor = self.isLight ? 'lightSquare' : 'darkSquare';
var squareGraphics = self.attachAsset(squareColor, {
anchorX: 0,
anchorY: 0
});
self.highlight = null;
self.setSelected = function (selected) {
self.isSelected = selected;
if (selected && !self.highlight) {
self.highlight = self.addChild(LK.getAsset('selectedSquare', {
anchorX: 0,
anchorY: 0,
alpha: 0.5
}));
} else if (!selected && self.highlight) {
self.removeChild(self.highlight);
self.highlight = null;
}
};
self.setPossibleMove = function (possible) {
self.isPossibleMove = possible;
if (possible && !self.highlight) {
self.highlight = self.addChild(LK.getAsset('possibleMove', {
anchorX: 0,
anchorY: 0,
alpha: 0.3
}));
} else if (!possible && self.highlight) {
self.removeChild(self.highlight);
self.highlight = null;
}
};
self.down = function (x, y, obj) {
handleSquareClick(self.row, self.col);
};
return self;
});
var EloLeaderboardItem = Container.expand(function (playerData, rank) {
var self = Container.call(this);
self.playerData = playerData;
self.rank = rank;
var background = self.attachAsset('menuButton', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.8
});
background.tint = rank <= 3 ? rank === 1 ? 0xFFD700 : rank === 2 ? 0xC0C0C0 : 0xCD7F32 : 0x2a2a2a;
var rankText = new Text2('#' + rank, {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
rankText.anchor.set(0, 0.5);
rankText.x = 20;
self.addChild(rankText);
var nameText = new Text2(playerData.username, {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
nameText.anchor.set(0, 0.5);
nameText.x = 120;
self.addChild(nameText);
var eloText = new Text2('ELO: ' + playerData.elo, {
size: 48,
fill: 0xFFD700
});
eloText.anchor.set(1, 0.5);
eloText.x = 520;
self.addChild(eloText);
var gamesText = new Text2('Maçlar: ' + playerData.gamesPlayed, {
size: 36,
fill: 0xC0C0C0
});
gamesText.anchor.set(1, 0.5);
gamesText.x = 580;
gamesText.y = 25;
self.addChild(gamesText);
return self;
});
var FriendListItem = Container.expand(function (friendData, callback) {
var self = Container.call(this);
self.friendData = friendData;
self.callback = callback;
var background = self.attachAsset('menuButton', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.8
});
background.tint = friendData.online ? 0x1a5f1a : 0x2a2a2a;
var nameText = new Text2(friendData.username, {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
nameText.anchor.set(0, 0.5);
nameText.x = 20;
self.addChild(nameText);
var statusText = new Text2(friendData.online ? 'Oynamak için tıkla!' : 'Çevrimdışı', {
size: 38,
fill: friendData.online ? 0x00FF00 : 0x888888
});
statusText.anchor.set(1, 0.5);
statusText.x = 580;
statusText.y = -15;
self.addChild(statusText);
if (friendData.online) {
var playText = new Text2('🎮 Maç Başlat', {
size: 36,
fill: 0xFFD700
});
playText.anchor.set(1, 0.5);
playText.x = 580;
playText.y = 15;
self.addChild(playText);
}
self.down = function (x, y, obj) {
if (self.callback && friendData.online) {
self.callback(friendData);
}
};
return self;
});
var InputField = Container.expand(function (placeholder, width) {
var self = Container.call(this);
self.width = width || 600;
self.height = 80;
self.placeholder = placeholder;
self.value = '';
self.isFocused = false;
var fieldBackground = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.width / 400,
scaleY: self.height / 120
});
fieldBackground.tint = 0x333333;
self.displayText = new Text2(placeholder, {
size: 48,
fill: 0xCCCCCC
});
self.displayText.anchor.set(0.5, 0.5);
self.addChild(self.displayText);
self.setText = function (text) {
self.value = text;
if (text.length > 0) {
self.displayText.setText(text);
self.displayText.tint = 0xFFFFFF;
} else {
self.displayText.setText(self.placeholder);
self.displayText.tint = 0xCCCCCC;
}
};
self.down = function (x, y, obj) {
// Clear other input focus first
if (usernameInput && usernameInput !== self) {
usernameInput.isFocused = false;
usernameInput.children[0].tint = 0x333333;
}
if (passwordInput && passwordInput !== self) {
passwordInput.isFocused = false;
passwordInput.children[0].tint = 0x333333;
}
if (addFriendInput && addFriendInput !== self) {
addFriendInput.isFocused = false;
addFriendInput.children[0].tint = 0x333333;
}
self.isFocused = true;
fieldBackground.tint = 0x4169e1;
};
return self;
});
var MenuButton = Container.expand(function (text, callback) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 56,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.callback = callback;
self.down = function (x, y, obj) {
if (self.callback) {
self.callback();
}
};
return self;
});
var PawnPromotionUI = Container.expand(function (callback) {
var self = Container.call(this);
self.callback = callback;
// Background overlay
var overlay = self.attachAsset('chessBoard', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.3
});
overlay.tint = 0x000000;
overlay.alpha = 0.8;
var titleText = new Text2('Piyonu Dönüştür:', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -80;
self.addChild(titleText);
// Create promotion piece buttons
var pieces = ['Queen', 'Rook', 'Bishop', 'Knight'];
var pieceNames = ['Vezir', 'Kale', 'Fil', 'At'];
for (var i = 0; i < pieces.length; i++) {
var pieceButton = new Container();
pieceButton.x = (i - 1.5) * 180;
pieceButton.y = 20;
var buttonBg = pieceButton.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
}));
buttonBg.tint = 0x333333;
var buttonText = new Text2(pieceNames[i], {
size: 36,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
buttonText.anchor.set(0.5, 0.5);
pieceButton.addChild(buttonText);
pieceButton.pieceType = pieces[i];
pieceButton.down = function (x, y, obj) {
if (self.callback) {
self.callback(this.pieceType);
}
};
self.addChild(pieceButton);
}
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F4F
});
/****
* Game Code
****/
// Add beautiful chess background image
var backgroundImage = game.addChild(LK.getAsset('chessBackground', {
anchorX: 0,
anchorY: 0,
scaleX: 1,
scaleY: 1
}));
// Azami theme - minimal shapes
var gameState = 'login'; // 'login', 'register', 'menu', 'friends', 'playing', 'gameOver'
var currentPlayer = 'white';
var selectedSquare = null;
var possibleMoves = [];
var board = [];
var pieces = [];
var squares = [];
var gameMode = 'friend'; // 'online', 'friend'
var boardStartX = 224;
var boardStartY = 300;
var squareSize = 200;
var currentMatch = null;
var friendsList = [];
var friendRequestsList = [];
// Login/Register UI
var titleText = new Text2('Chess Master AI', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
var usernameInput = new InputField('Kullanıcı Adı Girin', 800);
usernameInput.x = 1024;
usernameInput.y = 2000;
var passwordInput = new InputField('Şifre Girin', 800);
passwordInput.x = 1024;
passwordInput.y = 2150;
function showSettingsMenu() {
// Clear all UI
clearAllUI();
updateSettingsDisplay();
// Add UI elements in organized order with proper spacing
game.addChild(settingsTitleText);
game.addChild(soundVolumeText);
game.addChild(decreaseSoundButton);
game.addChild(increaseSoundButton);
game.addChild(musicVolumeText);
game.addChild(decreaseMusicButton);
game.addChild(increaseMusicButton);
game.addChild(boardThemeText);
game.addChild(changeBoardThemeButton);
game.addChild(aiDifficultyText);
game.addChild(decreaseAIDifficultyButton);
game.addChild(increaseAIDifficultyButton);
game.addChild(backToMenuFromSettingsButton);
game.addChild(madeWithText);
gameState = 'settings';
}
function showEloLeaderboard() {
// Clear all UI
clearAllUI();
game.addChild(eloLeaderboardTitleText);
game.addChild(eloLeaderboardContainer);
game.addChild(backToMenuFromLeaderboardButton);
game.addChild(madeWithText);
updateEloLeaderboard();
gameState = 'leaderboard';
}
function updateEloLeaderboard() {
// Clear existing leaderboard
for (var i = eloLeaderboardContainer.children.length - 1; i >= 0; i--) {
eloLeaderboardContainer.removeChild(eloLeaderboardContainer.children[i]);
}
// Collect all player data from storage
var players = [];
// Add current player
if (storage.username && storage.playerELO) {
players.push({
username: storage.username,
elo: storage.playerELO,
gamesPlayed: storage.gamesPlayed || 0,
wins: storage.wins || 0,
losses: storage.losses || 0,
draws: storage.draws || 0
});
}
// Add friends data (simulated for demonstration)
if (storage.friends && Array.isArray(storage.friends)) {
for (var i = 0; i < storage.friends.length; i++) {
var friend = storage.friends[i];
if (friend && friend.username) {
// Generate simulated ELO data for friends
var friendElo = 1000 + Math.floor(Math.random() * 800);
var friendGames = Math.floor(Math.random() * 50) + 10;
players.push({
username: friend.username,
elo: friendElo,
gamesPlayed: friendGames,
wins: Math.floor(friendGames * 0.4),
losses: Math.floor(friendGames * 0.4),
draws: Math.floor(friendGames * 0.2)
});
}
}
}
// Add some sample players for demonstration
var samplePlayers = [{
username: 'GrandMaster_Pro',
elo: 2100,
gamesPlayed: 150,
wins: 90,
losses: 45,
draws: 15
}, {
username: 'ChessWizard',
elo: 1950,
gamesPlayed: 120,
wins: 75,
losses: 35,
draws: 10
}, {
username: 'KnightMover',
elo: 1800,
gamesPlayed: 80,
wins: 50,
losses: 25,
draws: 5
}, {
username: 'RookiePlayer',
elo: 1600,
gamesPlayed: 60,
wins: 30,
losses: 25,
draws: 5
}, {
username: 'PawnPusher',
elo: 1400,
gamesPlayed: 40,
wins: 20,
losses: 15,
draws: 5
}];
for (var i = 0; i < samplePlayers.length; i++) {
// Only add if not already in players list
var exists = false;
for (var j = 0; j < players.length; j++) {
if (players[j].username === samplePlayers[i].username) {
exists = true;
break;
}
}
if (!exists) {
players.push(samplePlayers[i]);
}
}
// Sort players by ELO in descending order
players.sort(function (a, b) {
return b.elo - a.elo;
});
// Display top 10 players
var yOffset = 0;
var maxPlayers = Math.min(players.length, 10);
for (var i = 0; i < maxPlayers; i++) {
var player = players[i];
var leaderboardItem = new EloLeaderboardItem(player, i + 1);
leaderboardItem.x = 0;
leaderboardItem.y = yOffset;
eloLeaderboardContainer.addChild(leaderboardItem);
yOffset += 100;
}
}
var loginButton = new MenuButton('Giriş Yap', function () {
if (usernameInput.value.length > 2 && passwordInput.value.length > 2) {
loginUser(usernameInput.value, passwordInput.value);
}
});
loginButton.x = 1024;
loginButton.y = 2350;
var registerButton = new MenuButton('Kayıt Ol', function () {
if (usernameInput.value.length > 2 && passwordInput.value.length > 2) {
registerUser(usernameInput.value, passwordInput.value);
}
});
registerButton.x = 1024;
registerButton.y = 2500;
// Main menu UI
var welcomeText = new Text2('', {
size: 64,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
welcomeText.anchor.set(0.5, 0.5);
welcomeText.x = 1024;
welcomeText.y = 300;
var eloText = new Text2('', {
size: 56,
fill: 0xFFD700
});
eloText.anchor.set(0.5, 0.5);
eloText.x = 1024;
eloText.y = 380;
var statsText = new Text2('', {
size: 44,
fill: 0xC0C0C0,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 1024;
statsText.y = 460;
var quickMatchButton = new MenuButton('Hızlı Maç', function () {
gameMode = 'online';
findOnlineMatch();
});
quickMatchButton.x = 1024;
quickMatchButton.y = 1310;
var eloLeaderboardButton = new MenuButton('ELO Sıralaması', function () {
showEloLeaderboard();
});
eloLeaderboardButton.x = 1024;
eloLeaderboardButton.y = 1600;
var settingsButton = new MenuButton('Ayarlar', function () {
showSettingsMenu();
});
settingsButton.x = 1024;
settingsButton.y = 1710;
var logoutButton = new MenuButton('Çıkış Yap', function () {
logoutUser();
});
logoutButton.x = 1024;
logoutButton.y = 2010;
// Friends UI
var friendsTitleText = new Text2('Arkadaşlar ve Maçlar', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
friendsTitleText.anchor.set(0.5, 0.5);
friendsTitleText.x = 1024;
friendsTitleText.y = 250;
var addFriendInput = new InputField('Arkadaş Kullanıcı Adı', 500);
addFriendInput.x = 1024;
addFriendInput.y = 350;
var addFriendButton = new MenuButton('Arkadaş Ekle', function () {
if (addFriendInput.value.length > 2) {
addFriend(addFriendInput.value);
addFriendInput.setText('');
}
});
addFriendButton.x = 1024;
addFriendButton.y = 450;
var friendsListContainer = new Container();
friendsListContainer.x = 224;
friendsListContainer.y = 600;
var backToMenuButton = new MenuButton('Menüye Dön', function () {
showMainMenu();
});
backToMenuButton.x = 1024;
backToMenuButton.y = 2200;
// ELO Leaderboard UI
var eloLeaderboardTitleText = new Text2('ELO Sıralaması', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
eloLeaderboardTitleText.anchor.set(0.5, 0.5);
eloLeaderboardTitleText.x = 1024;
eloLeaderboardTitleText.y = 250;
var eloLeaderboardContainer = new Container();
eloLeaderboardContainer.x = 224;
eloLeaderboardContainer.y = 400;
var backToMenuFromLeaderboardButton = new MenuButton('Menüye Dön', function () {
showMainMenu();
});
backToMenuFromLeaderboardButton.x = 1024;
backToMenuFromLeaderboardButton.y = 2200;
var eloLeaderboardButton = null;
// Game status display with larger text
var gameStatusText = new Text2('Beyazın hamlesi', {
size: 64,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
gameStatusText.anchor.set(0.5, 0.5);
gameStatusText.x = 1024;
gameStatusText.y = 150;
var backButton = new MenuButton('Menüye Dön', function () {
returnToMenu();
});
backButton.x = 1024;
backButton.y = 2400;
// Game UI elements
var gameStatusText = new Text2('Beyazın hamlesi', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
gameStatusText.anchor.set(0.5, 0.5);
gameStatusText.x = 1024;
gameStatusText.y = 300;
var backButton = new MenuButton('Menüye Dön', function () {
returnToMenu();
});
backButton.x = 1024;
backButton.y = 2400;
// Initialize board
function initializeBoard() {
board = [];
for (var row = 0; row < 8; row++) {
board[row] = [];
for (var col = 0; col < 8; col++) {
board[row][col] = null;
}
}
// Set up initial piece positions
var pieceOrder = ['Rook', 'Knight', 'Bishop', 'Queen', 'King', 'Bishop', 'Knight', 'Rook'];
// White pieces
for (var col = 0; col < 8; col++) {
board[7][col] = {
type: pieceOrder[col],
color: 'white'
};
board[6][col] = {
type: 'Pawn',
color: 'white'
};
}
// Black pieces
for (var col = 0; col < 8; col++) {
board[0][col] = {
type: pieceOrder[col],
color: 'black'
};
board[1][col] = {
type: 'Pawn',
color: 'black'
};
}
}
function createBoardVisual() {
// Clear existing board
for (var i = squares.length - 1; i >= 0; i--) {
squares[i].destroy();
}
squares = [];
for (var i = pieces.length - 1; i >= 0; i--) {
pieces[i].destroy();
}
pieces = [];
// Create squares
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var square = new ChessSquare(row, col);
square.x = boardStartX + col * squareSize;
square.y = boardStartY + row * squareSize;
squares.push(square);
game.addChild(square);
}
}
// Create pieces
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col]) {
var piece = new ChessPiece(board[row][col].type, board[row][col].color, row, col);
piece.x = boardStartX + col * squareSize + squareSize / 2;
piece.y = boardStartY + row * squareSize + squareSize / 2;
pieces.push(piece);
game.addChild(piece);
}
}
}
}
function getPossibleMoves(row, col) {
var moves = [];
var piece = board[row][col];
if (!piece || piece.color !== currentPlayer) {
return moves;
}
var rawMoves = [];
switch (piece.type) {
case 'Pawn':
rawMoves = getPawnMoves(row, col, piece.color);
break;
case 'Rook':
rawMoves = getRookMoves(row, col, piece.color);
break;
case 'Knight':
rawMoves = getKnightMoves(row, col, piece.color);
break;
case 'Bishop':
rawMoves = getBishopMoves(row, col, piece.color);
break;
case 'Queen':
rawMoves = getQueenMoves(row, col, piece.color);
break;
case 'King':
rawMoves = getKingMoves(row, col, piece.color);
break;
}
// Filter out moves that would leave king in check
for (var i = 0; i < rawMoves.length; i++) {
if (isLegalMove(row, col, rawMoves[i].row, rawMoves[i].col)) {
moves.push(rawMoves[i]);
}
}
return moves;
}
// Global variable to track last move for en passant
var lastMove = null;
function getPawnMoves(row, col, color) {
var moves = [];
var direction = color === 'white' ? -1 : 1;
var startRow = color === 'white' ? 6 : 1;
// Forward move
if (isValidSquare(row + direction, col) && !board[row + direction][col]) {
moves.push({
row: row + direction,
col: col
});
// Double move from start
if (row === startRow && !board[row + 2 * direction][col]) {
moves.push({
row: row + 2 * direction,
col: col
});
}
}
// Captures
if (isValidSquare(row + direction, col - 1) && board[row + direction][col - 1] && board[row + direction][col - 1].color !== color) {
moves.push({
row: row + direction,
col: col - 1
});
}
if (isValidSquare(row + direction, col + 1) && board[row + direction][col + 1] && board[row + direction][col + 1].color !== color) {
moves.push({
row: row + direction,
col: col + 1
});
}
// En passant captures
if (lastMove && lastMove.piece && lastMove.piece.type === 'Pawn' && Math.abs(lastMove.toRow - lastMove.fromRow) === 2) {
// Check if we are adjacent to the pawn that just moved 2 squares
if (lastMove.toRow === row && Math.abs(lastMove.toCol - col) === 1) {
// We can capture en passant
var enPassantRow = row + direction;
var enPassantCol = lastMove.toCol;
if (isValidSquare(enPassantRow, enPassantCol)) {
moves.push({
row: enPassantRow,
col: enPassantCol,
enPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
return moves;
}
function getRookMoves(row, col, color) {
var moves = [];
var directions = [{
row: 0,
col: 1
}, {
row: 0,
col: -1
}, {
row: 1,
col: 0
}, {
row: -1,
col: 0
}];
for (var d = 0; d < directions.length; d++) {
var dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = row + dir.row * i;
var newCol = col + dir.col * i;
if (!isValidSquare(newRow, newCol)) {
break;
}
if (!board[newRow][newCol]) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (board[newRow][newCol].color !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
return moves;
}
function getKnightMoves(row, col, color) {
var moves = [];
var knightMoves = [{
row: -2,
col: -1
}, {
row: -2,
col: 1
}, {
row: -1,
col: -2
}, {
row: -1,
col: 2
}, {
row: 1,
col: -2
}, {
row: 1,
col: 2
}, {
row: 2,
col: -1
}, {
row: 2,
col: 1
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = row + move.row;
var newCol = col + move.col;
if (isValidSquare(newRow, newCol) && (!board[newRow][newCol] || board[newRow][newCol].color !== color)) {
moves.push({
row: newRow,
col: newCol
});
}
}
return moves;
}
function getBishopMoves(row, col, color) {
var moves = [];
var directions = [{
row: 1,
col: 1
}, {
row: 1,
col: -1
}, {
row: -1,
col: 1
}, {
row: -1,
col: -1
}];
for (var d = 0; d < directions.length; d++) {
var dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = row + dir.row * i;
var newCol = col + dir.col * i;
if (!isValidSquare(newRow, newCol)) {
break;
}
if (!board[newRow][newCol]) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (board[newRow][newCol].color !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
return moves;
}
function getQueenMoves(row, col, color) {
var rookMoves = getRookMoves(row, col, color);
var bishopMoves = getBishopMoves(row, col, color);
return rookMoves.concat(bishopMoves);
}
function getKingMoves(row, col, color) {
var moves = [];
var directions = [{
row: -1,
col: -1
}, {
row: -1,
col: 0
}, {
row: -1,
col: 1
}, {
row: 0,
col: -1
}, {
row: 0,
col: 1
}, {
row: 1,
col: -1
}, {
row: 1,
col: 0
}, {
row: 1,
col: 1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var newRow = row + dir.row;
var newCol = col + dir.col;
if (isValidSquare(newRow, newCol) && (!board[newRow][newCol] || board[newRow][newCol].color !== color)) {
if (!isSquareUnderAttack(newRow, newCol, color)) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Castling
var piece = findPieceAt(row, col);
if (piece && !piece.hasMoved && !isSquareUnderAttack(row, col, color)) {
// Kingside castling
var kingsideRook = findPieceAt(row, 7);
if (kingsideRook && !kingsideRook.hasMoved && !board[row][5] && !board[row][6] && !isSquareUnderAttack(row, 5, color) && !isSquareUnderAttack(row, 6, color)) {
moves.push({
row: row,
col: 6,
castling: 'kingside'
});
}
// Queenside castling
var queensideRook = findPieceAt(row, 0);
if (queensideRook && !queensideRook.hasMoved && !board[row][1] && !board[row][2] && !board[row][3] && !isSquareUnderAttack(row, 2, color) && !isSquareUnderAttack(row, 3, color)) {
moves.push({
row: row,
col: 2,
castling: 'queenside'
});
}
}
return moves;
}
function isValidSquare(row, col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
}
function isSquareUnderAttack(row, col, defendingColor) {
var attackingColor = defendingColor === 'white' ? 'black' : 'white';
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === attackingColor) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, attackingColor);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
return true;
}
}
}
}
}
return false;
}
function getPossibleMovesForAttack(row, col, pieceType, color) {
switch (pieceType) {
case 'Pawn':
return getPawnAttacks(row, col, color);
case 'Rook':
return getRookMoves(row, col, color);
case 'Knight':
return getKnightMoves(row, col, color);
case 'Bishop':
return getBishopMoves(row, col, color);
case 'Queen':
return getQueenMoves(row, col, color);
case 'King':
return getKingBasicMoves(row, col, color);
}
return [];
}
function getPawnAttacks(row, col, color) {
var moves = [];
var direction = color === 'white' ? -1 : 1;
if (isValidSquare(row + direction, col - 1)) {
moves.push({
row: row + direction,
col: col - 1
});
}
if (isValidSquare(row + direction, col + 1)) {
moves.push({
row: row + direction,
col: col + 1
});
}
return moves;
}
function getKingBasicMoves(row, col, color) {
var moves = [];
var directions = [-1, 0, 1];
for (var i = 0; i < directions.length; i++) {
for (var j = 0; j < directions.length; j++) {
if (directions[i] === 0 && directions[j] === 0) {
continue;
}
var newRow = row + directions[i];
var newCol = col + directions[j];
if (isValidSquare(newRow, newCol)) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
return moves;
}
function handleSquareClick(row, col) {
if (gameState !== 'playing') {
return;
}
if (selectedSquare) {
// Check if clicked square is a possible move
var isPossibleMove = false;
for (var i = 0; i < possibleMoves.length; i++) {
if (possibleMoves[i].row === row && possibleMoves[i].col === col) {
isPossibleMove = true;
break;
}
}
if (isPossibleMove) {
var moveData = null;
for (var i = 0; i < possibleMoves.length; i++) {
if (possibleMoves[i].row === row && possibleMoves[i].col === col) {
moveData = possibleMoves[i];
break;
}
}
makeMove(selectedSquare.row, selectedSquare.col, row, col, moveData);
} else {
clearSelection();
if (board[row][col] && board[row][col].color === currentPlayer) {
selectSquare(row, col);
}
}
} else {
if (board[row][col] && board[row][col].color === currentPlayer) {
selectSquare(row, col);
}
}
}
function selectSquare(row, col) {
selectedSquare = {
row: row,
col: col
};
possibleMoves = getPossibleMoves(row, col);
// Highlight selected square
var squareIndex = row * 8 + col;
squares[squareIndex].setSelected(true);
// Highlight possible moves
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var moveSquareIndex = move.row * 8 + move.col;
squares[moveSquareIndex].setPossibleMove(true);
}
}
function clearSelection() {
if (selectedSquare) {
var squareIndex = selectedSquare.row * 8 + selectedSquare.col;
squares[squareIndex].setSelected(false);
}
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var moveSquareIndex = move.row * 8 + move.col;
squares[moveSquareIndex].setPossibleMove(false);
}
selectedSquare = null;
possibleMoves = [];
}
function makeMove(fromRow, fromCol, toRow, toCol, moveData) {
var isCapture = board[toRow][toCol] !== null;
var movingPiece = findPieceAt(fromRow, fromCol);
var movingPieceType = board[fromRow][fromCol];
// Check if move is legal (doesn't leave king in check)
if (!isLegalMove(fromRow, fromCol, toRow, toCol)) {
clearSelection();
return;
}
// Handle en passant capture
var isEnPassant = moveData && moveData.enPassant;
if (isEnPassant) {
// Remove the captured pawn (not at the destination square)
var capturedPiece = findPieceAt(moveData.captureRow, moveData.captureCol);
if (capturedPiece) {
capturedPiece.destroy();
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === capturedPiece) {
pieces.splice(i, 1);
break;
}
}
}
// Clear the captured pawn from the board
board[moveData.captureRow][moveData.captureCol] = null;
isCapture = true; // Treat as capture for sound
}
// Remove captured piece first (normal captures)
if (isCapture && !isEnPassant) {
var capturedPiece = findPieceAt(toRow, toCol);
if (capturedPiece) {
capturedPiece.destroy();
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === capturedPiece) {
pieces.splice(i, 1);
break;
}
}
}
}
// Handle castling
if (moveData && moveData.castling) {
// Move king
board[toRow][toCol] = board[fromRow][fromCol];
board[fromRow][fromCol] = null;
if (movingPiece) {
movingPiece.moveTo(toRow, toCol);
}
// Move rook
var rookFromCol = moveData.castling === 'kingside' ? 7 : 0;
var rookToCol = moveData.castling === 'kingside' ? 5 : 3;
var rook = findPieceAt(fromRow, rookFromCol);
board[fromRow][rookToCol] = board[fromRow][rookFromCol];
board[fromRow][rookFromCol] = null;
if (rook) {
rook.moveTo(fromRow, rookToCol);
}
} else {
// Normal move
board[toRow][toCol] = board[fromRow][fromCol];
board[fromRow][fromCol] = null;
if (movingPiece) {
movingPiece.moveTo(toRow, toCol);
}
}
clearSelection();
// Record this move for en passant tracking
lastMove = {
fromRow: fromRow,
fromCol: fromCol,
toRow: toRow,
toCol: toCol,
piece: movingPieceType,
moveData: moveData
};
// Check for pawn promotion
if (movingPieceType && movingPieceType.type === 'Pawn') {
var promotionRow = movingPieceType.color === 'white' ? 0 : 7;
if (toRow === promotionRow) {
// Show promotion UI
promotingPawn = {
row: toRow,
col: toCol,
color: movingPieceType.color,
piece: movingPiece
};
showPawnPromotionUI();
return; // Don't continue with turn until promotion is complete
}
}
// Play sound
if (isCapture) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
// Check if opponent is in check after this move
var opponentColor = currentPlayer === 'white' ? 'black' : 'white';
var inCheck = isKingInCheck(opponentColor);
// Switch players
currentPlayer = opponentColor;
var statusText = currentPlayer === 'white' ? 'Beyazın hamlesi' : 'Siyahın hamlesi';
if (inCheck) {
if (!canEscapeCheck(currentPlayer)) {
// Checkmate
endGame((currentPlayer === 'white' ? 'Siyah' : 'Beyaz') + ' şah mat ile kazandı!');
return;
} else {
statusText += ' - ŞAH!';
}
}
gameStatusText.setText(statusText);
// Check for game end
if (checkGameEnd()) {
return;
}
// Online/friend mode - no AI moves
if (gameMode === 'online' && currentPlayer === 'black') {
LK.setTimeout(function () {
makeAIMove();
}, 500);
}
}
function findPieceAt(row, col) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].boardRow === row && pieces[i].boardCol === col) {
return pieces[i];
}
}
return null;
}
// Piece values for AI evaluation
var pieceValues = {
'Pawn': 1,
'Knight': 3,
'Bishop': 3,
'Rook': 5,
'Queen': 9,
'King': 10
};
function getPieceValue(pieceType) {
return pieceValues[pieceType] || 0;
}
function isSquareProtectedBy(row, col, color, minProtectors) {
var protectors = 0;
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === color) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, color);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
protectors++;
if (protectors >= minProtectors) {
return true;
}
break;
}
}
}
}
}
return false;
}
function isSquareThreatenedByLowerValue(row, col, myPieceValue, opponentColor) {
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === opponentColor) {
var enemyValue = getPieceValue(board[r][c].type);
if (enemyValue < myPieceValue) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, opponentColor);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
return true;
}
}
}
}
}
}
return false;
}
function canThreatenHigherValuePiece(row, col, myPieceValue, myColor, opponentColor) {
// Simulate having a piece at this position and check what it can threaten
var tempPiece = {
type: 'Queen',
color: myColor
}; // Use queen to get all possible attacking squares
var moves = getPossibleMovesForAttack(row, col, 'Queen', myColor);
for (var i = 0; i < moves.length; i++) {
var targetRow = moves[i].row;
var targetCol = moves[i].col;
if (board[targetRow][targetCol] && board[targetRow][targetCol].color === opponentColor) {
var targetValue = getPieceValue(board[targetRow][targetCol].type);
if (targetValue > myPieceValue) {
return true;
}
}
}
return false;
}
function findThreatenedPieces(color) {
var threatened = [];
var opponentColor = color === 'white' ? 'black' : 'white';
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === color) {
// Check if this piece is threatened
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === opponentColor) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, opponentColor);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
threatened.push({
row: row,
col: col,
piece: board[row][col],
threatenedBy: {
row: r,
col: c
}
});
break;
}
}
}
}
}
}
}
}
return threatened;
}
function getAllPossibleMoves(color) {
var allMoves = [];
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === color) {
var moves = getPossibleMoves(row, col);
for (var i = 0; i < moves.length; i++) {
var move = {
from: {
row: row,
col: col
},
to: {
row: moves[i].row,
col: moves[i].col
},
moveData: moves[i]
};
allMoves.push(move);
}
}
}
}
return allMoves;
}
function evaluateMove(move, aiColor, opponentColor) {
var score = 0;
// Simulate the AI move
var capturedPiece = simulateMove(move);
// Check for immediate checkmate
if (isCheckmate(opponentColor)) {
score += 10000;
}
// Check for immediate check
else if (isKingInCheck(opponentColor)) {
score += 500;
}
// Evaluate material gain/loss
else {
score += evaluateMaterialBalance(move, capturedPiece);
score += evaluatePositionalAdvantage(move, aiColor);
score += evaluatePlayerThreats(aiColor, opponentColor);
score += evaluateTacticalOpportunities(move, aiColor, opponentColor);
}
// Restore the board
undoMove(move, capturedPiece);
return {
score: score
};
}
function simulateMove(move) {
var capturedPiece = board[move.to.row][move.to.col];
board[move.to.row][move.to.col] = board[move.from.row][move.from.col];
board[move.from.row][move.from.col] = null;
return capturedPiece;
}
function undoMove(move, capturedPiece) {
board[move.from.row][move.from.col] = board[move.to.row][move.to.col];
board[move.to.row][move.to.col] = capturedPiece;
}
function isCheckmate(color) {
if (!isKingInCheck(color)) return false;
var allMoves = getAllPossibleMoves(color);
for (var i = 0; i < allMoves.length; i++) {
if (isLegalMove(allMoves[i].from.row, allMoves[i].from.col, allMoves[i].to.row, allMoves[i].to.col)) {
return false;
}
}
return true;
}
function evaluateMaterialBalance(move, capturedPiece) {
var score = 0;
if (capturedPiece) {
score += getPieceValue(capturedPiece.type) * 100;
}
return score;
}
function evaluatePositionalAdvantage(move, aiColor) {
var score = 0;
var pieceType = board[move.to.row][move.to.col].type;
// Center control
if (move.to.row >= 3 && move.to.row <= 4 && move.to.col >= 3 && move.to.col <= 4) {
score += 30;
}
// Piece development
if (pieceType === 'Knight' || pieceType === 'Bishop') {
if (move.to.row === (aiColor === 'black' ? 2 : 5)) {
score += 20;
}
}
// King safety - keep king protected
if (pieceType === 'King') {
if (move.to.col < 2 || move.to.col > 5) {
score += 10;
}
}
return score;
}
function evaluatePlayerThreats(aiColor, opponentColor) {
var score = 0;
var playerMoves = getAllPossibleMoves(opponentColor);
// Count how many AI pieces are threatened by player
var threatenedAIPieces = 0;
var highValueThreats = 0;
for (var i = 0; i < playerMoves.length; i++) {
var playerMove = playerMoves[i];
if (board[playerMove.to.row][playerMove.to.col] && board[playerMove.to.row][playerMove.to.col].color === aiColor) {
threatenedAIPieces++;
var threatValue = getPieceValue(board[playerMove.to.row][playerMove.to.col].type);
if (threatValue >= 5) {
// Rook or Queen
highValueThreats++;
}
}
}
// Penalize if many pieces are threatened
score -= threatenedAIPieces * 20;
score -= highValueThreats * 50;
return score;
}
function evaluateTacticalOpportunities(move, aiColor, opponentColor) {
var score = 0;
var movedPieceType = board[move.to.row][move.to.col].type;
// Look for forks, pins, and discovered attacks
var attackedSquares = getPossibleMovesForAttack(move.to.row, move.to.col, movedPieceType, aiColor);
var valuableTargets = 0;
for (var i = 0; i < attackedSquares.length; i++) {
var targetSquare = attackedSquares[i];
if (board[targetSquare.row][targetSquare.col] && board[targetSquare.row][targetSquare.col].color === opponentColor) {
var targetValue = getPieceValue(board[targetSquare.row][targetSquare.col].type);
if (targetValue >= 3) {
// Bishop, Knight, Rook, Queen
valuableTargets++;
score += targetValue * 10;
}
}
}
// Bonus for threatening multiple pieces (potential fork)
if (valuableTargets >= 2) {
score += 100;
}
return score;
}
function evaluateBestMove(moves, aiColor, opponentColor) {
var bestMove = moves[0];
var bestScore = -9999;
for (var i = 0; i < moves.length; i++) {
var evaluation = evaluateMove(moves[i], aiColor, opponentColor);
if (evaluation.score > bestScore) {
bestScore = evaluation.score;
bestMove = moves[i];
}
}
return bestMove;
}
function makeAIMove() {
var aiColor = 'black';
var opponentColor = 'white';
var inCheck = isKingInCheck(aiColor);
// Get all possible AI moves
var possibleAIMoves = getAllPossibleMoves(aiColor);
if (possibleAIMoves.length === 0) {
return;
}
// Priority-based AI decision making with difficulty scaling
var bestMove = null;
var difficulty = storage.aiDifficulty || 5; // Default to level 5
// 1. HIGHEST PRIORITY: Checkmate in one move (disabled at difficulty 1-2)
if (difficulty >= 3) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
var capturedPiece = simulateMove(move);
var isCheckmate = isKingInCheck(opponentColor) && !canEscapeCheck(opponentColor);
undoMove(move, capturedPiece);
if (isCheckmate) {
bestMove = move;
break;
}
}
}
// 2. SECOND PRIORITY: Escape check if in check (disabled at difficulty 1)
if (!bestMove && inCheck && difficulty >= 2) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) {
var capturedPiece = simulateMove(move);
var stillInCheck = isKingInCheck(aiColor);
undoMove(move, capturedPiece);
if (!stillInCheck) {
bestMove = move;
break;
}
}
}
}
// 3. THIRD PRIORITY: Capture unprotected valuable pieces (disabled at difficulty 1-3)
if (!bestMove && difficulty >= 4) {
var bestCaptureValue = 0;
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
if (board[move.to.row][move.to.col]) {
var captureValue = getPieceValue(board[move.to.row][move.to.col].type);
var isProtected = isSquareProtectedBy(move.to.row, move.to.col, opponentColor, 1);
// Prefer unprotected pieces, but consider protected ones if value is high
if (!isProtected || captureValue >= 5) {
var adjustedValue = isProtected ? captureValue / 2 : captureValue;
if (adjustedValue > bestCaptureValue) {
bestCaptureValue = adjustedValue;
bestMove = move;
}
}
}
}
}
// 4. FOURTH PRIORITY: Make checks that lead to material gain (disabled at difficulty 1-4)
if (!bestMove && difficulty >= 5) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
var capturedPiece = simulateMove(move);
var givesCheck = isKingInCheck(opponentColor);
undoMove(move, capturedPiece);
if (givesCheck) {
bestMove = move;
break;
}
}
}
// 5. FIFTH PRIORITY: Develop pieces and control center (disabled at difficulty 1-5)
if (!bestMove && difficulty >= 6) {
var bestPositionalScore = -999;
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
var score = 0;
var pieceType = board[move.from.row][move.from.col].type;
// Center control bonus
if (move.to.row >= 3 && move.to.row <= 4 && move.to.col >= 3 && move.to.col <= 4) {
score += 30;
}
// Piece development
if (pieceType === 'Knight' || pieceType === 'Bishop') {
if (move.from.row <= 1 && move.to.row >= 2) score += 25; // Development
}
// King safety - castle when possible
if (pieceType === 'King' && Math.abs(move.to.col - move.from.col) === 2) {
score += 50; // Castling bonus
}
// Avoid moving same piece twice in opening
var gamePhase = countTotalPieces();
if (gamePhase > 28) {
// Opening phase
var piece = findPieceAt(move.from.row, move.from.col);
if (piece && piece.hasMoved) score -= 15;
}
if (score > bestPositionalScore) {
bestPositionalScore = score;
bestMove = move;
}
}
}
// 6. SIXTH PRIORITY: Safe piece placement avoiding threats (disabled at difficulty 1-6)
if (!bestMove && difficulty >= 7) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
// Avoid moving to squares attacked by opponent
var isSquareAttacked = isSquareUnderAttack(move.to.row, move.to.col, aiColor);
if (!isSquareAttacked) {
bestMove = move;
break;
}
}
}
// 7. FALLBACK: Random legal move if no good option found
if (!bestMove && possibleAIMoves.length > 0) {
var legalMoves = [];
for (var i = 0; i < possibleAIMoves.length; i++) {
if (isLegalMove(possibleAIMoves[i].from.row, possibleAIMoves[i].from.col, possibleAIMoves[i].to.row, possibleAIMoves[i].to.col)) {
legalMoves.push(possibleAIMoves[i]);
}
}
if (legalMoves.length > 0) {
bestMove = legalMoves[Math.floor(Math.random() * legalMoves.length)];
}
}
if (bestMove) {
makeMove(bestMove.from.row, bestMove.from.col, bestMove.to.row, bestMove.to.col, bestMove.moveData);
}
}
function checkGameEnd() {
// Check if king was captured
var whiteKing = false;
var blackKing = false;
var whiteKingPos = null;
var blackKingPos = null;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].type === 'King') {
if (board[row][col].color === 'white') {
whiteKing = true;
whiteKingPos = {
row: row,
col: col
};
} else {
blackKing = true;
blackKingPos = {
row: row,
col: col
};
}
}
}
}
if (!whiteKing) {
endGame('Siyah şahı ele geçirerek kazandı!');
return true;
} else if (!blackKing) {
endGame('Beyaz şahı ele geçirerek kazandı!');
return true;
}
// Check for checkmate/stalemate
var kingPos = currentPlayer === 'white' ? whiteKingPos : blackKingPos;
var inCheck = isSquareUnderAttack(kingPos.row, kingPos.col, currentPlayer);
var hasLegalMoves = false;
// Check if current player has any legal moves
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === currentPlayer) {
var moves = getPossibleMoves(row, col);
for (var i = 0; i < moves.length; i++) {
if (isLegalMove(row, col, moves[i].row, moves[i].col)) {
hasLegalMoves = true;
break;
}
}
if (hasLegalMoves) {
break;
}
}
}
if (hasLegalMoves) {
break;
}
}
if (!hasLegalMoves) {
if (inCheck) {
endGame((currentPlayer === 'white' ? 'Siyah' : 'Beyaz') + ' şah mat ile kazandı!');
} else {
endGame('Pat ile berabere!');
}
return true;
}
return false;
}
function isKingInCheck(color) {
// Find king position
var kingRow, kingCol;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].type === 'King' && board[row][col].color === color) {
kingRow = row;
kingCol = col;
break;
}
}
if (kingRow !== undefined) {
break;
}
}
if (kingRow !== undefined && kingCol !== undefined) {
return isSquareUnderAttack(kingRow, kingCol, color);
}
return false;
}
function canEscapeCheck(color) {
// Check if king can move to safety, block the check, or capture attacking piece
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === color) {
var moves = getPossibleMoves(row, col);
for (var i = 0; i < moves.length; i++) {
if (isLegalMove(row, col, moves[i].row, moves[i].col)) {
return true;
}
}
}
}
}
return false;
}
function isLegalMove(fromRow, fromCol, toRow, toCol) {
// Simulate the move and check if king is still safe
var originalPiece = board[toRow][toCol];
var movingPiece = board[fromRow][fromCol];
// Make temporary move
board[toRow][toCol] = movingPiece;
board[fromRow][fromCol] = null;
// Find king position
var kingRow, kingCol;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].type === 'King' && board[row][col].color === movingPiece.color) {
kingRow = row;
kingCol = col;
break;
}
}
if (kingRow !== undefined) {
break;
}
}
var isLegal = !isSquareUnderAttack(kingRow, kingCol, movingPiece.color);
// Undo the move
board[fromRow][fromCol] = movingPiece;
board[toRow][toCol] = originalPiece;
return isLegal;
}
function endGame(result) {
gameState = 'gameOver';
gameStatusText.setText(result);
// Update stats
storage.gamesPlayed++;
if (result.includes('White wins')) {
storage.wins++;
storage.playerELO += 20;
} else if (result.includes('Black wins')) {
storage.losses++;
storage.playerELO -= 15;
} else {
storage.draws++;
storage.playerELO += 5;
}
// Save user data after match
saveUserData();
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
function startNewGame() {
gameState = 'playing';
currentPlayer = 'white';
selectedSquare = null;
possibleMoves = [];
lastMove = null; // Reset en passant tracking
initializeBoard();
createBoardVisual();
showGameUI();
gameStatusText.setText('Beyazın hamlesi');
}
function returnToMenu() {
gameState = 'menu';
clearSelection();
// Clean up game elements
for (var i = squares.length - 1; i >= 0; i--) {
squares[i].destroy();
}
squares = [];
for (var i = pieces.length - 1; i >= 0; i--) {
pieces[i].destroy();
}
pieces = [];
showMainMenu();
}
function loginUser(username, password) {
var userId = 'user_' + username.toLowerCase().replace(/[^a-z0-9]/g, '');
var storedPassword = storage['password_' + userId];
if (storedPassword && storedPassword === password) {
storage.username = username;
storage.userId = userId;
storage.isLoggedIn = true;
loadUserData();
showMainMenu();
} else {
// Wrong password or user doesn't exist
titleText.setText('Hatalı kullanıcı adı veya şifre!');
LK.setTimeout(function () {
titleText.setText('Chess Master AI');
}, 2000);
}
}
function registerUser(username, password) {
var userId = 'user_' + username.toLowerCase().replace(/[^a-z0-9]/g, '');
var storedPassword = storage['password_' + userId];
if (!storedPassword) {
// New user registration
storage['password_' + userId] = password;
storage.username = username;
storage.userId = userId;
storage.isLoggedIn = true;
// Initialize user data for new user
storage.playerELO = 1200;
storage.gamesPlayed = 0;
storage.wins = 0;
storage.losses = 0;
storage.draws = 0;
storage.friends = [];
storage.friendRequests = [];
storage.userCreated = Date.now();
loadUserData();
showMainMenu();
} else {
// User already exists
titleText.setText('Bu kullanıcı adı zaten mevcut!');
LK.setTimeout(function () {
titleText.setText('Chess Master AI');
}, 2000);
}
}
function logoutUser() {
storage.isLoggedIn = false;
storage.username = '';
storage.userId = '';
gameState = 'login';
showLoginUI();
}
function loadUserData() {
// Data is already in storage, no need to load from nested object
// Storage plugin handles persistence automatically
// Ensure friends array is properly initialized
if (!storage.friends || !Array.isArray(storage.friends)) {
storage.friends = [];
}
if (!storage.friendRequests || !Array.isArray(storage.friendRequests)) {
storage.friendRequests = [];
}
}
function saveUserData() {
if (storage.userId) {
storage.lastOnline = Date.now();
// Storage plugin automatically persists data
}
}
function addFriend(friendUsername) {
if (friendUsername === storage.username) {
// Show feedback for trying to add yourself
showFriendFeedback('Kendini arkadaş olarak ekleyemezsin!', 0xff0000);
return;
}
var friendUserId = 'user_' + friendUsername.toLowerCase().replace(/[^a-z0-9]/g, '');
// Ensure storage and friends array are properly initialized
if (!storage) {
storage = {};
}
if (!storage.friends || !Array.isArray(storage.friends)) {
storage.friends = [];
}
// Check if already friends
var isAlreadyFriend = false;
if (storage.friends && storage.friends.length > 0) {
for (var i = 0; i < storage.friends.length; i++) {
if (storage.friends[i] && storage.friends[i].userId === friendUserId) {
isAlreadyFriend = true;
break;
}
}
}
if (isAlreadyFriend) {
showFriendFeedback('Bu kullanıcı zaten arkadaş listende!', 0xffa500);
} else {
// Add to friends list
var newFriend = {
userId: friendUserId,
username: friendUsername,
addedTime: Date.now()
};
try {
storage.friends.push(newFriend);
saveUserData();
updateFriendsList();
showFriendFeedback(friendUsername + ' arkadaş listene eklendi!', 0x00ff00);
} catch (error) {
console.log('Error adding friend:', error);
showFriendFeedback('Arkadaş eklenirken hata oluştu!', 0xff0000);
}
}
}
function startFriendMatch(friendData) {
var matchId = 'match_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
currentMatch = {
id: matchId,
player1: storage.userId,
player2: friendData.userId,
player1Name: storage.username,
player2Name: friendData.username,
currentPlayer: 'white',
moves: [],
started: Date.now()
};
storage['match_' + matchId] = currentMatch;
gameMode = 'friend';
// Show match starting message
showFriendFeedback(friendData.username + ' ile maç başlıyor!', 0x00ff00);
LK.setTimeout(function () {
startNewGame();
}, 1500);
}
function findOnlineMatch() {
// Simplified matchmaking - start AI match instead
gameMode = 'online';
startNewGame();
}
function checkForOnlineMatch() {
// Simplified - immediately start AI match
startNewGame();
}
function startOnlineMatch(opponent) {
var matchId = 'match_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
currentMatch = {
id: matchId,
player1: storage.userId,
player2: 'ai_opponent',
currentPlayer: 'white',
moves: [],
started: Date.now()
};
gameMode = 'online';
startNewGame();
}
function updateFriendsList() {
// Clear existing friend list
for (var i = friendsListContainer.children.length - 1; i >= 0; i--) {
friendsListContainer.removeChild(friendsListContainer.children[i]);
}
// Initialize friends array if it doesn't exist
if (!storage.friends || !Array.isArray(storage.friends)) {
storage.friends = [];
}
var yOffset = 0;
for (var i = 0; i < storage.friends.length; i++) {
var friend = storage.friends[i];
if (friend && friend.username && friend.userId) {
var friendItem = new FriendListItem({
username: friend.username,
userId: friend.userId,
online: true // Simplified - assume friends are online
}, function (friendData) {
startFriendMatch(friendData);
});
friendItem.x = 0;
friendItem.y = yOffset;
friendsListContainer.addChild(friendItem);
yOffset += 100;
}
}
}
function showLoginUI() {
// Clear all UI
clearAllUI();
// Position title at top, other elements centered vertically
titleText.x = 1024;
titleText.y = 300;
usernameInput.x = 1024;
usernameInput.y = 1300;
passwordInput.x = 1024;
passwordInput.y = 1450;
loginButton.x = 1024;
loginButton.y = 1650;
registerButton.x = 1024;
registerButton.y = 1800;
game.addChild(titleText);
game.addChild(usernameInput);
game.addChild(passwordInput);
game.addChild(loginButton);
game.addChild(registerButton);
game.addChild(madeWithText);
gameState = 'login';
}
function showMainMenu() {
// Clear all UI
clearAllUI();
// Update display texts
titleText.setText('Chess Master AI');
welcomeText.setText('Hoş geldin, ' + storage.username + '!');
eloText.setText('ELO: ' + storage.playerELO);
statsText.setText('Maçlar: ' + storage.gamesPlayed + ' G:' + storage.wins + ' K:' + storage.losses + ' B:' + storage.draws);
game.addChild(titleText);
game.addChild(welcomeText);
game.addChild(eloText);
game.addChild(statsText);
game.addChild(quickMatchButton);
game.addChild(eloLeaderboardButton);
game.addChild(settingsButton);
game.addChild(logoutButton);
game.addChild(madeWithText);
gameState = 'menu';
}
function showFriendsUI() {
// Clear all UI
clearAllUI();
// New title
multiplayerTitleText = new Text2('Çok Oyunculu Mod', {
size: 72,
fill: 0xFFFFFF
});
multiplayerTitleText.anchor.set(0.5, 0.5);
multiplayerTitleText.x = 1024;
multiplayerTitleText.y = 200;
// Instructions text
instructionsText = new Text2('Arkadaşlarınla oynamak için:', {
size: 48,
fill: 0xFFD700
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 300;
// Step 1
step1Text = new Text2('1. Arkadaşının kullanıcı adını gir', {
size: 42,
fill: 0xC0C0C0
});
step1Text.anchor.set(0.5, 0.5);
step1Text.x = 1024;
step1Text.y = 380;
// Add friend input (repositioned)
addFriendInput.x = 1024;
addFriendInput.y = 450;
// Add friend button (repositioned)
addFriendButton.x = 1024;
addFriendButton.y = 550;
// Step 2
step2Text = new Text2('2. Arkadaş listesinden çevrimiçi arkadaşına tıkla', {
size: 42,
fill: 0xC0C0C0
});
step2Text.anchor.set(0.5, 0.5);
step2Text.x = 1024;
step2Text.y = 650;
// Step 3
step3Text = new Text2('3. Maç otomatik olarak başlayacak!', {
size: 42,
fill: 0xC0C0C0
});
step3Text.anchor.set(0.5, 0.5);
step3Text.x = 1024;
step3Text.y = 720;
// Friends list title
friendsListTitle = new Text2('Arkadaş Listesi:', {
size: 56,
fill: 0xFFFFFF
});
friendsListTitle.anchor.set(0.5, 0.5);
friendsListTitle.x = 1024;
friendsListTitle.y = 850;
// Reposition friends list container
friendsListContainer.x = 224;
friendsListContainer.y = 950;
// Back button (repositioned)
backToMenuButton.x = 1024;
backToMenuButton.y = 2300;
game.addChild(multiplayerTitleText);
game.addChild(instructionsText);
game.addChild(step1Text);
game.addChild(addFriendInput);
game.addChild(addFriendButton);
game.addChild(step2Text);
game.addChild(step3Text);
game.addChild(friendsListTitle);
game.addChild(friendsListContainer);
game.addChild(backToMenuButton);
game.addChild(madeWithText);
updateFriendsList();
gameState = 'friends';
}
function showGameUI() {
// Clear all UI
clearAllUI();
game.addChild(gameStatusText);
game.addChild(backButton);
game.addChild(madeWithText);
gameState = 'playing';
}
function clearAllUI() {
// Hide virtual keyboard first
hideVirtualKeyboard();
// Remove feedback text if present
if (friendFeedbackText && friendFeedbackText.parent) {
game.removeChild(friendFeedbackText);
friendFeedbackText = null;
}
// Remove instruction texts if present
var instructionTexts = [multiplayerTitleText, instructionsText, step1Text, step2Text, step3Text, friendsListTitle];
for (var i = 0; i < instructionTexts.length; i++) {
if (typeof instructionTexts[i] !== 'undefined' && instructionTexts[i] && instructionTexts[i].parent) {
game.removeChild(instructionTexts[i]);
}
}
// Remove all UI elements (excluding madeWithText which should persist)
var uiElements = [titleText, welcomeText, eloText, statsText, usernameInput, passwordInput, loginButton, registerButton, quickMatchButton, eloLeaderboardButton, settingsButton, logoutButton, friendsTitleText, addFriendInput, addFriendButton, friendsListContainer, backToMenuButton, gameStatusText, backButton, eloLeaderboardTitleText, eloLeaderboardContainer, backToMenuFromLeaderboardButton, settingsTitleText, soundVolumeText, decreaseSoundButton, increaseSoundButton, musicVolumeText, decreaseMusicButton, increaseMusicButton, boardThemeText, changeBoardThemeButton, aiDifficultyText, decreaseAIDifficultyButton, increaseAIDifficultyButton, backToMenuFromSettingsButton];
for (var i = 0; i < uiElements.length; i++) {
if (uiElements[i] && uiElements[i].parent) {
game.removeChild(uiElements[i]);
}
}
}
// Initialize based on login status
if (storage.isLoggedIn && storage.username) {
loadUserData();
showMainMenu();
} else {
showLoginUI();
}
// Virtual keyboard system
var virtualKeyboard = null;
var currentInputField = null;
var keyboardVisible = false;
var promotionUI = null;
var promotingPawn = null;
var promotionCallback = null;
function createVirtualKeyboard() {
var keyboard = new Container();
keyboard.x = 124;
keyboard.y = 1600;
// Keyboard background - sized to match board area
var keyboardBg = keyboard.addChild(LK.getAsset('chessBoard', {
anchorX: 0,
anchorY: 0,
scaleX: 1,
scaleY: 0.8
}));
keyboardBg.tint = 0x1a1a1a;
// Create keyboard layout
var layout = [['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'DEL'], ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['SPACE', 'DONE']];
// Calculate uniform key sizes to fit within the 1800px wide area for mobile
var availableWidth = 1800 - 40; // Leave 20px margin on each side
var availableHeight = 1000 - 40; // Leave 20px margin on top and bottom
var keyHeight = 140; // Even larger key height for mobile
var keySpacing = 15;
var totalRows = layout.length;
var maxKeysInRow = 10; // Maximum keys in any row
var keyWidth = (availableWidth - (maxKeysInRow - 1) * keySpacing) / maxKeysInRow;
for (var row = 0; row < layout.length; row++) {
var rowKeys = layout[row].length;
var rowWidth = rowKeys * keyWidth + (rowKeys - 1) * keySpacing;
var startX = (availableWidth - rowWidth) / 2 + 20; // Center the row with margin
for (var col = 0; col < layout[row].length; col++) {
var _char = layout[row][col];
var key = new Container();
// Position keys uniformly
key.x = startX + col * (keyWidth + keySpacing);
key.y = 20 + row * (keyHeight + keySpacing);
// Key background - uniform size for all keys
var keyBg = key.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: keyWidth / 400,
scaleY: keyHeight / 120
}));
keyBg.tint = 0x333333;
keyBg.x = keyWidth / 2;
keyBg.y = keyHeight / 2;
// Key text - larger and consistent
var keyText = new Text2(_char === 'SPACE' ? 'BOŞ' : _char === 'DONE' ? 'TAMAM' : _char, {
size: 44,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
keyText.anchor.set(0.5, 0.5);
keyText.x = keyWidth / 2;
keyText.y = keyHeight / 2;
key.addChild(keyText);
// Store character for click handling
key.character = _char;
// Click handler
key.down = function (x, y, obj) {
if (!currentInputField) {
return;
}
var _char2 = this.character;
if (_char2 === 'DEL') {
// Delete character
if (currentInputField.value.length > 0) {
currentInputField.setText(currentInputField.value.slice(0, -1));
}
} else if (_char2 === 'SPACE') {
// Add space
if (currentInputField.value.length < 20) {
currentInputField.setText(currentInputField.value + ' ');
}
} else if (_char2 === 'DONE') {
// Hide keyboard
hideVirtualKeyboard();
} else {
// Add character
if (currentInputField.value.length < 20) {
currentInputField.setText(currentInputField.value + _char2);
}
}
};
keyboard.addChild(key);
}
}
return keyboard;
}
function showVirtualKeyboard(inputField) {
if (!virtualKeyboard) {
virtualKeyboard = createVirtualKeyboard();
}
currentInputField = inputField;
keyboardVisible = true;
game.addChild(virtualKeyboard);
}
function hideVirtualKeyboard() {
if (virtualKeyboard && virtualKeyboard.parent) {
game.removeChild(virtualKeyboard);
}
currentInputField = null;
keyboardVisible = false;
}
function showPawnPromotionUI() {
promotionUI = new PawnPromotionUI(function (pieceType) {
promotePawn(pieceType);
});
promotionUI.x = 1024;
promotionUI.y = 1200;
game.addChild(promotionUI);
}
function promotePawn(pieceType) {
if (promotingPawn && promotionUI) {
// Remove promotion UI
game.removeChild(promotionUI);
promotionUI = null;
// Update board data
board[promotingPawn.row][promotingPawn.col] = {
type: pieceType,
color: promotingPawn.color
};
// Remove old pawn piece
if (promotingPawn.piece) {
promotingPawn.piece.destroy();
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === promotingPawn.piece) {
pieces.splice(i, 1);
break;
}
}
}
// Create new promoted piece
var newPiece = new ChessPiece(pieceType, promotingPawn.color, promotingPawn.row, promotingPawn.col);
newPiece.x = boardStartX + promotingPawn.col * squareSize + squareSize / 2;
newPiece.y = boardStartY + promotingPawn.row * squareSize + squareSize / 2;
newPiece.hasMoved = true;
pieces.push(newPiece);
game.addChild(newPiece);
promotingPawn = null;
// Continue with game after promotion
var opponentColor = currentPlayer === 'white' ? 'black' : 'white';
var inCheck = isKingInCheck(opponentColor);
// Switch players
currentPlayer = opponentColor;
var statusText = currentPlayer === 'white' ? 'Beyazın hamlesi' : 'Siyahın hamlesi';
if (inCheck) {
if (!canEscapeCheck(currentPlayer)) {
// Checkmate
endGame((currentPlayer === 'white' ? 'Siyah' : 'Beyaz') + ' şah mat ile kazandı!');
return;
} else {
statusText += ' - ŞAH!';
}
}
gameStatusText.setText(statusText);
// Online/friend mode - no AI moves
if (gameMode === 'online' && currentPlayer === 'black') {
LK.setTimeout(function () {
makeAIMove();
}, 500);
}
}
}
game.down = function (x, y, obj) {
// Handle virtual keyboard when input fields are focused
if (gameState === 'login' && (usernameInput.isFocused || passwordInput.isFocused)) {
if (usernameInput.isFocused && !keyboardVisible) {
showVirtualKeyboard(usernameInput);
} else if (passwordInput.isFocused && !keyboardVisible) {
showVirtualKeyboard(passwordInput);
}
} else if (gameState === 'friends' && addFriendInput.isFocused && !keyboardVisible) {
showVirtualKeyboard(addFriendInput);
}
};
game.update = function () {
// Auto-save user data periodically
if (LK.ticks % 300 === 0 && storage.isLoggedIn) {
// Every 5 seconds
saveUserData();
}
// Update friends list periodically when viewing friends
if (gameState === 'friends' && LK.ticks % 600 === 0) {
// Every 10 seconds
updateFriendsList();
}
};
var friendFeedbackText = null;
var multiplayerTitleText = null;
var instructionsText = null;
var step1Text = null;
var step2Text = null;
var step3Text = null;
var friendsListTitle = null;
// Made with Yasin OCAK text - positioned at bottom right corner of screen with larger size
var madeWithText = new Text2('Made with Yasin OCAK', {
size: 64,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
madeWithText.anchor.set(1, 1); // Anchor to bottom right
madeWithText.x = 2048 - 20; // 20px from right edge
madeWithText.y = 2732 - 20; // 20px from bottom edge
// Add to game so it appears on all screens automatically
game.addChild(madeWithText);
// Settings UI elements - organized layout
var settingsTitleText = new Text2('Ayarlar', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
settingsTitleText.anchor.set(0.5, 0.5);
settingsTitleText.x = 1024;
settingsTitleText.y = 300;
// Sound Volume Section (y: 450-580)
var soundVolumeText = new Text2('Ses Seviyesi: 100%', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
soundVolumeText.anchor.set(0.5, 0.5);
soundVolumeText.x = 1024;
soundVolumeText.y = 500;
var decreaseSoundButton = new MenuButton('-', function () {
changeSoundVolume(-10);
});
decreaseSoundButton.x = 750;
decreaseSoundButton.y = 620;
var increaseSoundButton = new MenuButton('+', function () {
changeSoundVolume(10);
});
increaseSoundButton.x = 1298;
increaseSoundButton.y = 620;
// Music Volume Section (y: 650-780)
var musicVolumeText = new Text2('Müzik Seviyesi: 100%', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
musicVolumeText.anchor.set(0.5, 0.5);
musicVolumeText.x = 1024;
musicVolumeText.y = 880;
var decreaseMusicButton = new MenuButton('-', function () {
changeMusicVolume(-10);
});
decreaseMusicButton.x = 800;
decreaseMusicButton.y = 1000;
var increaseMusicButton = new MenuButton('+', function () {
changeMusicVolume(10);
});
increaseMusicButton.x = 1248;
increaseMusicButton.y = 1000;
// Board Theme Section (y: 850-980)
var boardThemeText = new Text2('Tahta Teması: Klasik', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
boardThemeText.anchor.set(0.5, 0.5);
boardThemeText.x = 1024;
boardThemeText.y = 1160;
var changeBoardThemeButton = new MenuButton('Tema Değiştir', function () {
changeBoardTheme();
});
changeBoardThemeButton.x = 1024;
changeBoardThemeButton.y = 1280;
// AI Difficulty Section (y: 1050-1180)
var aiDifficultyText = new Text2('Yapay Zeka Zorluğu: 5', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
aiDifficultyText.anchor.set(0.5, 0.5);
aiDifficultyText.x = 1024;
aiDifficultyText.y = 1440;
var decreaseAIDifficultyButton = new MenuButton('-', function () {
changeAIDifficulty(-1);
});
decreaseAIDifficultyButton.x = 800;
decreaseAIDifficultyButton.y = 1560;
var increaseAIDifficultyButton = new MenuButton('+', function () {
changeAIDifficulty(1);
});
increaseAIDifficultyButton.x = 1248;
increaseAIDifficultyButton.y = 1560;
// Navigation Section (y: 1300+)
var backToMenuFromSettingsButton = new MenuButton('Menüye Dön', function () {
showMainMenu();
});
backToMenuFromSettingsButton.x = 1024;
backToMenuFromSettingsButton.y = 1800;
function showFriendFeedback(message, color) {
// Remove existing feedback
if (friendFeedbackText && friendFeedbackText.parent) {
game.removeChild(friendFeedbackText);
}
// Create new feedback text
friendFeedbackText = new Text2(message, {
size: 44,
fill: color
});
friendFeedbackText.anchor.set(0.5, 0.5);
friendFeedbackText.x = 1024;
friendFeedbackText.y = 600;
game.addChild(friendFeedbackText);
// Auto-hide after 3 seconds
LK.setTimeout(function () {
if (friendFeedbackText && friendFeedbackText.parent) {
game.removeChild(friendFeedbackText);
friendFeedbackText = null;
}
}, 3000);
}
function changeSoundVolume(change) {
storage.soundVolume = Math.max(0, Math.min(100, storage.soundVolume + change));
updateSettingsDisplay();
saveUserData();
}
function changeMusicVolume(change) {
storage.musicVolume = Math.max(0, Math.min(100, storage.musicVolume + change));
updateSettingsDisplay();
saveUserData();
}
function changeBoardTheme() {
var themes = ['klasik', 'azami'];
var currentIndex = themes.indexOf(storage.boardTheme);
if (currentIndex === -1) currentIndex = 0; // Default to klasik if not found
storage.boardTheme = themes[(currentIndex + 1) % themes.length];
updateSettingsDisplay();
saveUserData();
// Recreate board visual if in game to apply new theme
if (gameState === 'playing') {
createBoardVisual();
}
}
function changeAIDifficulty(change) {
storage.aiDifficulty = Math.max(1, Math.min(10, storage.aiDifficulty + change));
updateSettingsDisplay();
saveUserData();
}
function updateSettingsDisplay() {
soundVolumeText.setText('Ses Seviyesi: ' + storage.soundVolume + '%');
musicVolumeText.setText('Müzik Seviyesi: ' + storage.musicVolume + '%');
var themeNames = {
'klasik': 'Klasik',
'azami': 'Azami'
};
boardThemeText.setText('Tahta Teması: ' + (themeNames[storage.boardTheme] || 'Klasik'));
aiDifficultyText.setText('Yapay Zeka Zorluğu: ' + storage.aiDifficulty);
}
function countTotalPieces() {
var total = 0;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col]) {
total++;
}
}
}
return total;
} /****
* Plugins
****/
var storage = LK.import("@upit/storage.v1", {
playerELO: 1200,
gamesPlayed: 0,
wins: 0,
losses: 0,
draws: 0,
username: "",
userId: "",
friends: [],
friendRequests: [],
onlineMatches: [],
isLoggedIn: false,
soundVolume: 100,
musicVolume: 100,
boardTheme: "klasik",
aiDifficulty: 5
});
/****
* Classes
****/
var ChessPiece = Container.expand(function (type, color, row, col) {
var self = Container.call(this);
self.pieceType = type;
self.pieceColor = color;
self.boardRow = row;
self.boardCol = col;
self.hasMoved = false;
// Get asset name based on current theme
var assetName;
if (storage.boardTheme === 'azami') {
// Create bordered piece for azami theme
var borderAssetName = 'azami' + color + type + 'Border';
var fillAssetName = 'azami' + color + type;
// Add border first (larger)
var borderGraphics = self.attachAsset(borderAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Add fill on top (smaller)
var pieceGraphics = self.attachAsset(fillAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
} else {
assetName = color + type; // Classic theme
var pieceGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
}
self.moveTo = function (newRow, newCol) {
self.boardRow = newRow;
self.boardCol = newCol;
self.hasMoved = true;
self.x = boardStartX + newCol * squareSize + squareSize / 2;
self.y = boardStartY + newRow * squareSize + squareSize / 2;
};
return self;
});
var ChessSquare = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.isLight = (row + col) % 2 === 0;
self.piece = null;
self.isSelected = false;
self.isPossibleMove = false;
var squareColor = self.isLight ? 'lightSquare' : 'darkSquare';
var squareGraphics = self.attachAsset(squareColor, {
anchorX: 0,
anchorY: 0
});
self.highlight = null;
self.setSelected = function (selected) {
self.isSelected = selected;
if (selected && !self.highlight) {
self.highlight = self.addChild(LK.getAsset('selectedSquare', {
anchorX: 0,
anchorY: 0,
alpha: 0.5
}));
} else if (!selected && self.highlight) {
self.removeChild(self.highlight);
self.highlight = null;
}
};
self.setPossibleMove = function (possible) {
self.isPossibleMove = possible;
if (possible && !self.highlight) {
self.highlight = self.addChild(LK.getAsset('possibleMove', {
anchorX: 0,
anchorY: 0,
alpha: 0.3
}));
} else if (!possible && self.highlight) {
self.removeChild(self.highlight);
self.highlight = null;
}
};
self.down = function (x, y, obj) {
handleSquareClick(self.row, self.col);
};
return self;
});
var EloLeaderboardItem = Container.expand(function (playerData, rank) {
var self = Container.call(this);
self.playerData = playerData;
self.rank = rank;
var background = self.attachAsset('menuButton', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.8
});
background.tint = rank <= 3 ? rank === 1 ? 0xFFD700 : rank === 2 ? 0xC0C0C0 : 0xCD7F32 : 0x2a2a2a;
var rankText = new Text2('#' + rank, {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
rankText.anchor.set(0, 0.5);
rankText.x = 20;
self.addChild(rankText);
var nameText = new Text2(playerData.username, {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
nameText.anchor.set(0, 0.5);
nameText.x = 120;
self.addChild(nameText);
var eloText = new Text2('ELO: ' + playerData.elo, {
size: 48,
fill: 0xFFD700
});
eloText.anchor.set(1, 0.5);
eloText.x = 520;
self.addChild(eloText);
var gamesText = new Text2('Maçlar: ' + playerData.gamesPlayed, {
size: 36,
fill: 0xC0C0C0
});
gamesText.anchor.set(1, 0.5);
gamesText.x = 580;
gamesText.y = 25;
self.addChild(gamesText);
return self;
});
var FriendListItem = Container.expand(function (friendData, callback) {
var self = Container.call(this);
self.friendData = friendData;
self.callback = callback;
var background = self.attachAsset('menuButton', {
anchorX: 0,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.8
});
background.tint = friendData.online ? 0x1a5f1a : 0x2a2a2a;
var nameText = new Text2(friendData.username, {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
nameText.anchor.set(0, 0.5);
nameText.x = 20;
self.addChild(nameText);
var statusText = new Text2(friendData.online ? 'Oynamak için tıkla!' : 'Çevrimdışı', {
size: 38,
fill: friendData.online ? 0x00FF00 : 0x888888
});
statusText.anchor.set(1, 0.5);
statusText.x = 580;
statusText.y = -15;
self.addChild(statusText);
if (friendData.online) {
var playText = new Text2('🎮 Maç Başlat', {
size: 36,
fill: 0xFFD700
});
playText.anchor.set(1, 0.5);
playText.x = 580;
playText.y = 15;
self.addChild(playText);
}
self.down = function (x, y, obj) {
if (self.callback && friendData.online) {
self.callback(friendData);
}
};
return self;
});
var InputField = Container.expand(function (placeholder, width) {
var self = Container.call(this);
self.width = width || 600;
self.height = 80;
self.placeholder = placeholder;
self.value = '';
self.isFocused = false;
var fieldBackground = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.width / 400,
scaleY: self.height / 120
});
fieldBackground.tint = 0x333333;
self.displayText = new Text2(placeholder, {
size: 48,
fill: 0xCCCCCC
});
self.displayText.anchor.set(0.5, 0.5);
self.addChild(self.displayText);
self.setText = function (text) {
self.value = text;
if (text.length > 0) {
self.displayText.setText(text);
self.displayText.tint = 0xFFFFFF;
} else {
self.displayText.setText(self.placeholder);
self.displayText.tint = 0xCCCCCC;
}
};
self.down = function (x, y, obj) {
// Clear other input focus first
if (usernameInput && usernameInput !== self) {
usernameInput.isFocused = false;
usernameInput.children[0].tint = 0x333333;
}
if (passwordInput && passwordInput !== self) {
passwordInput.isFocused = false;
passwordInput.children[0].tint = 0x333333;
}
if (addFriendInput && addFriendInput !== self) {
addFriendInput.isFocused = false;
addFriendInput.children[0].tint = 0x333333;
}
self.isFocused = true;
fieldBackground.tint = 0x4169e1;
};
return self;
});
var MenuButton = Container.expand(function (text, callback) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 56,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.callback = callback;
self.down = function (x, y, obj) {
if (self.callback) {
self.callback();
}
};
return self;
});
var PawnPromotionUI = Container.expand(function (callback) {
var self = Container.call(this);
self.callback = callback;
// Background overlay
var overlay = self.attachAsset('chessBoard', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.3
});
overlay.tint = 0x000000;
overlay.alpha = 0.8;
var titleText = new Text2('Piyonu Dönüştür:', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -80;
self.addChild(titleText);
// Create promotion piece buttons
var pieces = ['Queen', 'Rook', 'Bishop', 'Knight'];
var pieceNames = ['Vezir', 'Kale', 'Fil', 'At'];
for (var i = 0; i < pieces.length; i++) {
var pieceButton = new Container();
pieceButton.x = (i - 1.5) * 180;
pieceButton.y = 20;
var buttonBg = pieceButton.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
}));
buttonBg.tint = 0x333333;
var buttonText = new Text2(pieceNames[i], {
size: 36,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
buttonText.anchor.set(0.5, 0.5);
pieceButton.addChild(buttonText);
pieceButton.pieceType = pieces[i];
pieceButton.down = function (x, y, obj) {
if (self.callback) {
self.callback(this.pieceType);
}
};
self.addChild(pieceButton);
}
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F4F
});
/****
* Game Code
****/
// Add beautiful chess background image
var backgroundImage = game.addChild(LK.getAsset('chessBackground', {
anchorX: 0,
anchorY: 0,
scaleX: 1,
scaleY: 1
}));
// Azami theme - minimal shapes
var gameState = 'login'; // 'login', 'register', 'menu', 'friends', 'playing', 'gameOver'
var currentPlayer = 'white';
var selectedSquare = null;
var possibleMoves = [];
var board = [];
var pieces = [];
var squares = [];
var gameMode = 'friend'; // 'online', 'friend'
var boardStartX = 224;
var boardStartY = 300;
var squareSize = 200;
var currentMatch = null;
var friendsList = [];
var friendRequestsList = [];
// Login/Register UI
var titleText = new Text2('Chess Master AI', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 200;
var usernameInput = new InputField('Kullanıcı Adı Girin', 800);
usernameInput.x = 1024;
usernameInput.y = 2000;
var passwordInput = new InputField('Şifre Girin', 800);
passwordInput.x = 1024;
passwordInput.y = 2150;
function showSettingsMenu() {
// Clear all UI
clearAllUI();
updateSettingsDisplay();
// Add UI elements in organized order with proper spacing
game.addChild(settingsTitleText);
game.addChild(soundVolumeText);
game.addChild(decreaseSoundButton);
game.addChild(increaseSoundButton);
game.addChild(musicVolumeText);
game.addChild(decreaseMusicButton);
game.addChild(increaseMusicButton);
game.addChild(boardThemeText);
game.addChild(changeBoardThemeButton);
game.addChild(aiDifficultyText);
game.addChild(decreaseAIDifficultyButton);
game.addChild(increaseAIDifficultyButton);
game.addChild(backToMenuFromSettingsButton);
game.addChild(madeWithText);
gameState = 'settings';
}
function showEloLeaderboard() {
// Clear all UI
clearAllUI();
game.addChild(eloLeaderboardTitleText);
game.addChild(eloLeaderboardContainer);
game.addChild(backToMenuFromLeaderboardButton);
game.addChild(madeWithText);
updateEloLeaderboard();
gameState = 'leaderboard';
}
function updateEloLeaderboard() {
// Clear existing leaderboard
for (var i = eloLeaderboardContainer.children.length - 1; i >= 0; i--) {
eloLeaderboardContainer.removeChild(eloLeaderboardContainer.children[i]);
}
// Collect all player data from storage
var players = [];
// Add current player
if (storage.username && storage.playerELO) {
players.push({
username: storage.username,
elo: storage.playerELO,
gamesPlayed: storage.gamesPlayed || 0,
wins: storage.wins || 0,
losses: storage.losses || 0,
draws: storage.draws || 0
});
}
// Add friends data (simulated for demonstration)
if (storage.friends && Array.isArray(storage.friends)) {
for (var i = 0; i < storage.friends.length; i++) {
var friend = storage.friends[i];
if (friend && friend.username) {
// Generate simulated ELO data for friends
var friendElo = 1000 + Math.floor(Math.random() * 800);
var friendGames = Math.floor(Math.random() * 50) + 10;
players.push({
username: friend.username,
elo: friendElo,
gamesPlayed: friendGames,
wins: Math.floor(friendGames * 0.4),
losses: Math.floor(friendGames * 0.4),
draws: Math.floor(friendGames * 0.2)
});
}
}
}
// Add some sample players for demonstration
var samplePlayers = [{
username: 'GrandMaster_Pro',
elo: 2100,
gamesPlayed: 150,
wins: 90,
losses: 45,
draws: 15
}, {
username: 'ChessWizard',
elo: 1950,
gamesPlayed: 120,
wins: 75,
losses: 35,
draws: 10
}, {
username: 'KnightMover',
elo: 1800,
gamesPlayed: 80,
wins: 50,
losses: 25,
draws: 5
}, {
username: 'RookiePlayer',
elo: 1600,
gamesPlayed: 60,
wins: 30,
losses: 25,
draws: 5
}, {
username: 'PawnPusher',
elo: 1400,
gamesPlayed: 40,
wins: 20,
losses: 15,
draws: 5
}];
for (var i = 0; i < samplePlayers.length; i++) {
// Only add if not already in players list
var exists = false;
for (var j = 0; j < players.length; j++) {
if (players[j].username === samplePlayers[i].username) {
exists = true;
break;
}
}
if (!exists) {
players.push(samplePlayers[i]);
}
}
// Sort players by ELO in descending order
players.sort(function (a, b) {
return b.elo - a.elo;
});
// Display top 10 players
var yOffset = 0;
var maxPlayers = Math.min(players.length, 10);
for (var i = 0; i < maxPlayers; i++) {
var player = players[i];
var leaderboardItem = new EloLeaderboardItem(player, i + 1);
leaderboardItem.x = 0;
leaderboardItem.y = yOffset;
eloLeaderboardContainer.addChild(leaderboardItem);
yOffset += 100;
}
}
var loginButton = new MenuButton('Giriş Yap', function () {
if (usernameInput.value.length > 2 && passwordInput.value.length > 2) {
loginUser(usernameInput.value, passwordInput.value);
}
});
loginButton.x = 1024;
loginButton.y = 2350;
var registerButton = new MenuButton('Kayıt Ol', function () {
if (usernameInput.value.length > 2 && passwordInput.value.length > 2) {
registerUser(usernameInput.value, passwordInput.value);
}
});
registerButton.x = 1024;
registerButton.y = 2500;
// Main menu UI
var welcomeText = new Text2('', {
size: 64,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
welcomeText.anchor.set(0.5, 0.5);
welcomeText.x = 1024;
welcomeText.y = 300;
var eloText = new Text2('', {
size: 56,
fill: 0xFFD700
});
eloText.anchor.set(0.5, 0.5);
eloText.x = 1024;
eloText.y = 380;
var statsText = new Text2('', {
size: 44,
fill: 0xC0C0C0,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 1024;
statsText.y = 460;
var quickMatchButton = new MenuButton('Hızlı Maç', function () {
gameMode = 'online';
findOnlineMatch();
});
quickMatchButton.x = 1024;
quickMatchButton.y = 1310;
var eloLeaderboardButton = new MenuButton('ELO Sıralaması', function () {
showEloLeaderboard();
});
eloLeaderboardButton.x = 1024;
eloLeaderboardButton.y = 1600;
var settingsButton = new MenuButton('Ayarlar', function () {
showSettingsMenu();
});
settingsButton.x = 1024;
settingsButton.y = 1710;
var logoutButton = new MenuButton('Çıkış Yap', function () {
logoutUser();
});
logoutButton.x = 1024;
logoutButton.y = 2010;
// Friends UI
var friendsTitleText = new Text2('Arkadaşlar ve Maçlar', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
friendsTitleText.anchor.set(0.5, 0.5);
friendsTitleText.x = 1024;
friendsTitleText.y = 250;
var addFriendInput = new InputField('Arkadaş Kullanıcı Adı', 500);
addFriendInput.x = 1024;
addFriendInput.y = 350;
var addFriendButton = new MenuButton('Arkadaş Ekle', function () {
if (addFriendInput.value.length > 2) {
addFriend(addFriendInput.value);
addFriendInput.setText('');
}
});
addFriendButton.x = 1024;
addFriendButton.y = 450;
var friendsListContainer = new Container();
friendsListContainer.x = 224;
friendsListContainer.y = 600;
var backToMenuButton = new MenuButton('Menüye Dön', function () {
showMainMenu();
});
backToMenuButton.x = 1024;
backToMenuButton.y = 2200;
// ELO Leaderboard UI
var eloLeaderboardTitleText = new Text2('ELO Sıralaması', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
eloLeaderboardTitleText.anchor.set(0.5, 0.5);
eloLeaderboardTitleText.x = 1024;
eloLeaderboardTitleText.y = 250;
var eloLeaderboardContainer = new Container();
eloLeaderboardContainer.x = 224;
eloLeaderboardContainer.y = 400;
var backToMenuFromLeaderboardButton = new MenuButton('Menüye Dön', function () {
showMainMenu();
});
backToMenuFromLeaderboardButton.x = 1024;
backToMenuFromLeaderboardButton.y = 2200;
var eloLeaderboardButton = null;
// Game status display with larger text
var gameStatusText = new Text2('Beyazın hamlesi', {
size: 64,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
gameStatusText.anchor.set(0.5, 0.5);
gameStatusText.x = 1024;
gameStatusText.y = 150;
var backButton = new MenuButton('Menüye Dön', function () {
returnToMenu();
});
backButton.x = 1024;
backButton.y = 2400;
// Game UI elements
var gameStatusText = new Text2('Beyazın hamlesi', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
gameStatusText.anchor.set(0.5, 0.5);
gameStatusText.x = 1024;
gameStatusText.y = 300;
var backButton = new MenuButton('Menüye Dön', function () {
returnToMenu();
});
backButton.x = 1024;
backButton.y = 2400;
// Initialize board
function initializeBoard() {
board = [];
for (var row = 0; row < 8; row++) {
board[row] = [];
for (var col = 0; col < 8; col++) {
board[row][col] = null;
}
}
// Set up initial piece positions
var pieceOrder = ['Rook', 'Knight', 'Bishop', 'Queen', 'King', 'Bishop', 'Knight', 'Rook'];
// White pieces
for (var col = 0; col < 8; col++) {
board[7][col] = {
type: pieceOrder[col],
color: 'white'
};
board[6][col] = {
type: 'Pawn',
color: 'white'
};
}
// Black pieces
for (var col = 0; col < 8; col++) {
board[0][col] = {
type: pieceOrder[col],
color: 'black'
};
board[1][col] = {
type: 'Pawn',
color: 'black'
};
}
}
function createBoardVisual() {
// Clear existing board
for (var i = squares.length - 1; i >= 0; i--) {
squares[i].destroy();
}
squares = [];
for (var i = pieces.length - 1; i >= 0; i--) {
pieces[i].destroy();
}
pieces = [];
// Create squares
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
var square = new ChessSquare(row, col);
square.x = boardStartX + col * squareSize;
square.y = boardStartY + row * squareSize;
squares.push(square);
game.addChild(square);
}
}
// Create pieces
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col]) {
var piece = new ChessPiece(board[row][col].type, board[row][col].color, row, col);
piece.x = boardStartX + col * squareSize + squareSize / 2;
piece.y = boardStartY + row * squareSize + squareSize / 2;
pieces.push(piece);
game.addChild(piece);
}
}
}
}
function getPossibleMoves(row, col) {
var moves = [];
var piece = board[row][col];
if (!piece || piece.color !== currentPlayer) {
return moves;
}
var rawMoves = [];
switch (piece.type) {
case 'Pawn':
rawMoves = getPawnMoves(row, col, piece.color);
break;
case 'Rook':
rawMoves = getRookMoves(row, col, piece.color);
break;
case 'Knight':
rawMoves = getKnightMoves(row, col, piece.color);
break;
case 'Bishop':
rawMoves = getBishopMoves(row, col, piece.color);
break;
case 'Queen':
rawMoves = getQueenMoves(row, col, piece.color);
break;
case 'King':
rawMoves = getKingMoves(row, col, piece.color);
break;
}
// Filter out moves that would leave king in check
for (var i = 0; i < rawMoves.length; i++) {
if (isLegalMove(row, col, rawMoves[i].row, rawMoves[i].col)) {
moves.push(rawMoves[i]);
}
}
return moves;
}
// Global variable to track last move for en passant
var lastMove = null;
function getPawnMoves(row, col, color) {
var moves = [];
var direction = color === 'white' ? -1 : 1;
var startRow = color === 'white' ? 6 : 1;
// Forward move
if (isValidSquare(row + direction, col) && !board[row + direction][col]) {
moves.push({
row: row + direction,
col: col
});
// Double move from start
if (row === startRow && !board[row + 2 * direction][col]) {
moves.push({
row: row + 2 * direction,
col: col
});
}
}
// Captures
if (isValidSquare(row + direction, col - 1) && board[row + direction][col - 1] && board[row + direction][col - 1].color !== color) {
moves.push({
row: row + direction,
col: col - 1
});
}
if (isValidSquare(row + direction, col + 1) && board[row + direction][col + 1] && board[row + direction][col + 1].color !== color) {
moves.push({
row: row + direction,
col: col + 1
});
}
// En passant captures
if (lastMove && lastMove.piece && lastMove.piece.type === 'Pawn' && Math.abs(lastMove.toRow - lastMove.fromRow) === 2) {
// Check if we are adjacent to the pawn that just moved 2 squares
if (lastMove.toRow === row && Math.abs(lastMove.toCol - col) === 1) {
// We can capture en passant
var enPassantRow = row + direction;
var enPassantCol = lastMove.toCol;
if (isValidSquare(enPassantRow, enPassantCol)) {
moves.push({
row: enPassantRow,
col: enPassantCol,
enPassant: true,
captureRow: lastMove.toRow,
captureCol: lastMove.toCol
});
}
}
}
return moves;
}
function getRookMoves(row, col, color) {
var moves = [];
var directions = [{
row: 0,
col: 1
}, {
row: 0,
col: -1
}, {
row: 1,
col: 0
}, {
row: -1,
col: 0
}];
for (var d = 0; d < directions.length; d++) {
var dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = row + dir.row * i;
var newCol = col + dir.col * i;
if (!isValidSquare(newRow, newCol)) {
break;
}
if (!board[newRow][newCol]) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (board[newRow][newCol].color !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
return moves;
}
function getKnightMoves(row, col, color) {
var moves = [];
var knightMoves = [{
row: -2,
col: -1
}, {
row: -2,
col: 1
}, {
row: -1,
col: -2
}, {
row: -1,
col: 2
}, {
row: 1,
col: -2
}, {
row: 1,
col: 2
}, {
row: 2,
col: -1
}, {
row: 2,
col: 1
}];
for (var i = 0; i < knightMoves.length; i++) {
var move = knightMoves[i];
var newRow = row + move.row;
var newCol = col + move.col;
if (isValidSquare(newRow, newCol) && (!board[newRow][newCol] || board[newRow][newCol].color !== color)) {
moves.push({
row: newRow,
col: newCol
});
}
}
return moves;
}
function getBishopMoves(row, col, color) {
var moves = [];
var directions = [{
row: 1,
col: 1
}, {
row: 1,
col: -1
}, {
row: -1,
col: 1
}, {
row: -1,
col: -1
}];
for (var d = 0; d < directions.length; d++) {
var dir = directions[d];
for (var i = 1; i < 8; i++) {
var newRow = row + dir.row * i;
var newCol = col + dir.col * i;
if (!isValidSquare(newRow, newCol)) {
break;
}
if (!board[newRow][newCol]) {
moves.push({
row: newRow,
col: newCol
});
} else {
if (board[newRow][newCol].color !== color) {
moves.push({
row: newRow,
col: newCol
});
}
break;
}
}
}
return moves;
}
function getQueenMoves(row, col, color) {
var rookMoves = getRookMoves(row, col, color);
var bishopMoves = getBishopMoves(row, col, color);
return rookMoves.concat(bishopMoves);
}
function getKingMoves(row, col, color) {
var moves = [];
var directions = [{
row: -1,
col: -1
}, {
row: -1,
col: 0
}, {
row: -1,
col: 1
}, {
row: 0,
col: -1
}, {
row: 0,
col: 1
}, {
row: 1,
col: -1
}, {
row: 1,
col: 0
}, {
row: 1,
col: 1
}];
for (var i = 0; i < directions.length; i++) {
var dir = directions[i];
var newRow = row + dir.row;
var newCol = col + dir.col;
if (isValidSquare(newRow, newCol) && (!board[newRow][newCol] || board[newRow][newCol].color !== color)) {
if (!isSquareUnderAttack(newRow, newCol, color)) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
// Castling
var piece = findPieceAt(row, col);
if (piece && !piece.hasMoved && !isSquareUnderAttack(row, col, color)) {
// Kingside castling
var kingsideRook = findPieceAt(row, 7);
if (kingsideRook && !kingsideRook.hasMoved && !board[row][5] && !board[row][6] && !isSquareUnderAttack(row, 5, color) && !isSquareUnderAttack(row, 6, color)) {
moves.push({
row: row,
col: 6,
castling: 'kingside'
});
}
// Queenside castling
var queensideRook = findPieceAt(row, 0);
if (queensideRook && !queensideRook.hasMoved && !board[row][1] && !board[row][2] && !board[row][3] && !isSquareUnderAttack(row, 2, color) && !isSquareUnderAttack(row, 3, color)) {
moves.push({
row: row,
col: 2,
castling: 'queenside'
});
}
}
return moves;
}
function isValidSquare(row, col) {
return row >= 0 && row < 8 && col >= 0 && col < 8;
}
function isSquareUnderAttack(row, col, defendingColor) {
var attackingColor = defendingColor === 'white' ? 'black' : 'white';
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === attackingColor) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, attackingColor);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
return true;
}
}
}
}
}
return false;
}
function getPossibleMovesForAttack(row, col, pieceType, color) {
switch (pieceType) {
case 'Pawn':
return getPawnAttacks(row, col, color);
case 'Rook':
return getRookMoves(row, col, color);
case 'Knight':
return getKnightMoves(row, col, color);
case 'Bishop':
return getBishopMoves(row, col, color);
case 'Queen':
return getQueenMoves(row, col, color);
case 'King':
return getKingBasicMoves(row, col, color);
}
return [];
}
function getPawnAttacks(row, col, color) {
var moves = [];
var direction = color === 'white' ? -1 : 1;
if (isValidSquare(row + direction, col - 1)) {
moves.push({
row: row + direction,
col: col - 1
});
}
if (isValidSquare(row + direction, col + 1)) {
moves.push({
row: row + direction,
col: col + 1
});
}
return moves;
}
function getKingBasicMoves(row, col, color) {
var moves = [];
var directions = [-1, 0, 1];
for (var i = 0; i < directions.length; i++) {
for (var j = 0; j < directions.length; j++) {
if (directions[i] === 0 && directions[j] === 0) {
continue;
}
var newRow = row + directions[i];
var newCol = col + directions[j];
if (isValidSquare(newRow, newCol)) {
moves.push({
row: newRow,
col: newCol
});
}
}
}
return moves;
}
function handleSquareClick(row, col) {
if (gameState !== 'playing') {
return;
}
if (selectedSquare) {
// Check if clicked square is a possible move
var isPossibleMove = false;
for (var i = 0; i < possibleMoves.length; i++) {
if (possibleMoves[i].row === row && possibleMoves[i].col === col) {
isPossibleMove = true;
break;
}
}
if (isPossibleMove) {
var moveData = null;
for (var i = 0; i < possibleMoves.length; i++) {
if (possibleMoves[i].row === row && possibleMoves[i].col === col) {
moveData = possibleMoves[i];
break;
}
}
makeMove(selectedSquare.row, selectedSquare.col, row, col, moveData);
} else {
clearSelection();
if (board[row][col] && board[row][col].color === currentPlayer) {
selectSquare(row, col);
}
}
} else {
if (board[row][col] && board[row][col].color === currentPlayer) {
selectSquare(row, col);
}
}
}
function selectSquare(row, col) {
selectedSquare = {
row: row,
col: col
};
possibleMoves = getPossibleMoves(row, col);
// Highlight selected square
var squareIndex = row * 8 + col;
squares[squareIndex].setSelected(true);
// Highlight possible moves
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var moveSquareIndex = move.row * 8 + move.col;
squares[moveSquareIndex].setPossibleMove(true);
}
}
function clearSelection() {
if (selectedSquare) {
var squareIndex = selectedSquare.row * 8 + selectedSquare.col;
squares[squareIndex].setSelected(false);
}
for (var i = 0; i < possibleMoves.length; i++) {
var move = possibleMoves[i];
var moveSquareIndex = move.row * 8 + move.col;
squares[moveSquareIndex].setPossibleMove(false);
}
selectedSquare = null;
possibleMoves = [];
}
function makeMove(fromRow, fromCol, toRow, toCol, moveData) {
var isCapture = board[toRow][toCol] !== null;
var movingPiece = findPieceAt(fromRow, fromCol);
var movingPieceType = board[fromRow][fromCol];
// Check if move is legal (doesn't leave king in check)
if (!isLegalMove(fromRow, fromCol, toRow, toCol)) {
clearSelection();
return;
}
// Handle en passant capture
var isEnPassant = moveData && moveData.enPassant;
if (isEnPassant) {
// Remove the captured pawn (not at the destination square)
var capturedPiece = findPieceAt(moveData.captureRow, moveData.captureCol);
if (capturedPiece) {
capturedPiece.destroy();
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === capturedPiece) {
pieces.splice(i, 1);
break;
}
}
}
// Clear the captured pawn from the board
board[moveData.captureRow][moveData.captureCol] = null;
isCapture = true; // Treat as capture for sound
}
// Remove captured piece first (normal captures)
if (isCapture && !isEnPassant) {
var capturedPiece = findPieceAt(toRow, toCol);
if (capturedPiece) {
capturedPiece.destroy();
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === capturedPiece) {
pieces.splice(i, 1);
break;
}
}
}
}
// Handle castling
if (moveData && moveData.castling) {
// Move king
board[toRow][toCol] = board[fromRow][fromCol];
board[fromRow][fromCol] = null;
if (movingPiece) {
movingPiece.moveTo(toRow, toCol);
}
// Move rook
var rookFromCol = moveData.castling === 'kingside' ? 7 : 0;
var rookToCol = moveData.castling === 'kingside' ? 5 : 3;
var rook = findPieceAt(fromRow, rookFromCol);
board[fromRow][rookToCol] = board[fromRow][rookFromCol];
board[fromRow][rookFromCol] = null;
if (rook) {
rook.moveTo(fromRow, rookToCol);
}
} else {
// Normal move
board[toRow][toCol] = board[fromRow][fromCol];
board[fromRow][fromCol] = null;
if (movingPiece) {
movingPiece.moveTo(toRow, toCol);
}
}
clearSelection();
// Record this move for en passant tracking
lastMove = {
fromRow: fromRow,
fromCol: fromCol,
toRow: toRow,
toCol: toCol,
piece: movingPieceType,
moveData: moveData
};
// Check for pawn promotion
if (movingPieceType && movingPieceType.type === 'Pawn') {
var promotionRow = movingPieceType.color === 'white' ? 0 : 7;
if (toRow === promotionRow) {
// Show promotion UI
promotingPawn = {
row: toRow,
col: toCol,
color: movingPieceType.color,
piece: movingPiece
};
showPawnPromotionUI();
return; // Don't continue with turn until promotion is complete
}
}
// Play sound
if (isCapture) {
LK.getSound('capture').play();
} else {
LK.getSound('move').play();
}
// Check if opponent is in check after this move
var opponentColor = currentPlayer === 'white' ? 'black' : 'white';
var inCheck = isKingInCheck(opponentColor);
// Switch players
currentPlayer = opponentColor;
var statusText = currentPlayer === 'white' ? 'Beyazın hamlesi' : 'Siyahın hamlesi';
if (inCheck) {
if (!canEscapeCheck(currentPlayer)) {
// Checkmate
endGame((currentPlayer === 'white' ? 'Siyah' : 'Beyaz') + ' şah mat ile kazandı!');
return;
} else {
statusText += ' - ŞAH!';
}
}
gameStatusText.setText(statusText);
// Check for game end
if (checkGameEnd()) {
return;
}
// Online/friend mode - no AI moves
if (gameMode === 'online' && currentPlayer === 'black') {
LK.setTimeout(function () {
makeAIMove();
}, 500);
}
}
function findPieceAt(row, col) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i].boardRow === row && pieces[i].boardCol === col) {
return pieces[i];
}
}
return null;
}
// Piece values for AI evaluation
var pieceValues = {
'Pawn': 1,
'Knight': 3,
'Bishop': 3,
'Rook': 5,
'Queen': 9,
'King': 10
};
function getPieceValue(pieceType) {
return pieceValues[pieceType] || 0;
}
function isSquareProtectedBy(row, col, color, minProtectors) {
var protectors = 0;
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === color) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, color);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
protectors++;
if (protectors >= minProtectors) {
return true;
}
break;
}
}
}
}
}
return false;
}
function isSquareThreatenedByLowerValue(row, col, myPieceValue, opponentColor) {
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === opponentColor) {
var enemyValue = getPieceValue(board[r][c].type);
if (enemyValue < myPieceValue) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, opponentColor);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
return true;
}
}
}
}
}
}
return false;
}
function canThreatenHigherValuePiece(row, col, myPieceValue, myColor, opponentColor) {
// Simulate having a piece at this position and check what it can threaten
var tempPiece = {
type: 'Queen',
color: myColor
}; // Use queen to get all possible attacking squares
var moves = getPossibleMovesForAttack(row, col, 'Queen', myColor);
for (var i = 0; i < moves.length; i++) {
var targetRow = moves[i].row;
var targetCol = moves[i].col;
if (board[targetRow][targetCol] && board[targetRow][targetCol].color === opponentColor) {
var targetValue = getPieceValue(board[targetRow][targetCol].type);
if (targetValue > myPieceValue) {
return true;
}
}
}
return false;
}
function findThreatenedPieces(color) {
var threatened = [];
var opponentColor = color === 'white' ? 'black' : 'white';
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === color) {
// Check if this piece is threatened
for (var r = 0; r < 8; r++) {
for (var c = 0; c < 8; c++) {
if (board[r][c] && board[r][c].color === opponentColor) {
var moves = getPossibleMovesForAttack(r, c, board[r][c].type, opponentColor);
for (var i = 0; i < moves.length; i++) {
if (moves[i].row === row && moves[i].col === col) {
threatened.push({
row: row,
col: col,
piece: board[row][col],
threatenedBy: {
row: r,
col: c
}
});
break;
}
}
}
}
}
}
}
}
return threatened;
}
function getAllPossibleMoves(color) {
var allMoves = [];
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === color) {
var moves = getPossibleMoves(row, col);
for (var i = 0; i < moves.length; i++) {
var move = {
from: {
row: row,
col: col
},
to: {
row: moves[i].row,
col: moves[i].col
},
moveData: moves[i]
};
allMoves.push(move);
}
}
}
}
return allMoves;
}
function evaluateMove(move, aiColor, opponentColor) {
var score = 0;
// Simulate the AI move
var capturedPiece = simulateMove(move);
// Check for immediate checkmate
if (isCheckmate(opponentColor)) {
score += 10000;
}
// Check for immediate check
else if (isKingInCheck(opponentColor)) {
score += 500;
}
// Evaluate material gain/loss
else {
score += evaluateMaterialBalance(move, capturedPiece);
score += evaluatePositionalAdvantage(move, aiColor);
score += evaluatePlayerThreats(aiColor, opponentColor);
score += evaluateTacticalOpportunities(move, aiColor, opponentColor);
}
// Restore the board
undoMove(move, capturedPiece);
return {
score: score
};
}
function simulateMove(move) {
var capturedPiece = board[move.to.row][move.to.col];
board[move.to.row][move.to.col] = board[move.from.row][move.from.col];
board[move.from.row][move.from.col] = null;
return capturedPiece;
}
function undoMove(move, capturedPiece) {
board[move.from.row][move.from.col] = board[move.to.row][move.to.col];
board[move.to.row][move.to.col] = capturedPiece;
}
function isCheckmate(color) {
if (!isKingInCheck(color)) return false;
var allMoves = getAllPossibleMoves(color);
for (var i = 0; i < allMoves.length; i++) {
if (isLegalMove(allMoves[i].from.row, allMoves[i].from.col, allMoves[i].to.row, allMoves[i].to.col)) {
return false;
}
}
return true;
}
function evaluateMaterialBalance(move, capturedPiece) {
var score = 0;
if (capturedPiece) {
score += getPieceValue(capturedPiece.type) * 100;
}
return score;
}
function evaluatePositionalAdvantage(move, aiColor) {
var score = 0;
var pieceType = board[move.to.row][move.to.col].type;
// Center control
if (move.to.row >= 3 && move.to.row <= 4 && move.to.col >= 3 && move.to.col <= 4) {
score += 30;
}
// Piece development
if (pieceType === 'Knight' || pieceType === 'Bishop') {
if (move.to.row === (aiColor === 'black' ? 2 : 5)) {
score += 20;
}
}
// King safety - keep king protected
if (pieceType === 'King') {
if (move.to.col < 2 || move.to.col > 5) {
score += 10;
}
}
return score;
}
function evaluatePlayerThreats(aiColor, opponentColor) {
var score = 0;
var playerMoves = getAllPossibleMoves(opponentColor);
// Count how many AI pieces are threatened by player
var threatenedAIPieces = 0;
var highValueThreats = 0;
for (var i = 0; i < playerMoves.length; i++) {
var playerMove = playerMoves[i];
if (board[playerMove.to.row][playerMove.to.col] && board[playerMove.to.row][playerMove.to.col].color === aiColor) {
threatenedAIPieces++;
var threatValue = getPieceValue(board[playerMove.to.row][playerMove.to.col].type);
if (threatValue >= 5) {
// Rook or Queen
highValueThreats++;
}
}
}
// Penalize if many pieces are threatened
score -= threatenedAIPieces * 20;
score -= highValueThreats * 50;
return score;
}
function evaluateTacticalOpportunities(move, aiColor, opponentColor) {
var score = 0;
var movedPieceType = board[move.to.row][move.to.col].type;
// Look for forks, pins, and discovered attacks
var attackedSquares = getPossibleMovesForAttack(move.to.row, move.to.col, movedPieceType, aiColor);
var valuableTargets = 0;
for (var i = 0; i < attackedSquares.length; i++) {
var targetSquare = attackedSquares[i];
if (board[targetSquare.row][targetSquare.col] && board[targetSquare.row][targetSquare.col].color === opponentColor) {
var targetValue = getPieceValue(board[targetSquare.row][targetSquare.col].type);
if (targetValue >= 3) {
// Bishop, Knight, Rook, Queen
valuableTargets++;
score += targetValue * 10;
}
}
}
// Bonus for threatening multiple pieces (potential fork)
if (valuableTargets >= 2) {
score += 100;
}
return score;
}
function evaluateBestMove(moves, aiColor, opponentColor) {
var bestMove = moves[0];
var bestScore = -9999;
for (var i = 0; i < moves.length; i++) {
var evaluation = evaluateMove(moves[i], aiColor, opponentColor);
if (evaluation.score > bestScore) {
bestScore = evaluation.score;
bestMove = moves[i];
}
}
return bestMove;
}
function makeAIMove() {
var aiColor = 'black';
var opponentColor = 'white';
var inCheck = isKingInCheck(aiColor);
// Get all possible AI moves
var possibleAIMoves = getAllPossibleMoves(aiColor);
if (possibleAIMoves.length === 0) {
return;
}
// Priority-based AI decision making with difficulty scaling
var bestMove = null;
var difficulty = storage.aiDifficulty || 5; // Default to level 5
// 1. HIGHEST PRIORITY: Checkmate in one move (disabled at difficulty 1-2)
if (difficulty >= 3) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
var capturedPiece = simulateMove(move);
var isCheckmate = isKingInCheck(opponentColor) && !canEscapeCheck(opponentColor);
undoMove(move, capturedPiece);
if (isCheckmate) {
bestMove = move;
break;
}
}
}
// 2. SECOND PRIORITY: Escape check if in check (disabled at difficulty 1)
if (!bestMove && inCheck && difficulty >= 2) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) {
var capturedPiece = simulateMove(move);
var stillInCheck = isKingInCheck(aiColor);
undoMove(move, capturedPiece);
if (!stillInCheck) {
bestMove = move;
break;
}
}
}
}
// 3. THIRD PRIORITY: Capture unprotected valuable pieces (disabled at difficulty 1-3)
if (!bestMove && difficulty >= 4) {
var bestCaptureValue = 0;
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
if (board[move.to.row][move.to.col]) {
var captureValue = getPieceValue(board[move.to.row][move.to.col].type);
var isProtected = isSquareProtectedBy(move.to.row, move.to.col, opponentColor, 1);
// Prefer unprotected pieces, but consider protected ones if value is high
if (!isProtected || captureValue >= 5) {
var adjustedValue = isProtected ? captureValue / 2 : captureValue;
if (adjustedValue > bestCaptureValue) {
bestCaptureValue = adjustedValue;
bestMove = move;
}
}
}
}
}
// 4. FOURTH PRIORITY: Make checks that lead to material gain (disabled at difficulty 1-4)
if (!bestMove && difficulty >= 5) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
var capturedPiece = simulateMove(move);
var givesCheck = isKingInCheck(opponentColor);
undoMove(move, capturedPiece);
if (givesCheck) {
bestMove = move;
break;
}
}
}
// 5. FIFTH PRIORITY: Develop pieces and control center (disabled at difficulty 1-5)
if (!bestMove && difficulty >= 6) {
var bestPositionalScore = -999;
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
var score = 0;
var pieceType = board[move.from.row][move.from.col].type;
// Center control bonus
if (move.to.row >= 3 && move.to.row <= 4 && move.to.col >= 3 && move.to.col <= 4) {
score += 30;
}
// Piece development
if (pieceType === 'Knight' || pieceType === 'Bishop') {
if (move.from.row <= 1 && move.to.row >= 2) score += 25; // Development
}
// King safety - castle when possible
if (pieceType === 'King' && Math.abs(move.to.col - move.from.col) === 2) {
score += 50; // Castling bonus
}
// Avoid moving same piece twice in opening
var gamePhase = countTotalPieces();
if (gamePhase > 28) {
// Opening phase
var piece = findPieceAt(move.from.row, move.from.col);
if (piece && piece.hasMoved) score -= 15;
}
if (score > bestPositionalScore) {
bestPositionalScore = score;
bestMove = move;
}
}
}
// 6. SIXTH PRIORITY: Safe piece placement avoiding threats (disabled at difficulty 1-6)
if (!bestMove && difficulty >= 7) {
for (var i = 0; i < possibleAIMoves.length; i++) {
var move = possibleAIMoves[i];
if (!isLegalMove(move.from.row, move.from.col, move.to.row, move.to.col)) continue;
// Avoid moving to squares attacked by opponent
var isSquareAttacked = isSquareUnderAttack(move.to.row, move.to.col, aiColor);
if (!isSquareAttacked) {
bestMove = move;
break;
}
}
}
// 7. FALLBACK: Random legal move if no good option found
if (!bestMove && possibleAIMoves.length > 0) {
var legalMoves = [];
for (var i = 0; i < possibleAIMoves.length; i++) {
if (isLegalMove(possibleAIMoves[i].from.row, possibleAIMoves[i].from.col, possibleAIMoves[i].to.row, possibleAIMoves[i].to.col)) {
legalMoves.push(possibleAIMoves[i]);
}
}
if (legalMoves.length > 0) {
bestMove = legalMoves[Math.floor(Math.random() * legalMoves.length)];
}
}
if (bestMove) {
makeMove(bestMove.from.row, bestMove.from.col, bestMove.to.row, bestMove.to.col, bestMove.moveData);
}
}
function checkGameEnd() {
// Check if king was captured
var whiteKing = false;
var blackKing = false;
var whiteKingPos = null;
var blackKingPos = null;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].type === 'King') {
if (board[row][col].color === 'white') {
whiteKing = true;
whiteKingPos = {
row: row,
col: col
};
} else {
blackKing = true;
blackKingPos = {
row: row,
col: col
};
}
}
}
}
if (!whiteKing) {
endGame('Siyah şahı ele geçirerek kazandı!');
return true;
} else if (!blackKing) {
endGame('Beyaz şahı ele geçirerek kazandı!');
return true;
}
// Check for checkmate/stalemate
var kingPos = currentPlayer === 'white' ? whiteKingPos : blackKingPos;
var inCheck = isSquareUnderAttack(kingPos.row, kingPos.col, currentPlayer);
var hasLegalMoves = false;
// Check if current player has any legal moves
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === currentPlayer) {
var moves = getPossibleMoves(row, col);
for (var i = 0; i < moves.length; i++) {
if (isLegalMove(row, col, moves[i].row, moves[i].col)) {
hasLegalMoves = true;
break;
}
}
if (hasLegalMoves) {
break;
}
}
}
if (hasLegalMoves) {
break;
}
}
if (!hasLegalMoves) {
if (inCheck) {
endGame((currentPlayer === 'white' ? 'Siyah' : 'Beyaz') + ' şah mat ile kazandı!');
} else {
endGame('Pat ile berabere!');
}
return true;
}
return false;
}
function isKingInCheck(color) {
// Find king position
var kingRow, kingCol;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].type === 'King' && board[row][col].color === color) {
kingRow = row;
kingCol = col;
break;
}
}
if (kingRow !== undefined) {
break;
}
}
if (kingRow !== undefined && kingCol !== undefined) {
return isSquareUnderAttack(kingRow, kingCol, color);
}
return false;
}
function canEscapeCheck(color) {
// Check if king can move to safety, block the check, or capture attacking piece
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].color === color) {
var moves = getPossibleMoves(row, col);
for (var i = 0; i < moves.length; i++) {
if (isLegalMove(row, col, moves[i].row, moves[i].col)) {
return true;
}
}
}
}
}
return false;
}
function isLegalMove(fromRow, fromCol, toRow, toCol) {
// Simulate the move and check if king is still safe
var originalPiece = board[toRow][toCol];
var movingPiece = board[fromRow][fromCol];
// Make temporary move
board[toRow][toCol] = movingPiece;
board[fromRow][fromCol] = null;
// Find king position
var kingRow, kingCol;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col] && board[row][col].type === 'King' && board[row][col].color === movingPiece.color) {
kingRow = row;
kingCol = col;
break;
}
}
if (kingRow !== undefined) {
break;
}
}
var isLegal = !isSquareUnderAttack(kingRow, kingCol, movingPiece.color);
// Undo the move
board[fromRow][fromCol] = movingPiece;
board[toRow][toCol] = originalPiece;
return isLegal;
}
function endGame(result) {
gameState = 'gameOver';
gameStatusText.setText(result);
// Update stats
storage.gamesPlayed++;
if (result.includes('White wins')) {
storage.wins++;
storage.playerELO += 20;
} else if (result.includes('Black wins')) {
storage.losses++;
storage.playerELO -= 15;
} else {
storage.draws++;
storage.playerELO += 5;
}
// Save user data after match
saveUserData();
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
function startNewGame() {
gameState = 'playing';
currentPlayer = 'white';
selectedSquare = null;
possibleMoves = [];
lastMove = null; // Reset en passant tracking
initializeBoard();
createBoardVisual();
showGameUI();
gameStatusText.setText('Beyazın hamlesi');
}
function returnToMenu() {
gameState = 'menu';
clearSelection();
// Clean up game elements
for (var i = squares.length - 1; i >= 0; i--) {
squares[i].destroy();
}
squares = [];
for (var i = pieces.length - 1; i >= 0; i--) {
pieces[i].destroy();
}
pieces = [];
showMainMenu();
}
function loginUser(username, password) {
var userId = 'user_' + username.toLowerCase().replace(/[^a-z0-9]/g, '');
var storedPassword = storage['password_' + userId];
if (storedPassword && storedPassword === password) {
storage.username = username;
storage.userId = userId;
storage.isLoggedIn = true;
loadUserData();
showMainMenu();
} else {
// Wrong password or user doesn't exist
titleText.setText('Hatalı kullanıcı adı veya şifre!');
LK.setTimeout(function () {
titleText.setText('Chess Master AI');
}, 2000);
}
}
function registerUser(username, password) {
var userId = 'user_' + username.toLowerCase().replace(/[^a-z0-9]/g, '');
var storedPassword = storage['password_' + userId];
if (!storedPassword) {
// New user registration
storage['password_' + userId] = password;
storage.username = username;
storage.userId = userId;
storage.isLoggedIn = true;
// Initialize user data for new user
storage.playerELO = 1200;
storage.gamesPlayed = 0;
storage.wins = 0;
storage.losses = 0;
storage.draws = 0;
storage.friends = [];
storage.friendRequests = [];
storage.userCreated = Date.now();
loadUserData();
showMainMenu();
} else {
// User already exists
titleText.setText('Bu kullanıcı adı zaten mevcut!');
LK.setTimeout(function () {
titleText.setText('Chess Master AI');
}, 2000);
}
}
function logoutUser() {
storage.isLoggedIn = false;
storage.username = '';
storage.userId = '';
gameState = 'login';
showLoginUI();
}
function loadUserData() {
// Data is already in storage, no need to load from nested object
// Storage plugin handles persistence automatically
// Ensure friends array is properly initialized
if (!storage.friends || !Array.isArray(storage.friends)) {
storage.friends = [];
}
if (!storage.friendRequests || !Array.isArray(storage.friendRequests)) {
storage.friendRequests = [];
}
}
function saveUserData() {
if (storage.userId) {
storage.lastOnline = Date.now();
// Storage plugin automatically persists data
}
}
function addFriend(friendUsername) {
if (friendUsername === storage.username) {
// Show feedback for trying to add yourself
showFriendFeedback('Kendini arkadaş olarak ekleyemezsin!', 0xff0000);
return;
}
var friendUserId = 'user_' + friendUsername.toLowerCase().replace(/[^a-z0-9]/g, '');
// Ensure storage and friends array are properly initialized
if (!storage) {
storage = {};
}
if (!storage.friends || !Array.isArray(storage.friends)) {
storage.friends = [];
}
// Check if already friends
var isAlreadyFriend = false;
if (storage.friends && storage.friends.length > 0) {
for (var i = 0; i < storage.friends.length; i++) {
if (storage.friends[i] && storage.friends[i].userId === friendUserId) {
isAlreadyFriend = true;
break;
}
}
}
if (isAlreadyFriend) {
showFriendFeedback('Bu kullanıcı zaten arkadaş listende!', 0xffa500);
} else {
// Add to friends list
var newFriend = {
userId: friendUserId,
username: friendUsername,
addedTime: Date.now()
};
try {
storage.friends.push(newFriend);
saveUserData();
updateFriendsList();
showFriendFeedback(friendUsername + ' arkadaş listene eklendi!', 0x00ff00);
} catch (error) {
console.log('Error adding friend:', error);
showFriendFeedback('Arkadaş eklenirken hata oluştu!', 0xff0000);
}
}
}
function startFriendMatch(friendData) {
var matchId = 'match_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
currentMatch = {
id: matchId,
player1: storage.userId,
player2: friendData.userId,
player1Name: storage.username,
player2Name: friendData.username,
currentPlayer: 'white',
moves: [],
started: Date.now()
};
storage['match_' + matchId] = currentMatch;
gameMode = 'friend';
// Show match starting message
showFriendFeedback(friendData.username + ' ile maç başlıyor!', 0x00ff00);
LK.setTimeout(function () {
startNewGame();
}, 1500);
}
function findOnlineMatch() {
// Simplified matchmaking - start AI match instead
gameMode = 'online';
startNewGame();
}
function checkForOnlineMatch() {
// Simplified - immediately start AI match
startNewGame();
}
function startOnlineMatch(opponent) {
var matchId = 'match_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
currentMatch = {
id: matchId,
player1: storage.userId,
player2: 'ai_opponent',
currentPlayer: 'white',
moves: [],
started: Date.now()
};
gameMode = 'online';
startNewGame();
}
function updateFriendsList() {
// Clear existing friend list
for (var i = friendsListContainer.children.length - 1; i >= 0; i--) {
friendsListContainer.removeChild(friendsListContainer.children[i]);
}
// Initialize friends array if it doesn't exist
if (!storage.friends || !Array.isArray(storage.friends)) {
storage.friends = [];
}
var yOffset = 0;
for (var i = 0; i < storage.friends.length; i++) {
var friend = storage.friends[i];
if (friend && friend.username && friend.userId) {
var friendItem = new FriendListItem({
username: friend.username,
userId: friend.userId,
online: true // Simplified - assume friends are online
}, function (friendData) {
startFriendMatch(friendData);
});
friendItem.x = 0;
friendItem.y = yOffset;
friendsListContainer.addChild(friendItem);
yOffset += 100;
}
}
}
function showLoginUI() {
// Clear all UI
clearAllUI();
// Position title at top, other elements centered vertically
titleText.x = 1024;
titleText.y = 300;
usernameInput.x = 1024;
usernameInput.y = 1300;
passwordInput.x = 1024;
passwordInput.y = 1450;
loginButton.x = 1024;
loginButton.y = 1650;
registerButton.x = 1024;
registerButton.y = 1800;
game.addChild(titleText);
game.addChild(usernameInput);
game.addChild(passwordInput);
game.addChild(loginButton);
game.addChild(registerButton);
game.addChild(madeWithText);
gameState = 'login';
}
function showMainMenu() {
// Clear all UI
clearAllUI();
// Update display texts
titleText.setText('Chess Master AI');
welcomeText.setText('Hoş geldin, ' + storage.username + '!');
eloText.setText('ELO: ' + storage.playerELO);
statsText.setText('Maçlar: ' + storage.gamesPlayed + ' G:' + storage.wins + ' K:' + storage.losses + ' B:' + storage.draws);
game.addChild(titleText);
game.addChild(welcomeText);
game.addChild(eloText);
game.addChild(statsText);
game.addChild(quickMatchButton);
game.addChild(eloLeaderboardButton);
game.addChild(settingsButton);
game.addChild(logoutButton);
game.addChild(madeWithText);
gameState = 'menu';
}
function showFriendsUI() {
// Clear all UI
clearAllUI();
// New title
multiplayerTitleText = new Text2('Çok Oyunculu Mod', {
size: 72,
fill: 0xFFFFFF
});
multiplayerTitleText.anchor.set(0.5, 0.5);
multiplayerTitleText.x = 1024;
multiplayerTitleText.y = 200;
// Instructions text
instructionsText = new Text2('Arkadaşlarınla oynamak için:', {
size: 48,
fill: 0xFFD700
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 300;
// Step 1
step1Text = new Text2('1. Arkadaşının kullanıcı adını gir', {
size: 42,
fill: 0xC0C0C0
});
step1Text.anchor.set(0.5, 0.5);
step1Text.x = 1024;
step1Text.y = 380;
// Add friend input (repositioned)
addFriendInput.x = 1024;
addFriendInput.y = 450;
// Add friend button (repositioned)
addFriendButton.x = 1024;
addFriendButton.y = 550;
// Step 2
step2Text = new Text2('2. Arkadaş listesinden çevrimiçi arkadaşına tıkla', {
size: 42,
fill: 0xC0C0C0
});
step2Text.anchor.set(0.5, 0.5);
step2Text.x = 1024;
step2Text.y = 650;
// Step 3
step3Text = new Text2('3. Maç otomatik olarak başlayacak!', {
size: 42,
fill: 0xC0C0C0
});
step3Text.anchor.set(0.5, 0.5);
step3Text.x = 1024;
step3Text.y = 720;
// Friends list title
friendsListTitle = new Text2('Arkadaş Listesi:', {
size: 56,
fill: 0xFFFFFF
});
friendsListTitle.anchor.set(0.5, 0.5);
friendsListTitle.x = 1024;
friendsListTitle.y = 850;
// Reposition friends list container
friendsListContainer.x = 224;
friendsListContainer.y = 950;
// Back button (repositioned)
backToMenuButton.x = 1024;
backToMenuButton.y = 2300;
game.addChild(multiplayerTitleText);
game.addChild(instructionsText);
game.addChild(step1Text);
game.addChild(addFriendInput);
game.addChild(addFriendButton);
game.addChild(step2Text);
game.addChild(step3Text);
game.addChild(friendsListTitle);
game.addChild(friendsListContainer);
game.addChild(backToMenuButton);
game.addChild(madeWithText);
updateFriendsList();
gameState = 'friends';
}
function showGameUI() {
// Clear all UI
clearAllUI();
game.addChild(gameStatusText);
game.addChild(backButton);
game.addChild(madeWithText);
gameState = 'playing';
}
function clearAllUI() {
// Hide virtual keyboard first
hideVirtualKeyboard();
// Remove feedback text if present
if (friendFeedbackText && friendFeedbackText.parent) {
game.removeChild(friendFeedbackText);
friendFeedbackText = null;
}
// Remove instruction texts if present
var instructionTexts = [multiplayerTitleText, instructionsText, step1Text, step2Text, step3Text, friendsListTitle];
for (var i = 0; i < instructionTexts.length; i++) {
if (typeof instructionTexts[i] !== 'undefined' && instructionTexts[i] && instructionTexts[i].parent) {
game.removeChild(instructionTexts[i]);
}
}
// Remove all UI elements (excluding madeWithText which should persist)
var uiElements = [titleText, welcomeText, eloText, statsText, usernameInput, passwordInput, loginButton, registerButton, quickMatchButton, eloLeaderboardButton, settingsButton, logoutButton, friendsTitleText, addFriendInput, addFriendButton, friendsListContainer, backToMenuButton, gameStatusText, backButton, eloLeaderboardTitleText, eloLeaderboardContainer, backToMenuFromLeaderboardButton, settingsTitleText, soundVolumeText, decreaseSoundButton, increaseSoundButton, musicVolumeText, decreaseMusicButton, increaseMusicButton, boardThemeText, changeBoardThemeButton, aiDifficultyText, decreaseAIDifficultyButton, increaseAIDifficultyButton, backToMenuFromSettingsButton];
for (var i = 0; i < uiElements.length; i++) {
if (uiElements[i] && uiElements[i].parent) {
game.removeChild(uiElements[i]);
}
}
}
// Initialize based on login status
if (storage.isLoggedIn && storage.username) {
loadUserData();
showMainMenu();
} else {
showLoginUI();
}
// Virtual keyboard system
var virtualKeyboard = null;
var currentInputField = null;
var keyboardVisible = false;
var promotionUI = null;
var promotingPawn = null;
var promotionCallback = null;
function createVirtualKeyboard() {
var keyboard = new Container();
keyboard.x = 124;
keyboard.y = 1600;
// Keyboard background - sized to match board area
var keyboardBg = keyboard.addChild(LK.getAsset('chessBoard', {
anchorX: 0,
anchorY: 0,
scaleX: 1,
scaleY: 0.8
}));
keyboardBg.tint = 0x1a1a1a;
// Create keyboard layout
var layout = [['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'DEL'], ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['SPACE', 'DONE']];
// Calculate uniform key sizes to fit within the 1800px wide area for mobile
var availableWidth = 1800 - 40; // Leave 20px margin on each side
var availableHeight = 1000 - 40; // Leave 20px margin on top and bottom
var keyHeight = 140; // Even larger key height for mobile
var keySpacing = 15;
var totalRows = layout.length;
var maxKeysInRow = 10; // Maximum keys in any row
var keyWidth = (availableWidth - (maxKeysInRow - 1) * keySpacing) / maxKeysInRow;
for (var row = 0; row < layout.length; row++) {
var rowKeys = layout[row].length;
var rowWidth = rowKeys * keyWidth + (rowKeys - 1) * keySpacing;
var startX = (availableWidth - rowWidth) / 2 + 20; // Center the row with margin
for (var col = 0; col < layout[row].length; col++) {
var _char = layout[row][col];
var key = new Container();
// Position keys uniformly
key.x = startX + col * (keyWidth + keySpacing);
key.y = 20 + row * (keyHeight + keySpacing);
// Key background - uniform size for all keys
var keyBg = key.addChild(LK.getAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: keyWidth / 400,
scaleY: keyHeight / 120
}));
keyBg.tint = 0x333333;
keyBg.x = keyWidth / 2;
keyBg.y = keyHeight / 2;
// Key text - larger and consistent
var keyText = new Text2(_char === 'SPACE' ? 'BOŞ' : _char === 'DONE' ? 'TAMAM' : _char, {
size: 44,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
keyText.anchor.set(0.5, 0.5);
keyText.x = keyWidth / 2;
keyText.y = keyHeight / 2;
key.addChild(keyText);
// Store character for click handling
key.character = _char;
// Click handler
key.down = function (x, y, obj) {
if (!currentInputField) {
return;
}
var _char2 = this.character;
if (_char2 === 'DEL') {
// Delete character
if (currentInputField.value.length > 0) {
currentInputField.setText(currentInputField.value.slice(0, -1));
}
} else if (_char2 === 'SPACE') {
// Add space
if (currentInputField.value.length < 20) {
currentInputField.setText(currentInputField.value + ' ');
}
} else if (_char2 === 'DONE') {
// Hide keyboard
hideVirtualKeyboard();
} else {
// Add character
if (currentInputField.value.length < 20) {
currentInputField.setText(currentInputField.value + _char2);
}
}
};
keyboard.addChild(key);
}
}
return keyboard;
}
function showVirtualKeyboard(inputField) {
if (!virtualKeyboard) {
virtualKeyboard = createVirtualKeyboard();
}
currentInputField = inputField;
keyboardVisible = true;
game.addChild(virtualKeyboard);
}
function hideVirtualKeyboard() {
if (virtualKeyboard && virtualKeyboard.parent) {
game.removeChild(virtualKeyboard);
}
currentInputField = null;
keyboardVisible = false;
}
function showPawnPromotionUI() {
promotionUI = new PawnPromotionUI(function (pieceType) {
promotePawn(pieceType);
});
promotionUI.x = 1024;
promotionUI.y = 1200;
game.addChild(promotionUI);
}
function promotePawn(pieceType) {
if (promotingPawn && promotionUI) {
// Remove promotion UI
game.removeChild(promotionUI);
promotionUI = null;
// Update board data
board[promotingPawn.row][promotingPawn.col] = {
type: pieceType,
color: promotingPawn.color
};
// Remove old pawn piece
if (promotingPawn.piece) {
promotingPawn.piece.destroy();
for (var i = pieces.length - 1; i >= 0; i--) {
if (pieces[i] === promotingPawn.piece) {
pieces.splice(i, 1);
break;
}
}
}
// Create new promoted piece
var newPiece = new ChessPiece(pieceType, promotingPawn.color, promotingPawn.row, promotingPawn.col);
newPiece.x = boardStartX + promotingPawn.col * squareSize + squareSize / 2;
newPiece.y = boardStartY + promotingPawn.row * squareSize + squareSize / 2;
newPiece.hasMoved = true;
pieces.push(newPiece);
game.addChild(newPiece);
promotingPawn = null;
// Continue with game after promotion
var opponentColor = currentPlayer === 'white' ? 'black' : 'white';
var inCheck = isKingInCheck(opponentColor);
// Switch players
currentPlayer = opponentColor;
var statusText = currentPlayer === 'white' ? 'Beyazın hamlesi' : 'Siyahın hamlesi';
if (inCheck) {
if (!canEscapeCheck(currentPlayer)) {
// Checkmate
endGame((currentPlayer === 'white' ? 'Siyah' : 'Beyaz') + ' şah mat ile kazandı!');
return;
} else {
statusText += ' - ŞAH!';
}
}
gameStatusText.setText(statusText);
// Online/friend mode - no AI moves
if (gameMode === 'online' && currentPlayer === 'black') {
LK.setTimeout(function () {
makeAIMove();
}, 500);
}
}
}
game.down = function (x, y, obj) {
// Handle virtual keyboard when input fields are focused
if (gameState === 'login' && (usernameInput.isFocused || passwordInput.isFocused)) {
if (usernameInput.isFocused && !keyboardVisible) {
showVirtualKeyboard(usernameInput);
} else if (passwordInput.isFocused && !keyboardVisible) {
showVirtualKeyboard(passwordInput);
}
} else if (gameState === 'friends' && addFriendInput.isFocused && !keyboardVisible) {
showVirtualKeyboard(addFriendInput);
}
};
game.update = function () {
// Auto-save user data periodically
if (LK.ticks % 300 === 0 && storage.isLoggedIn) {
// Every 5 seconds
saveUserData();
}
// Update friends list periodically when viewing friends
if (gameState === 'friends' && LK.ticks % 600 === 0) {
// Every 10 seconds
updateFriendsList();
}
};
var friendFeedbackText = null;
var multiplayerTitleText = null;
var instructionsText = null;
var step1Text = null;
var step2Text = null;
var step3Text = null;
var friendsListTitle = null;
// Made with Yasin OCAK text - positioned at bottom right corner of screen with larger size
var madeWithText = new Text2('Made with Yasin OCAK', {
size: 64,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
madeWithText.anchor.set(1, 1); // Anchor to bottom right
madeWithText.x = 2048 - 20; // 20px from right edge
madeWithText.y = 2732 - 20; // 20px from bottom edge
// Add to game so it appears on all screens automatically
game.addChild(madeWithText);
// Settings UI elements - organized layout
var settingsTitleText = new Text2('Ayarlar', {
size: 72,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
settingsTitleText.anchor.set(0.5, 0.5);
settingsTitleText.x = 1024;
settingsTitleText.y = 300;
// Sound Volume Section (y: 450-580)
var soundVolumeText = new Text2('Ses Seviyesi: 100%', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
soundVolumeText.anchor.set(0.5, 0.5);
soundVolumeText.x = 1024;
soundVolumeText.y = 500;
var decreaseSoundButton = new MenuButton('-', function () {
changeSoundVolume(-10);
});
decreaseSoundButton.x = 750;
decreaseSoundButton.y = 620;
var increaseSoundButton = new MenuButton('+', function () {
changeSoundVolume(10);
});
increaseSoundButton.x = 1298;
increaseSoundButton.y = 620;
// Music Volume Section (y: 650-780)
var musicVolumeText = new Text2('Müzik Seviyesi: 100%', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
musicVolumeText.anchor.set(0.5, 0.5);
musicVolumeText.x = 1024;
musicVolumeText.y = 880;
var decreaseMusicButton = new MenuButton('-', function () {
changeMusicVolume(-10);
});
decreaseMusicButton.x = 800;
decreaseMusicButton.y = 1000;
var increaseMusicButton = new MenuButton('+', function () {
changeMusicVolume(10);
});
increaseMusicButton.x = 1248;
increaseMusicButton.y = 1000;
// Board Theme Section (y: 850-980)
var boardThemeText = new Text2('Tahta Teması: Klasik', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
boardThemeText.anchor.set(0.5, 0.5);
boardThemeText.x = 1024;
boardThemeText.y = 1160;
var changeBoardThemeButton = new MenuButton('Tema Değiştir', function () {
changeBoardTheme();
});
changeBoardThemeButton.x = 1024;
changeBoardThemeButton.y = 1280;
// AI Difficulty Section (y: 1050-1180)
var aiDifficultyText = new Text2('Yapay Zeka Zorluğu: 5', {
size: 48,
fill: 0xFFFFFF,
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
aiDifficultyText.anchor.set(0.5, 0.5);
aiDifficultyText.x = 1024;
aiDifficultyText.y = 1440;
var decreaseAIDifficultyButton = new MenuButton('-', function () {
changeAIDifficulty(-1);
});
decreaseAIDifficultyButton.x = 800;
decreaseAIDifficultyButton.y = 1560;
var increaseAIDifficultyButton = new MenuButton('+', function () {
changeAIDifficulty(1);
});
increaseAIDifficultyButton.x = 1248;
increaseAIDifficultyButton.y = 1560;
// Navigation Section (y: 1300+)
var backToMenuFromSettingsButton = new MenuButton('Menüye Dön', function () {
showMainMenu();
});
backToMenuFromSettingsButton.x = 1024;
backToMenuFromSettingsButton.y = 1800;
function showFriendFeedback(message, color) {
// Remove existing feedback
if (friendFeedbackText && friendFeedbackText.parent) {
game.removeChild(friendFeedbackText);
}
// Create new feedback text
friendFeedbackText = new Text2(message, {
size: 44,
fill: color
});
friendFeedbackText.anchor.set(0.5, 0.5);
friendFeedbackText.x = 1024;
friendFeedbackText.y = 600;
game.addChild(friendFeedbackText);
// Auto-hide after 3 seconds
LK.setTimeout(function () {
if (friendFeedbackText && friendFeedbackText.parent) {
game.removeChild(friendFeedbackText);
friendFeedbackText = null;
}
}, 3000);
}
function changeSoundVolume(change) {
storage.soundVolume = Math.max(0, Math.min(100, storage.soundVolume + change));
updateSettingsDisplay();
saveUserData();
}
function changeMusicVolume(change) {
storage.musicVolume = Math.max(0, Math.min(100, storage.musicVolume + change));
updateSettingsDisplay();
saveUserData();
}
function changeBoardTheme() {
var themes = ['klasik', 'azami'];
var currentIndex = themes.indexOf(storage.boardTheme);
if (currentIndex === -1) currentIndex = 0; // Default to klasik if not found
storage.boardTheme = themes[(currentIndex + 1) % themes.length];
updateSettingsDisplay();
saveUserData();
// Recreate board visual if in game to apply new theme
if (gameState === 'playing') {
createBoardVisual();
}
}
function changeAIDifficulty(change) {
storage.aiDifficulty = Math.max(1, Math.min(10, storage.aiDifficulty + change));
updateSettingsDisplay();
saveUserData();
}
function updateSettingsDisplay() {
soundVolumeText.setText('Ses Seviyesi: ' + storage.soundVolume + '%');
musicVolumeText.setText('Müzik Seviyesi: ' + storage.musicVolume + '%');
var themeNames = {
'klasik': 'Klasik',
'azami': 'Azami'
};
boardThemeText.setText('Tahta Teması: ' + (themeNames[storage.boardTheme] || 'Klasik'));
aiDifficultyText.setText('Yapay Zeka Zorluğu: ' + storage.aiDifficulty);
}
function countTotalPieces() {
var total = 0;
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 8; col++) {
if (board[row][col]) {
total++;
}
}
}
return total;
}
beyazpiyon. In-Game asset. 2d. High contrast. No shadows
beyaz satranç atı. In-Game asset. 2d. High contrast. No shadows
beyaz satranç kalesi. In-Game asset. 2d. High contrast. No shadows
white chess king. In-Game asset. 2d. High contrast. No shadows
beyaz satranç fili. In-Game asset. 2d. High contrast. No shadows
beyaz vezir. In-Game asset. 2d. High contrast. No shadows
siyah vezir. In-Game asset. 2d. High contrast. No shadows
siyah satranç kalesi. In-Game asset. 2d. High contrast. No shadows
siyah piyon. In-Game asset. 2d. High contrast. No shadows
siyah satranç atı. In-Game asset. 2d. High contrast. No shadows
siyah şah. In-Game asset. 2d. High contrast. No shadows
siyah satranç fili. In-Game asset. 2d. High contrast. No shadows. siyah satranç fili
satranç ile ilgili buton resmi. In-Game asset. 2d. High contrast. No shadows
gölgelendirmeli koyu yeşil buton. In-Game asset. 2d. High contrast. No shadows
en altla havalı kalın ve grafik çizim olarak italik bir yazıyla Chess Master yazan koyu renk temalı 3 adet ortada büyük şah sağda vezir ve solda fil olacak şekilde satranç taşları. In-Game asset. 2d. High contrast. No shadows