/**** * Classes ****/ // Board cell class var Cell = Container.expand(function () { var self = Container.call(this); // Board position self.row = 0; self.col = 0; self.mark = null; // Mark instance or null // Draw cell background var bg = self.attachAsset('cellBg', { width: cellSize, height: cellSize, color: 0x12e66b, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Draw border (simulate with a slightly smaller colored box) var border = self.attachAsset('cellBorder', { width: cellSize - 8, height: cellSize - 8, color: 0xed056b, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Place mark (X or O) self.placeMark = function (type) { if (self.mark) return; var m = new Mark(); m.setType(type); m.x = 0; m.y = 0; self.addChild(m); self.mark = m; }; // Remove mark (for reset) self.clearMark = function () { if (self.mark) { self.mark.destroy(); self.mark = null; } }; // Touch/click event self.down = function (x, y, obj) { if (gameOver || waitingBot) return; if (self.mark) return; if (isBotGame && currentPlayer !== playerMark) return; self.placeMark(currentPlayer); boardState[self.row][self.col] = currentPlayer; var win = checkWin(); if (win) { for (var i = 0; i < win.length; i++) { var cell = cells[win[i][0]][win[i][1]]; LK.effects.flashObject(cell, 0x8be34a, 800); } playerScore++; updateScoreTxt(); if (currentPlayer === 'X') { LK.showYouWin('Kazandın!'); } else { LK.showGameOver(); } gameOver = true; nextRound(); return; } if (isBoardFull()) { // If board is full and no win, it's a draw LK.effects.flashScreen(0xcccccc, 800); LK.showYouWin('Berabere!'); gameOver = true; nextRound(); return; } // Switch player currentPlayer = isBotGame ? botMark : currentPlayer === 'X' ? 'O' : 'X'; updateTurnText(); // If bot's turn, trigger bot move if (isBotGame && currentPlayer === botMark && !gameOver) { waitingBot = true; LK.setTimeout(botMove, 600); } }; return self; }); // No plugins needed for MVP // X or O mark class var Mark = Container.expand(function () { var self = Container.call(this); // type: 'X' or 'O' self.type = 'X'; // Set up asset for X or O self.setType = function (type) { self.type = type; self.removeChildren(); if (type === 'X') { // X: two crossing rectangles var bar1 = self.attachAsset('xBar1', { width: 120, height: 20, color: 0x3c0ef1, shape: 'box', anchorX: 0.5, anchorY: 0.5, rotation: Math.PI / 4 }); var bar2 = self.attachAsset('xBar2', { width: 120, height: 20, color: 0x7c620f, shape: 'box', anchorX: 0.5, anchorY: 0.5, rotation: -Math.PI / 4 }); } else { // O: ellipse var ellipse = self.attachAsset('oEllipse', { width: 110, height: 110, color: 0x5ece7b, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); // Inner white ellipse for "hollow" O var inner = self.attachAsset('oInner', { width: 60, height: 60, color: 0xab76dc, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xffffff }); /**** * Game Code ****/ // Board setup var boardSize = 3; var cellSize = 320; // 3x3 grid fits well in 2048x2732 var boardPixelSize = cellSize * boardSize; var boardOffsetX = (2048 - boardPixelSize) / 2; var boardOffsetY = Math.max(120, (2732 - boardPixelSize) / 2 + 100); // State var cells = []; var boardState = []; var currentPlayer = 'X'; var gameOver = false; // 3-round logic and bot var totalRounds = 3; var currentRound = 1; var playerScore = 0; var botScore = 0; var isBotGame = true; // always play against bot var playerMark = 'X'; var botMark = 'O'; var waitingBot = false; // Score display var scoreTxt = new Text2('Sen: 0 Bot: 0 Tur: 1/3', { size: 90, fill: 0x2D8CF0 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 30; // Bot level selector (always 'Çok Zor') var botLevelNames = ['Çok Zor']; var botLevel = 4; // 4 = perfect play (minimax) var botLevelTxt = new Text2('Bot: ' + botLevelNames[0], { size: 70, fill: 0x1A6B2B }); botLevelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(botLevelTxt); botLevelTxt.y = 110; // Bot zorluğu sabit, değiştirilemez botLevelTxt.setText('Bot: ' + botLevelNames[0]); botLevelTxt.interactive = false; botLevelTxt.buttonMode = false; botLevelTxt.down = function (x, y, obj) { // Seviye değiştirilemez }; // Helper: update score and round display function updateScoreTxt() { scoreTxt.setText('Sen: ' + playerScore + ' Bot: ' + botScore + ' Tur: ' + currentRound + '/3'); } // Turn display var turnTxt = new Text2('Sıra: X', { size: 80, fill: 0x444444 }); turnTxt.anchor.set(0.5, 0); LK.gui.top.addChild(turnTxt); turnTxt.y = 170; // Helper: update turn text function updateTurnText() { if (isBotGame && currentPlayer === botMark) { turnTxt.setText('Bot düşünüyor...'); } else { turnTxt.setText('Sıra: ' + currentPlayer); } } // Helper: check for win function checkWin() { // Returns array of [row,col] for winning cells, or null var b = boardState; // Rows for (var r = 0; r < 3; r++) { if (b[r][0] && b[r][0] === b[r][1] && b[r][1] === b[r][2]) { return [[r, 0], [r, 1], [r, 2]]; } } // Cols for (var c = 0; c < 3; c++) { if (b[0][c] && b[0][c] === b[1][c] && b[1][c] === b[2][c]) { return [[0, c], [1, c], [2, c]]; } } // Diagonals if (b[0][0] && b[0][0] === b[1][1] && b[1][1] === b[2][2]) { return [[0, 0], [1, 1], [2, 2]]; } if (b[0][2] && b[0][2] === b[1][1] && b[1][1] === b[2][0]) { return [[0, 2], [1, 1], [2, 0]]; } return null; } // Helper: check for draw function isBoardFull() { for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { if (!boardState[r][c]) return false; } } return true; } // Helper: reset board function resetBoard() { for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { cells[r][c].clearMark(); boardState[r][c] = null; } } // Alternate who starts each round if (isBotGame) { if (currentRound % 2 === 1) { playerMark = 'X'; botMark = 'O'; currentPlayer = 'X'; } else { playerMark = 'O'; botMark = 'X'; currentPlayer = 'X'; } } else { currentPlayer = 'X'; } gameOver = false; waitingBot = false; updateTurnText(); updateScoreTxt(); // If bot starts, trigger bot move if (isBotGame && currentPlayer === botMark) { waitingBot = true; LK.setTimeout(botMove, 600); } } // Bot difficulty: 1 = easy, 2 = normal, 3 = hard, 4 = very hard, 5 = perfect var botLevel = 1; // Change this to set bot difficulty (1-5) // Use selected botLevel from UI function getBotLevel() { return 4; } // Minimax for perfect play (level 5) function minimax(board, depth, isMax, mark, oppMark) { var win = null; // Check for win for (var r = 0; r < 3; r++) { if (board[r][0] && board[r][0] === board[r][1] && board[r][1] === board[r][2]) win = board[r][0]; } for (var c = 0; c < 3; c++) { if (board[0][c] && board[0][c] === board[1][c] && board[1][c] === board[2][c]) win = board[0][c]; } if (board[0][0] && board[0][0] === board[1][1] && board[1][1] === board[2][2]) win = board[0][0]; if (board[0][2] && board[0][2] === board[1][1] && board[1][1] === board[2][0]) win = board[0][2]; if (win === mark) return 10 - depth; if (win === oppMark) return depth - 10; var full = true; for (var r = 0; r < 3; r++) for (var c = 0; c < 3; c++) if (!board[r][c]) full = false; if (full) return 0; var best = isMax ? -Infinity : Infinity; for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { if (!board[r][c]) { board[r][c] = isMax ? mark : oppMark; var score = minimax(board, depth + 1, !isMax, mark, oppMark); board[r][c] = null; if (isMax) { if (score > best) best = score; } else { if (score < best) best = score; } } } } return best; } // Find best move for minimax function findBestMove(board, mark, oppMark) { var bestScore = -Infinity; var move = null; for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { if (!board[r][c]) { board[r][c] = mark; var score = minimax(board, 0, false, mark, oppMark); board[r][c] = null; if (score > bestScore) { bestScore = score; move = [r, c]; } } } } return move; } // Try to win or block (level 3+) function findWinOrBlock(board, mark) { // Try to win for (var r = 0; r < 3; r++) for (var c = 0; c < 3; c++) { if (!board[r][c]) { board[r][c] = mark; var win = false; // Check win for (var i = 0; i < 3; i++) { if (board[i][0] && board[i][0] === board[i][1] && board[i][1] === board[i][2] && board[i][0] === mark) win = true; if (board[0][i] && board[0][i] === board[1][i] && board[1][i] === board[2][i] && board[0][i] === mark) win = true; } if (board[0][0] && board[0][0] === board[1][1] && board[1][1] === board[2][2] && board[0][0] === mark) win = true; if (board[0][2] && board[0][2] === board[1][1] && board[1][1] === board[2][0] && board[0][2] === mark) win = true; board[r][c] = null; if (win) return [r, c]; } } return null; } function botMove() { if (!isBotGame || gameOver) { waitingBot = false; return; } var level = getBotLevel(); // Find all empty cells var empty = []; for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { if (!boardState[r][c]) empty.push([r, c]); } } if (empty.length === 0) { waitingBot = false; return; } var rc = null; if (level === 1) { // Easy: random var idx = Math.floor(Math.random() * empty.length); rc = empty[idx]; } else if (level === 2) { // Normal: 60% random, 40% block/win if (Math.random() < 0.4) { rc = findWinOrBlock(boardState, botMark); if (!rc) rc = findWinOrBlock(boardState, playerMark); if (!rc) { var idx = Math.floor(Math.random() * empty.length); rc = empty[idx]; } } else { var idx = Math.floor(Math.random() * empty.length); rc = empty[idx]; } } else if (level === 3) { // Hard: always block/win if possible, else random rc = findWinOrBlock(boardState, botMark); if (!rc) rc = findWinOrBlock(boardState, playerMark); if (!rc) { var idx = Math.floor(Math.random() * empty.length); rc = empty[idx]; } } else { // Level 4+: perfect play (minimax) rc = findBestMove(boardState, botMark, playerMark); if (!rc) { var idx = Math.floor(Math.random() * empty.length); rc = empty[idx]; } } var cell = cells[rc[0]][rc[1]]; // Place mark as bot cell.placeMark(botMark); boardState[rc[0]][rc[1]] = botMark; var win = checkWin(); if (win) { for (var i = 0; i < win.length; i++) { var wcell = cells[win[i][0]][win[i][1]]; LK.effects.flashObject(wcell, 0x8be34a, 800); } botScore++; updateScoreTxt(); LK.showGameOver(); gameOver = true; nextRound(); waitingBot = false; return; } if (isBoardFull()) { // If board is full and no win, it's a draw LK.effects.flashScreen(0xcccccc, 800); LK.showYouWin('Berabere!'); gameOver = true; nextRound(); waitingBot = false; return; } // Switch to player currentPlayer = playerMark; updateTurnText(); waitingBot = false; } // Build board for (var r = 0; r < 3; r++) { cells[r] = []; boardState[r] = []; for (var c = 0; c < 3; c++) { var cell = new Cell(); cell.row = r; cell.col = c; cell.x = boardOffsetX + c * cellSize + cellSize / 2; cell.y = boardOffsetY + r * cellSize + cellSize / 2; game.addChild(cell); cells[r][c] = cell; boardState[r][c] = null; } } // Reset board on game start or after game over resetBoard(); // Next round logic function nextRound() { LK.setTimeout(function () { currentRound++; if (currentRound > totalRounds) { // Show final winner var msg = ''; if (playerScore > botScore) msg = 'Kazandın! 🎉';else if (playerScore < botScore) msg = 'Bot kazandı!';else msg = 'Berabere!'; LK.effects.flashScreen(0x00ffcc, 800); LK.showYouWin(msg); // Reset all for new match currentRound = 1; playerScore = 0; botScore = 0; } resetBoard(); }, 1200); } // Optional: reset board after win/game over (handled by LK, but for MVP, reset on new game) game.on('reset', function () { currentRound = 1; playerScore = 0; botScore = 0; resetBoard(); updateScoreTxt(); LK.setScore(0); }); // No dragging or move events needed for this game // No update loop needed for static board game
/****
* Classes
****/
// Board cell class
var Cell = Container.expand(function () {
var self = Container.call(this);
// Board position
self.row = 0;
self.col = 0;
self.mark = null; // Mark instance or null
// Draw cell background
var bg = self.attachAsset('cellBg', {
width: cellSize,
height: cellSize,
color: 0x12e66b,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Draw border (simulate with a slightly smaller colored box)
var border = self.attachAsset('cellBorder', {
width: cellSize - 8,
height: cellSize - 8,
color: 0xed056b,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Place mark (X or O)
self.placeMark = function (type) {
if (self.mark) return;
var m = new Mark();
m.setType(type);
m.x = 0;
m.y = 0;
self.addChild(m);
self.mark = m;
};
// Remove mark (for reset)
self.clearMark = function () {
if (self.mark) {
self.mark.destroy();
self.mark = null;
}
};
// Touch/click event
self.down = function (x, y, obj) {
if (gameOver || waitingBot) return;
if (self.mark) return;
if (isBotGame && currentPlayer !== playerMark) return;
self.placeMark(currentPlayer);
boardState[self.row][self.col] = currentPlayer;
var win = checkWin();
if (win) {
for (var i = 0; i < win.length; i++) {
var cell = cells[win[i][0]][win[i][1]];
LK.effects.flashObject(cell, 0x8be34a, 800);
}
playerScore++;
updateScoreTxt();
if (currentPlayer === 'X') {
LK.showYouWin('Kazandın!');
} else {
LK.showGameOver();
}
gameOver = true;
nextRound();
return;
}
if (isBoardFull()) {
// If board is full and no win, it's a draw
LK.effects.flashScreen(0xcccccc, 800);
LK.showYouWin('Berabere!');
gameOver = true;
nextRound();
return;
}
// Switch player
currentPlayer = isBotGame ? botMark : currentPlayer === 'X' ? 'O' : 'X';
updateTurnText();
// If bot's turn, trigger bot move
if (isBotGame && currentPlayer === botMark && !gameOver) {
waitingBot = true;
LK.setTimeout(botMove, 600);
}
};
return self;
});
// No plugins needed for MVP
// X or O mark class
var Mark = Container.expand(function () {
var self = Container.call(this);
// type: 'X' or 'O'
self.type = 'X';
// Set up asset for X or O
self.setType = function (type) {
self.type = type;
self.removeChildren();
if (type === 'X') {
// X: two crossing rectangles
var bar1 = self.attachAsset('xBar1', {
width: 120,
height: 20,
color: 0x3c0ef1,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 4
});
var bar2 = self.attachAsset('xBar2', {
width: 120,
height: 20,
color: 0x7c620f,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
rotation: -Math.PI / 4
});
} else {
// O: ellipse
var ellipse = self.attachAsset('oEllipse', {
width: 110,
height: 110,
color: 0x5ece7b,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Inner white ellipse for "hollow" O
var inner = self.attachAsset('oInner', {
width: 60,
height: 60,
color: 0xab76dc,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffffff
});
/****
* Game Code
****/
// Board setup
var boardSize = 3;
var cellSize = 320; // 3x3 grid fits well in 2048x2732
var boardPixelSize = cellSize * boardSize;
var boardOffsetX = (2048 - boardPixelSize) / 2;
var boardOffsetY = Math.max(120, (2732 - boardPixelSize) / 2 + 100);
// State
var cells = [];
var boardState = [];
var currentPlayer = 'X';
var gameOver = false;
// 3-round logic and bot
var totalRounds = 3;
var currentRound = 1;
var playerScore = 0;
var botScore = 0;
var isBotGame = true; // always play against bot
var playerMark = 'X';
var botMark = 'O';
var waitingBot = false;
// Score display
var scoreTxt = new Text2('Sen: 0 Bot: 0 Tur: 1/3', {
size: 90,
fill: 0x2D8CF0
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 30;
// Bot level selector (always 'Çok Zor')
var botLevelNames = ['Çok Zor'];
var botLevel = 4; // 4 = perfect play (minimax)
var botLevelTxt = new Text2('Bot: ' + botLevelNames[0], {
size: 70,
fill: 0x1A6B2B
});
botLevelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(botLevelTxt);
botLevelTxt.y = 110;
// Bot zorluğu sabit, değiştirilemez
botLevelTxt.setText('Bot: ' + botLevelNames[0]);
botLevelTxt.interactive = false;
botLevelTxt.buttonMode = false;
botLevelTxt.down = function (x, y, obj) {
// Seviye değiştirilemez
};
// Helper: update score and round display
function updateScoreTxt() {
scoreTxt.setText('Sen: ' + playerScore + ' Bot: ' + botScore + ' Tur: ' + currentRound + '/3');
}
// Turn display
var turnTxt = new Text2('Sıra: X', {
size: 80,
fill: 0x444444
});
turnTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(turnTxt);
turnTxt.y = 170;
// Helper: update turn text
function updateTurnText() {
if (isBotGame && currentPlayer === botMark) {
turnTxt.setText('Bot düşünüyor...');
} else {
turnTxt.setText('Sıra: ' + currentPlayer);
}
}
// Helper: check for win
function checkWin() {
// Returns array of [row,col] for winning cells, or null
var b = boardState;
// Rows
for (var r = 0; r < 3; r++) {
if (b[r][0] && b[r][0] === b[r][1] && b[r][1] === b[r][2]) {
return [[r, 0], [r, 1], [r, 2]];
}
}
// Cols
for (var c = 0; c < 3; c++) {
if (b[0][c] && b[0][c] === b[1][c] && b[1][c] === b[2][c]) {
return [[0, c], [1, c], [2, c]];
}
}
// Diagonals
if (b[0][0] && b[0][0] === b[1][1] && b[1][1] === b[2][2]) {
return [[0, 0], [1, 1], [2, 2]];
}
if (b[0][2] && b[0][2] === b[1][1] && b[1][1] === b[2][0]) {
return [[0, 2], [1, 1], [2, 0]];
}
return null;
}
// Helper: check for draw
function isBoardFull() {
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (!boardState[r][c]) return false;
}
}
return true;
}
// Helper: reset board
function resetBoard() {
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
cells[r][c].clearMark();
boardState[r][c] = null;
}
}
// Alternate who starts each round
if (isBotGame) {
if (currentRound % 2 === 1) {
playerMark = 'X';
botMark = 'O';
currentPlayer = 'X';
} else {
playerMark = 'O';
botMark = 'X';
currentPlayer = 'X';
}
} else {
currentPlayer = 'X';
}
gameOver = false;
waitingBot = false;
updateTurnText();
updateScoreTxt();
// If bot starts, trigger bot move
if (isBotGame && currentPlayer === botMark) {
waitingBot = true;
LK.setTimeout(botMove, 600);
}
}
// Bot difficulty: 1 = easy, 2 = normal, 3 = hard, 4 = very hard, 5 = perfect
var botLevel = 1; // Change this to set bot difficulty (1-5)
// Use selected botLevel from UI
function getBotLevel() {
return 4;
}
// Minimax for perfect play (level 5)
function minimax(board, depth, isMax, mark, oppMark) {
var win = null;
// Check for win
for (var r = 0; r < 3; r++) {
if (board[r][0] && board[r][0] === board[r][1] && board[r][1] === board[r][2]) win = board[r][0];
}
for (var c = 0; c < 3; c++) {
if (board[0][c] && board[0][c] === board[1][c] && board[1][c] === board[2][c]) win = board[0][c];
}
if (board[0][0] && board[0][0] === board[1][1] && board[1][1] === board[2][2]) win = board[0][0];
if (board[0][2] && board[0][2] === board[1][1] && board[1][1] === board[2][0]) win = board[0][2];
if (win === mark) return 10 - depth;
if (win === oppMark) return depth - 10;
var full = true;
for (var r = 0; r < 3; r++) for (var c = 0; c < 3; c++) if (!board[r][c]) full = false;
if (full) return 0;
var best = isMax ? -Infinity : Infinity;
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (!board[r][c]) {
board[r][c] = isMax ? mark : oppMark;
var score = minimax(board, depth + 1, !isMax, mark, oppMark);
board[r][c] = null;
if (isMax) {
if (score > best) best = score;
} else {
if (score < best) best = score;
}
}
}
}
return best;
}
// Find best move for minimax
function findBestMove(board, mark, oppMark) {
var bestScore = -Infinity;
var move = null;
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (!board[r][c]) {
board[r][c] = mark;
var score = minimax(board, 0, false, mark, oppMark);
board[r][c] = null;
if (score > bestScore) {
bestScore = score;
move = [r, c];
}
}
}
}
return move;
}
// Try to win or block (level 3+)
function findWinOrBlock(board, mark) {
// Try to win
for (var r = 0; r < 3; r++) for (var c = 0; c < 3; c++) {
if (!board[r][c]) {
board[r][c] = mark;
var win = false;
// Check win
for (var i = 0; i < 3; i++) {
if (board[i][0] && board[i][0] === board[i][1] && board[i][1] === board[i][2] && board[i][0] === mark) win = true;
if (board[0][i] && board[0][i] === board[1][i] && board[1][i] === board[2][i] && board[0][i] === mark) win = true;
}
if (board[0][0] && board[0][0] === board[1][1] && board[1][1] === board[2][2] && board[0][0] === mark) win = true;
if (board[0][2] && board[0][2] === board[1][1] && board[1][1] === board[2][0] && board[0][2] === mark) win = true;
board[r][c] = null;
if (win) return [r, c];
}
}
return null;
}
function botMove() {
if (!isBotGame || gameOver) {
waitingBot = false;
return;
}
var level = getBotLevel();
// Find all empty cells
var empty = [];
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (!boardState[r][c]) empty.push([r, c]);
}
}
if (empty.length === 0) {
waitingBot = false;
return;
}
var rc = null;
if (level === 1) {
// Easy: random
var idx = Math.floor(Math.random() * empty.length);
rc = empty[idx];
} else if (level === 2) {
// Normal: 60% random, 40% block/win
if (Math.random() < 0.4) {
rc = findWinOrBlock(boardState, botMark);
if (!rc) rc = findWinOrBlock(boardState, playerMark);
if (!rc) {
var idx = Math.floor(Math.random() * empty.length);
rc = empty[idx];
}
} else {
var idx = Math.floor(Math.random() * empty.length);
rc = empty[idx];
}
} else if (level === 3) {
// Hard: always block/win if possible, else random
rc = findWinOrBlock(boardState, botMark);
if (!rc) rc = findWinOrBlock(boardState, playerMark);
if (!rc) {
var idx = Math.floor(Math.random() * empty.length);
rc = empty[idx];
}
} else {
// Level 4+: perfect play (minimax)
rc = findBestMove(boardState, botMark, playerMark);
if (!rc) {
var idx = Math.floor(Math.random() * empty.length);
rc = empty[idx];
}
}
var cell = cells[rc[0]][rc[1]];
// Place mark as bot
cell.placeMark(botMark);
boardState[rc[0]][rc[1]] = botMark;
var win = checkWin();
if (win) {
for (var i = 0; i < win.length; i++) {
var wcell = cells[win[i][0]][win[i][1]];
LK.effects.flashObject(wcell, 0x8be34a, 800);
}
botScore++;
updateScoreTxt();
LK.showGameOver();
gameOver = true;
nextRound();
waitingBot = false;
return;
}
if (isBoardFull()) {
// If board is full and no win, it's a draw
LK.effects.flashScreen(0xcccccc, 800);
LK.showYouWin('Berabere!');
gameOver = true;
nextRound();
waitingBot = false;
return;
}
// Switch to player
currentPlayer = playerMark;
updateTurnText();
waitingBot = false;
}
// Build board
for (var r = 0; r < 3; r++) {
cells[r] = [];
boardState[r] = [];
for (var c = 0; c < 3; c++) {
var cell = new Cell();
cell.row = r;
cell.col = c;
cell.x = boardOffsetX + c * cellSize + cellSize / 2;
cell.y = boardOffsetY + r * cellSize + cellSize / 2;
game.addChild(cell);
cells[r][c] = cell;
boardState[r][c] = null;
}
}
// Reset board on game start or after game over
resetBoard();
// Next round logic
function nextRound() {
LK.setTimeout(function () {
currentRound++;
if (currentRound > totalRounds) {
// Show final winner
var msg = '';
if (playerScore > botScore) msg = 'Kazandın! 🎉';else if (playerScore < botScore) msg = 'Bot kazandı!';else msg = 'Berabere!';
LK.effects.flashScreen(0x00ffcc, 800);
LK.showYouWin(msg);
// Reset all for new match
currentRound = 1;
playerScore = 0;
botScore = 0;
}
resetBoard();
}, 1200);
}
// Optional: reset board after win/game over (handled by LK, but for MVP, reset on new game)
game.on('reset', function () {
currentRound = 1;
playerScore = 0;
botScore = 0;
resetBoard();
updateScoreTxt();
LK.setScore(0);
});
// No dragging or move events needed for this game
// No update loop needed for static board game