User prompt
malumlar arası duvar koydun evet birbirlerine girmiyorlar ama bu sefer de düğmelere biz tıklayamıyoruz
User prompt
Yeni bir menüye geçtiğimizde daha önceki menülerin etkileşimini kapat, çünkü menüler arası hata oluşuyor.
User prompt
Oyun ekranı başlamadan birşey koymak yasak olsun çünkü bazen iki tane beraber koyabiliyoruz
User prompt
Bazen Yapay Zeka Kendi Sırasını Kullanmıyor
User prompt
Normal mod bazı engellemeleri öğrenir mesela çatal taktiği gibi
User prompt
Normal seviyede yapay zeka kendi kazanma fırsatını ve oyuncunun doğrudan tehditlerini engellemeyi öğrenir. Basit kullanmaya başlar, oyuncuyu biraz meydan okur ama yine de kazanmasına şans verir.
User prompt
Kolay seviye genellikle oyuncunun kazanmasını hedefleyen bir kolay moddur.
User prompt
Kolay seviyede yapay zeka genellikle rastgele hamleler yapar. Kendi kazanmasının şansını veya diğer oyuncunun amacını hiç umursamaz rastgele hamleler yapar.
User prompt
Oyunu hiç bozmadan gereksiz kodları sil.
User prompt
Oyunu hiç bozmadan, dokunmadan hataları düzelt.
User prompt
Bu modumu seçmek istiyorsun diye uyarı veren yerde Evet veya Hayır'a tıklayınca tepki vermiyor.
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'yesBtn.down = function (x, y, obj) {' Line Number: 397
User prompt
Bir Zorluk Modu Seçince Bu Zorluk Modunu Mu Seçmek İstiyorsun Diye Uyarsın
User prompt
kolay, normal ve zor düğmelerin altında blok olsun renk yanıyor
User prompt
Oyun oynarken bazı yerlere tıklayınca algılamıyor, bir boşluğa tıklayınca hepsini algılasın. Hataları düzelt.
User prompt
kolay, normal ve zor modlar arasında boşluklar olsun yoksa yanlışla yanlış modu seçebiliyoruz
User prompt
Yapay zeka modunda bazı yerleri kendimiz koyamıyoruz.
User prompt
yapay zeka modunu seçince kolay, normal ve zor modlar olsun
User prompt
Yapay ZK'ya daha çok taktik öğret.
User prompt
Algılama sistemini ve hataları düzelt.
User prompt
Yapay Zeka Hep Aynı Hareketleri Yapmasın Aynı Stratejileri Yapmasın Farklı Farklı
User prompt
Yapay zeka, bizim tıkladığımız yere göre hep belirli yerlere tıklıyor. Farklı yerlere ama mantıklı, saçma yerlere dokunmadan düzgün bir oyun oynasın. Bizim tıkladığımız yere göre belirli yerlere dokunmadan.
User prompt
Bazən bizim tıxladığımız yerə yapay zeka qoyuyor. O yüzden bizim tıxladığımız yerlə yapay zekanın tıxladığı yeri algıla və doğru konumlandır.
User prompt
Bazen oyundaki düğmeler çalışmıyor.
User prompt
Oyun oynarken arada küçük donmalar kesilmeler oluyor.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Cell = Container.expand(function (row, col) { var self = Container.call(this); self.row = row; self.col = col; self.value = 0; // 0 = empty, 1 = X (blue), 2 = O (red) var cellBg = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.1 }); self.marker = null; self.placeMarker = function (type) { if (self.value !== 0) return false; self.value = type; if (type === 1) { // Blue X self.marker = self.attachAsset('xMarker', { anchorX: 0.5, anchorY: 0.5, alpha: 0, scaleX: 0.1, scaleY: 0.1 }); tween(self.marker, { alpha: 0.9, scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut }); } else { // Red O self.marker = self.attachAsset('oMarker', { anchorX: 0.5, anchorY: 0.5, alpha: 0, scaleX: 0.1, scaleY: 0.1 }); tween(self.marker, { alpha: 0.9, scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut }); } LK.getSound('place').play(); return true; }; self.down = function (x, y, obj) { if (!gameReady || gameOver || self.value !== 0 || gameMode === 'menu') return; // In AI mode, only allow player clicks during player's turn (currentPlayer === 1) if (isAIMode && currentPlayer !== 1) return; // Prevent rapid clicking by adding a small delay check if (self.lastClickTime && Date.now() - self.lastClickTime < 100) return; self.lastClickTime = Date.now(); // Clear any existing reservations from other cells first clearAllReservations(); // Mark this cell as reserved for player to prevent AI interference self.isPlayerReserved = true; // Add timeout to clear reservation automatically LK.setTimeout(function () { if (self.isPlayerReserved) { self.isPlayerReserved = false; } }, 200); if (self.placeMarker(currentPlayer)) { // Clear reservation after successful placement self.isPlayerReserved = false; checkWin(); if (!gameOver) { if (isAIMode && currentPlayer === 1) { // AI mode - player played, now AI plays currentPlayer = 2; updateTurnDisplay(); makeAIMove(); } else if (isAIMode && currentPlayer === 2) { // This shouldn't happen in AI mode since AI doesn't click currentPlayer = 1; updateTurnDisplay(); } else { // Two player mode - switch players normally currentPlayer = currentPlayer === 1 ? 2 : 1; updateTurnDisplay(); } } } else { // Clear reservation if placement failed self.isPlayerReserved = false; } }; return self; }); var WinLine = Container.expand(function () { var self = Container.call(this); self.line = self.attachAsset('winLine', { anchorX: 0.5, anchorY: 0.5, alpha: 0, scaleX: 0 }); self.showWinLine = function (startX, startY, endX, endY, color) { var deltaX = endX - startX; var deltaY = endY - startY; var angle = Math.atan2(deltaY, deltaX); var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); self.x = startX + deltaX / 2; self.y = startY + deltaY / 2; self.line.rotation = angle; self.line.tint = color; self.line.width = distance; tween(self.line, { alpha: 1, scaleX: 1 }, { duration: 500, easing: tween.easeOut }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ var grid = []; var currentPlayer = 1; // 1 = Blue X, 2 = Red O var gameOver = false; var winLine = null; var gameMode = 'menu'; // 'menu', 'ai', 'twoPlayer' var isAIMode = false; var currentLanguage = storage.language || 'tr'; // 'tr' for Turkish, 'en' for English var languageTexts = { tr: { blueTurn: 'Sıra: Mavinin', redTurn: 'Sıra: Kırmızının', blueWin: 'MAVİ TAKIM KAZANDI!', redWin: 'KIRMIZI TAKIM KAZANDI!', draw: 'BERABERE!', playAgain: 'Tekrar Oyna', language: 'Türkçe', vsAI: 'Yapay Zeka ile Oyna', twoPlayer: 'İki Kişilik Oyna', selectMode: 'Oyun Modunu Seçin', back: '← Geri', exit: 'Çıkış' }, en: { blueTurn: 'Turn: Blue', redTurn: 'Turn: Red', blueWin: 'BLUE TEAM WON!', redWin: 'RED TEAM WON!', draw: 'DRAW!', playAgain: 'Play Again', language: 'English', vsAI: 'Play vs AI', twoPlayer: 'Two Player', selectMode: 'Select Game Mode', back: '← Back', exit: 'Exit' } }; // Game setup var gameBoard = game.addChild(new Container()); gameBoard.x = 2048 / 2; gameBoard.y = 2732 / 2; gameBoard.scaleX = 1.2; gameBoard.scaleY = 1.2; gameBoard.alpha = 0; // Hidden initially // Create background var background = gameBoard.attachAsset('gridBackground', { anchorX: 0.5, anchorY: 0.5 }); // Create grid lines var verticalLine1 = gameBoard.attachAsset('gridLine', { anchorX: 0.5, anchorY: 0.5, x: -300, height: 1800 }); var verticalLine2 = gameBoard.attachAsset('gridLine', { anchorX: 0.5, anchorY: 0.5, x: 300, height: 1800 }); var horizontalLine1 = gameBoard.attachAsset('gridLine', { anchorX: 0.5, anchorY: 0.5, y: -300, width: 1800, height: 8 }); var horizontalLine2 = gameBoard.attachAsset('gridLine', { anchorX: 0.5, anchorY: 0.5, y: 300, width: 1800, height: 8 }); // Create cells for (var row = 0; row < 3; row++) { grid[row] = []; for (var col = 0; col < 3; col++) { var cell = gameBoard.addChild(new Cell(row, col)); cell.x = (col - 1) * 600; cell.y = (row - 1) * 600; grid[row][col] = cell; } } // UI Elements var blueTurnText = new Text2(languageTexts[currentLanguage].blueTurn, { size: 120, fill: 0x00AAFF }); blueTurnText.anchor.set(0.5, 0); LK.gui.top.addChild(blueTurnText); blueTurnText.y = 150; var redTurnText = new Text2(languageTexts[currentLanguage].redTurn, { size: 120, fill: 0xff0000 }); redTurnText.anchor.set(0.5, 0); LK.gui.top.addChild(redTurnText); redTurnText.y = 150; var languageBtn = new Text2(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language, { size: 60, fill: 0xFFFFFF }); languageBtn.anchor.set(0.5, 0); LK.gui.top.addChild(languageBtn); languageBtn.y = 80; var statusText = new Text2('', { size: 100, fill: 0xFFFFFF }); statusText.anchor.set(0.5, 0.5); LK.gui.center.addChild(statusText); statusText.y = 400; var playAgainBtn = new Text2(languageTexts[currentLanguage].playAgain, { size: 80, fill: 0xFFFFFF }); playAgainBtn.anchor.set(0.5, 0.5); LK.gui.center.addChild(playAgainBtn); playAgainBtn.y = 550; playAgainBtn.alpha = 0; // Menu UI elements var menuTitle = new Text2(languageTexts[currentLanguage].selectMode, { size: 120, fill: 0xFFFFFF }); menuTitle.anchor.set(0.5, 0.5); LK.gui.center.addChild(menuTitle); menuTitle.y = -200; var vsAIBtn = new Text2(languageTexts[currentLanguage].vsAI, { size: 100, fill: 0x00AAFF }); vsAIBtn.anchor.set(0.5, 0.5); LK.gui.center.addChild(vsAIBtn); vsAIBtn.y = 0; var twoPlayerBtn = new Text2(languageTexts[currentLanguage].twoPlayer, { size: 100, fill: 0xFF4444 }); twoPlayerBtn.anchor.set(0.5, 0.5); LK.gui.center.addChild(twoPlayerBtn); twoPlayerBtn.y = 150; var backBtn = new Text2(languageTexts[currentLanguage].back, { size: 80, fill: 0xFFFFFF }); backBtn.anchor.set(0.5, 0.5); LK.gui.center.addChild(backBtn); backBtn.x = -800; backBtn.y = -300; backBtn.alpha = 0; var exitBtn = new Text2(languageTexts[currentLanguage].exit, { size: 80, fill: 0xFF0000 }); exitBtn.anchor.set(0.5, 0); LK.gui.top.addChild(exitBtn); exitBtn.y = 80; exitBtn.x = 450; exitBtn.alpha = 0; // Language toggle functionality languageBtn.down = function (x, y, obj) { // Always allow language switching regardless of game state currentLanguage = currentLanguage === 'tr' ? 'en' : 'tr'; storage.language = currentLanguage; updateLanguageTexts(); }; // Menu button handlers vsAIBtn.down = function (x, y, obj) { if (gameMode === 'menu') { startGame('ai'); } }; twoPlayerBtn.down = function (x, y, obj) { if (gameMode === 'menu') { startGame('twoPlayer'); } }; backBtn.down = function (x, y, obj) { if (gameMode !== 'menu') { resetGame(); showMenu(); } }; exitBtn.down = function (x, y, obj) { if (gameMode !== 'menu') { resetGame(); showMenu(); } }; function updateLanguageTexts() { blueTurnText.setText(languageTexts[currentLanguage].blueTurn); redTurnText.setText(languageTexts[currentLanguage].redTurn); playAgainBtn.setText(languageTexts[currentLanguage].playAgain); languageBtn.setText(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language); menuTitle.setText(languageTexts[currentLanguage].selectMode); vsAIBtn.setText(languageTexts[currentLanguage].vsAI); twoPlayerBtn.setText(languageTexts[currentLanguage].twoPlayer); backBtn.setText(languageTexts[currentLanguage].back); exitBtn.setText(languageTexts[currentLanguage].exit); } // Start in menu mode showMenu(); function updateTurnDisplay() { if (gameMode === 'menu' || gameOver) { blueTurnText.alpha = 0; redTurnText.alpha = 0; } else if (currentPlayer === 1) { blueTurnText.alpha = 1; redTurnText.alpha = 0; } else { blueTurnText.alpha = 0; redTurnText.alpha = 1; } } function showMenu() { gameMode = 'menu'; gameBoard.alpha = 0; menuTitle.alpha = 1; vsAIBtn.alpha = 1; twoPlayerBtn.alpha = 1; blueTurnText.alpha = 0; redTurnText.alpha = 0; statusText.alpha = 0; playAgainBtn.alpha = 0; backBtn.alpha = 0; exitBtn.alpha = 0; } function startGame(mode) { gameMode = mode; isAIMode = mode === 'ai'; gameBoard.alpha = 1; menuTitle.alpha = 0; vsAIBtn.alpha = 0; twoPlayerBtn.alpha = 0; backBtn.alpha = 1; exitBtn.alpha = 1; // In AI mode, player (1) always starts first if (isAIMode) { currentPlayer = 1; } else { // In two player mode, random start currentPlayer = Math.random() < 0.5 ? 1 : 2; } updateTurnDisplay(); } function checkWin() { var winner = 0; var winPositions = []; // Check rows for (var row = 0; row < 3; row++) { if (grid[row][0].value !== 0 && grid[row][0].value === grid[row][1].value && grid[row][1].value === grid[row][2].value) { winner = grid[row][0].value; winPositions = [{ row: row, col: 0 }, { row: row, col: 1 }, { row: row, col: 2 }]; break; } } // Check columns if (winner === 0) { for (var col = 0; col < 3; col++) { if (grid[0][col].value !== 0 && grid[0][col].value === grid[1][col].value && grid[1][col].value === grid[2][col].value) { winner = grid[0][col].value; winPositions = [{ row: 0, col: col }, { row: 1, col: col }, { row: 2, col: col }]; break; } } } // Check diagonals if (winner === 0) { if (grid[0][0].value !== 0 && grid[0][0].value === grid[1][1].value && grid[1][1].value === grid[2][2].value) { winner = grid[0][0].value; winPositions = [{ row: 0, col: 0 }, { row: 1, col: 1 }, { row: 2, col: 2 }]; } else if (grid[0][2].value !== 0 && grid[0][2].value === grid[1][1].value && grid[1][1].value === grid[2][0].value) { winner = grid[0][2].value; winPositions = [{ row: 0, col: 2 }, { row: 1, col: 1 }, { row: 2, col: 0 }]; } } if (winner !== 0) { gameOver = true; showWinner(winner, winPositions); return; } // Check for draw var isDraw = true; for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { if (grid[r][c].value === 0) { isDraw = false; break; } } if (!isDraw) break; } if (isDraw) { gameOver = true; showDraw(); } } function showWinner(winner, positions) { LK.getSound('win').play(); var winnerText = winner === 1 ? languageTexts[currentLanguage].blueWin : languageTexts[currentLanguage].redWin; var winnerColor = 0x000000; // Black color statusText.setText(winnerText); statusText.fill = winnerColor; statusText.alpha = 1; blueTurnText.alpha = 0; redTurnText.alpha = 0; // Show win line winLine = gameBoard.addChild(new WinLine()); var startPos = grid[positions[0].row][positions[0].col]; var endPos = grid[positions[2].row][positions[2].col]; var lineColor = winner === 1 ? 0x00aaff : 0xff4444; winLine.showWinLine(startPos.x, startPos.y, endPos.x, endPos.y, lineColor); // Show play again button tween(playAgainBtn, { alpha: 1 }, { duration: 500 }); } function showDraw() { statusText.setText(languageTexts[currentLanguage].draw); statusText.fill = 0x000000; // Black color statusText.alpha = 1; blueTurnText.alpha = 0; redTurnText.alpha = 0; // Show play again button tween(playAgainBtn, { alpha: 1 }, { duration: 500 }); } function clearAllReservations() { for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (grid[row][col].isPlayerReserved) { grid[row][col].isPlayerReserved = false; } } } } function makeAIMove() { if (gameOver || currentPlayer !== 2) return; // Variable thinking time to make AI feel more natural and less predictable var thinkingTime = 200 + Math.floor(Math.random() * 800); // 200-1000ms random delay // Use setTimeout to yield frame and prevent blocking LK.setTimeout(function () { // Recheck game state after timeout if (gameOver || currentPlayer !== 2) return; // Simple AI strategy: try to win, block player, or play randomly var bestMove = findBestMove(); if (bestMove && bestMove.value === 0 && !bestMove.isPlayerReserved) { // Validate coordinates are within bounds if (bestMove.row >= 0 && bestMove.row < 3 && bestMove.col >= 0 && bestMove.col < 3) { // Triple check the cell is still valid before AI places marker var targetCell = grid[bestMove.row][bestMove.col]; if (targetCell && targetCell.value === 0 && !targetCell.isPlayerReserved) { if (targetCell.placeMarker(2)) { checkWin(); if (!gameOver) { currentPlayer = 1; updateTurnDisplay(); } } } } } }, thinkingTime); } function findBestMove() { var emptyCells = []; var winningMoves = []; var blockingMoves = []; var forkMoves = []; var blockForkMoves = []; var cornerCells = []; var edgeCells = []; var validCells = []; // Collect all valid empty cells for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { var cell = grid[row][col]; if (cell && cell.value === 0 && !cell.isPlayerReserved) { emptyCells.push(cell); validCells.push(cell); // Categorize cell positions if ((row === 0 || row === 2) && (col === 0 || col === 2)) { cornerCells.push(cell); } else if (row === 1 && col === 1) { // Center cell - handled separately } else { edgeCells.push(cell); } } } } // Early exit if no valid moves if (validCells.length === 0) { return null; } // Advanced tactic evaluation functions function countWinningLines(row, col, player) { var count = 0; // Check row var rowCount = 0; for (var c = 0; c < 3; c++) { if (grid[row][c].value === player || c === col) { rowCount++; } else if (grid[row][c].value !== 0) { rowCount = -10; // Blocked break; } } if (rowCount === 3) count++; // Check column var colCount = 0; for (var r = 0; r < 3; r++) { if (grid[r][col].value === player || r === row) { colCount++; } else if (grid[r][col].value !== 0) { colCount = -10; // Blocked break; } } if (colCount === 3) count++; // Check diagonals if (row === 0 && col === 0 || row === 1 && col === 1 || row === 2 && col === 2) { var diagCount = 0; for (var i = 0; i < 3; i++) { if (grid[i][i].value === player || i === row && i === col) { diagCount++; } else if (grid[i][i].value !== 0) { diagCount = -10; // Blocked break; } } if (diagCount === 3) count++; } if (row === 0 && col === 2 || row === 1 && col === 1 || row === 2 && col === 0) { var antiDiagCount = 0; for (var i = 0; i < 3; i++) { if (grid[i][2 - i].value === player || i === row && 2 - i === col) { antiDiagCount++; } else if (grid[i][2 - i].value !== 0) { antiDiagCount = -10; // Blocked break; } } if (antiDiagCount === 3) count++; } return count; } // Evaluate move position strength function evaluatePosition(cell) { var score = 0; var row = cell.row; var col = cell.col; // Center is most valuable if (row === 1 && col === 1) score += 4; // Corners are second most valuable else if ((row === 0 || row === 2) && (col === 0 || col === 2)) score += 3; // Edges are least valuable else score += 1; // Check potential winning lines var potentialLines = countWinningLines(row, col, 2); score += potentialLines * 2; return score; } // Check for forks (moves that create two winning threats) function checkForFork(player) { var forkCells = []; for (var i = 0; i < emptyCells.length; i++) { var cell = emptyCells[i]; cell.value = player; var winningLineCount = 0; // Count how many winning moves this creates for (var j = 0; j < emptyCells.length; j++) { if (i !== j) { var testCell = emptyCells[j]; testCell.value = player; if (checkWinCondition(player)) { winningLineCount++; } testCell.value = 0; } } cell.value = 0; if (winningLineCount >= 2) { forkCells.push(cell); } } return forkCells; } // Randomly select AI personality/strategy for this move var aiPersonality = Math.floor(Math.random() * 8); // Increased personalities var randomnessFactor = Math.random(); // Priority 1: Check if AI can win immediately for (var i = 0; i < emptyCells.length; i++) { var cell = emptyCells[i]; cell.value = 2; if (checkWinCondition(2)) { cell.value = 0; winningMoves.push(cell); } cell.value = 0; } // Always take winning move (reduced randomness from 5% to 2%) if (winningMoves.length > 0 && randomnessFactor > 0.02) { return winningMoves[Math.floor(Math.random() * winningMoves.length)]; } // Priority 2: Block player from winning for (var i = 0; i < emptyCells.length; i++) { var cell = emptyCells[i]; cell.value = 1; if (checkWinCondition(1)) { cell.value = 0; blockingMoves.push(cell); } cell.value = 0; } // Almost always block (reduced fail chance from 10% to 5%) if (blockingMoves.length > 0 && randomnessFactor > 0.05) { return blockingMoves[Math.floor(Math.random() * blockingMoves.length)]; } // Priority 3: Check for fork opportunities forkMoves = checkForFork(2); if (forkMoves.length > 0 && randomnessFactor > 0.15) { return forkMoves[Math.floor(Math.random() * forkMoves.length)]; } // Priority 4: Block player forks blockForkMoves = checkForFork(1); if (blockForkMoves.length > 0 && randomnessFactor > 0.2) { // Force player to defend instead of creating fork return blockForkMoves[Math.floor(Math.random() * blockForkMoves.length)]; } // Priority 5: Advanced tactical personalities var moveChoices = []; var moveScores = []; if (aiPersonality === 0) { // Perfect player - uses optimal strategy if (emptyCells.length === 9) { // First move: prefer corner moveChoices = cornerCells.slice(); } else if (emptyCells.length === 8) { // Second move response if (grid[1][1].value === 1) { // Player took center, take corner moveChoices = cornerCells.slice(); } else { // Player took corner or edge, take center if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); } } } else { // Evaluate all positions for (var i = 0; i < emptyCells.length; i++) { var score = evaluatePosition(emptyCells[i]); moveScores.push({ cell: emptyCells[i], score: score }); } moveScores.sort(function (a, b) { return b.score - a.score; }); // Take top scoring moves var topScore = moveScores[0].score; for (var i = 0; i < moveScores.length; i++) { if (moveScores[i].score >= topScore - 1) { moveChoices.push(moveScores[i].cell); } } } } else if (aiPersonality === 1) { // Trap setter - tries to create winning patterns if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); moveChoices.push(grid[1][1]); // Double weight } // Look for L-shaped patterns if (grid[0][0].value === 2 && grid[2][2].value === 0 && !grid[2][2].isPlayerReserved) { moveChoices.push(grid[2][2]); } if (grid[0][2].value === 2 && grid[2][0].value === 0 && !grid[2][0].isPlayerReserved) { moveChoices.push(grid[2][0]); } // Add corners for trap potential if (cornerCells.length > 0) { moveChoices = moveChoices.concat(cornerCells); } } else if (aiPersonality === 2) { // Defensive player - blocks and controls center if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); moveChoices.push(grid[1][1]); moveChoices.push(grid[1][1]); // Triple weight for center } // Prefer moves that block multiple lines for (var i = 0; i < emptyCells.length; i++) { var blockCount = countWinningLines(emptyCells[i].row, emptyCells[i].col, 1); if (blockCount >= 2) { moveChoices.push(emptyCells[i]); } } if (moveChoices.length === 0 && cornerCells.length > 0) { moveChoices = cornerCells.slice(); } } else if (aiPersonality === 3) { // Mirror player - plays symmetrically var playerMoves = []; for (var r = 0; r < 3; r++) { for (var c = 0; c < 3; c++) { if (grid[r][c].value === 1) { playerMoves.push({ row: r, col: c }); } } } if (playerMoves.length > 0) { var lastMove = playerMoves[playerMoves.length - 1]; // Try to mirror across center var mirrorRow = 2 - lastMove.row; var mirrorCol = 2 - lastMove.col; if (grid[mirrorRow][mirrorCol].value === 0 && !grid[mirrorRow][mirrorCol].isPlayerReserved) { moveChoices.push(grid[mirrorRow][mirrorCol]); moveChoices.push(grid[mirrorRow][mirrorCol]); // Double weight } } // Add strategic positions if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); } if (cornerCells.length > 0) { moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]); } } else if (aiPersonality === 4) { // Edge control player - unusual but effective if (edgeCells.length > 0) { // Prefer edges that connect to existing pieces for (var i = 0; i < edgeCells.length; i++) { var edge = edgeCells[i]; var adjacentAI = 0; // Check adjacent cells var checkPositions = [{ r: edge.row - 1, c: edge.col }, { r: edge.row + 1, c: edge.col }, { r: edge.row, c: edge.col - 1 }, { r: edge.row, c: edge.col + 1 }]; for (var j = 0; j < checkPositions.length; j++) { var pos = checkPositions[j]; if (pos.r >= 0 && pos.r < 3 && pos.c >= 0 && pos.c < 3) { if (grid[pos.r][pos.c].value === 2) { adjacentAI++; } } } if (adjacentAI > 0) { moveChoices.push(edge); moveChoices.push(edge); // Double weight for connected edges } } if (moveChoices.length === 0) { moveChoices = edgeCells.slice(); } } // Sometimes take center if (Math.random() < 0.3 && grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); } } else if (aiPersonality === 5) { // Chaos player - creates complex board states var complexityScore = []; for (var i = 0; i < emptyCells.length; i++) { var cell = emptyCells[i]; // Calculate how many lines this move affects var linesAffected = 0; if (true) linesAffected++; // Row if (true) linesAffected++; // Column if (cell.row === cell.col || cell.row + cell.col === 2) { linesAffected++; // Diagonal } complexityScore.push({ cell: cell, complexity: linesAffected }); } // Prefer high complexity moves complexityScore.sort(function (a, b) { return b.complexity - a.complexity; }); for (var i = 0; i < Math.min(3, complexityScore.length); i++) { moveChoices.push(complexityScore[i].cell); } } else if (aiPersonality === 6) { // Pattern player - follows specific winning patterns var patterns = [ // Corner-opposite-corner [{ r: 0, c: 0 }, { r: 2, c: 2 }], [{ r: 0, c: 2 }, { r: 2, c: 0 }], // L-shapes [{ r: 0, c: 0 }, { r: 0, c: 2 }], [{ r: 0, c: 0 }, { r: 2, c: 0 }], [{ r: 2, c: 2 }, { r: 2, c: 0 }], [{ r: 2, c: 2 }, { r: 0, c: 2 }]]; for (var p = 0; p < patterns.length; p++) { var pattern = patterns[p]; var hasFirst = grid[pattern[0].r][pattern[0].c].value === 2; var secondEmpty = grid[pattern[1].r][pattern[1].c].value === 0 && !grid[pattern[1].r][pattern[1].c].isPlayerReserved; if (hasFirst && secondEmpty) { moveChoices.push(grid[pattern[1].r][pattern[1].c]); moveChoices.push(grid[pattern[1].r][pattern[1].c]); // Double weight } } // Default to smart positions if (moveChoices.length === 0) { if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); } if (cornerCells.length > 0) { moveChoices = moveChoices.concat(cornerCells); } } } else { // Adaptive player - changes strategy based on game state var gamePhase = 9 - emptyCells.length; // 0-8, higher = later if (gamePhase <= 2) { // Early game: control key positions if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { moveChoices.push(grid[1][1]); moveChoices.push(grid[1][1]); } if (cornerCells.length > 0) { moveChoices = moveChoices.concat(cornerCells); } } else if (gamePhase <= 5) { // Mid game: create threats for (var i = 0; i < emptyCells.length; i++) { var threatLevel = countWinningLines(emptyCells[i].row, emptyCells[i].col, 2); if (threatLevel >= 1) { moveChoices.push(emptyCells[i]); if (threatLevel >= 2) { moveChoices.push(emptyCells[i]); // Extra weight for multi-threats } } } } else { // Late game: optimize winning chances for (var i = 0; i < emptyCells.length; i++) { moveChoices.push(emptyCells[i]); } } } // Add calculated randomness if (Math.random() < 0.1) { // 10% chance to add unexpected move if (validCells.length > 0) { var randomCell = validCells[Math.floor(Math.random() * validCells.length)]; moveChoices.push(randomCell); } } // If we have strategic choices, pick from them if (moveChoices.length > 0) { // Sometimes pick the most frequent choice (if duplicates exist) var choiceFrequency = {}; for (var i = 0; i < moveChoices.length; i++) { var key = moveChoices[i].row + ',' + moveChoices[i].col; choiceFrequency[key] = (choiceFrequency[key] || 0) + 1; } // Create weighted selection var weightedChoices = []; for (var i = 0; i < moveChoices.length; i++) { weightedChoices.push(moveChoices[i]); } return weightedChoices[Math.floor(Math.random() * weightedChoices.length)]; } // Final fallback: intelligent selection var fallbackChoices = []; // Prioritize based on position value if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) { fallbackChoices.push(grid[1][1]); } if (cornerCells.length > 0) { fallbackChoices = fallbackChoices.concat(cornerCells); } if (edgeCells.length > 0 && Math.random() < 0.3) { fallbackChoices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]); } if (fallbackChoices.length === 0) { fallbackChoices = validCells; } if (fallbackChoices.length > 0) { return fallbackChoices[Math.floor(Math.random() * fallbackChoices.length)]; } return null; } function checkWinCondition(player) { // Check rows for (var row = 0; row < 3; row++) { if (grid[row][0].value === player && grid[row][1].value === player && grid[row][2].value === player) { return true; } } // Check columns for (var col = 0; col < 3; col++) { if (grid[0][col].value === player && grid[1][col].value === player && grid[2][col].value === player) { return true; } } // Check diagonals if (grid[0][0].value === player && grid[1][1].value === player && grid[2][2].value === player) { return true; } if (grid[0][2].value === player && grid[1][1].value === player && grid[2][0].value === player) { return true; } return false; } function resetGame() { gameOver = false; // Start according to game mode if (gameMode === 'ai') { currentPlayer = 1; // Player always starts in AI mode isAIMode = true; } else if (gameMode === 'twoPlayer') { currentPlayer = Math.random() < 0.5 ? 1 : 2; isAIMode = false; } else { // Menu mode currentPlayer = 1; isAIMode = false; } // Clear grid for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { var cell = grid[row][col]; cell.value = 0; cell.isPlayerReserved = false; cell.lastClickTime = 0; if (cell.marker) { cell.marker.destroy(); cell.marker = null; } } } // Clear UI statusText.setText(''); statusText.alpha = 0; playAgainBtn.alpha = 0; // Remove win line if (winLine) { // Reset line properties before destroying winLine.line.alpha = 0; winLine.line.scaleX = 0; winLine.destroy(); winLine = null; } updateTurnDisplay(); } // Save current version function function saveCurrentVersion() { storage.savedVersion = { timestamp: Date.now(), version: 'TicTacToe_TurkishEnglish_v1.0' }; } // Play again button handler playAgainBtn.down = function (x, y, obj) { if (gameOver) { resetGame(); } }; // Save the current version on game initialization saveCurrentVersion(); // Add small delay to prevent initial freeze when entering game var gameReady = false; LK.setTimeout(function () { gameReady = true; }, 50); // Reduced delay for better responsiveness
===================================================================
--- original.js
+++ change.js
@@ -554,9 +554,10 @@
function findBestMove() {
var emptyCells = [];
var winningMoves = [];
var blockingMoves = [];
- var strategicMoves = [];
+ var forkMoves = [];
+ var blockForkMoves = [];
var cornerCells = [];
var edgeCells = [];
var validCells = [];
// Collect all valid empty cells
@@ -580,12 +581,105 @@
// Early exit if no valid moves
if (validCells.length === 0) {
return null;
}
+ // Advanced tactic evaluation functions
+ function countWinningLines(row, col, player) {
+ var count = 0;
+ // Check row
+ var rowCount = 0;
+ for (var c = 0; c < 3; c++) {
+ if (grid[row][c].value === player || c === col) {
+ rowCount++;
+ } else if (grid[row][c].value !== 0) {
+ rowCount = -10; // Blocked
+ break;
+ }
+ }
+ if (rowCount === 3) count++;
+ // Check column
+ var colCount = 0;
+ for (var r = 0; r < 3; r++) {
+ if (grid[r][col].value === player || r === row) {
+ colCount++;
+ } else if (grid[r][col].value !== 0) {
+ colCount = -10; // Blocked
+ break;
+ }
+ }
+ if (colCount === 3) count++;
+ // Check diagonals
+ if (row === 0 && col === 0 || row === 1 && col === 1 || row === 2 && col === 2) {
+ var diagCount = 0;
+ for (var i = 0; i < 3; i++) {
+ if (grid[i][i].value === player || i === row && i === col) {
+ diagCount++;
+ } else if (grid[i][i].value !== 0) {
+ diagCount = -10; // Blocked
+ break;
+ }
+ }
+ if (diagCount === 3) count++;
+ }
+ if (row === 0 && col === 2 || row === 1 && col === 1 || row === 2 && col === 0) {
+ var antiDiagCount = 0;
+ for (var i = 0; i < 3; i++) {
+ if (grid[i][2 - i].value === player || i === row && 2 - i === col) {
+ antiDiagCount++;
+ } else if (grid[i][2 - i].value !== 0) {
+ antiDiagCount = -10; // Blocked
+ break;
+ }
+ }
+ if (antiDiagCount === 3) count++;
+ }
+ return count;
+ }
+ // Evaluate move position strength
+ function evaluatePosition(cell) {
+ var score = 0;
+ var row = cell.row;
+ var col = cell.col;
+ // Center is most valuable
+ if (row === 1 && col === 1) score += 4;
+ // Corners are second most valuable
+ else if ((row === 0 || row === 2) && (col === 0 || col === 2)) score += 3;
+ // Edges are least valuable
+ else score += 1;
+ // Check potential winning lines
+ var potentialLines = countWinningLines(row, col, 2);
+ score += potentialLines * 2;
+ return score;
+ }
+ // Check for forks (moves that create two winning threats)
+ function checkForFork(player) {
+ var forkCells = [];
+ for (var i = 0; i < emptyCells.length; i++) {
+ var cell = emptyCells[i];
+ cell.value = player;
+ var winningLineCount = 0;
+ // Count how many winning moves this creates
+ for (var j = 0; j < emptyCells.length; j++) {
+ if (i !== j) {
+ var testCell = emptyCells[j];
+ testCell.value = player;
+ if (checkWinCondition(player)) {
+ winningLineCount++;
+ }
+ testCell.value = 0;
+ }
+ }
+ cell.value = 0;
+ if (winningLineCount >= 2) {
+ forkCells.push(cell);
+ }
+ }
+ return forkCells;
+ }
// Randomly select AI personality/strategy for this move
- var aiPersonality = Math.floor(Math.random() * 5);
+ var aiPersonality = Math.floor(Math.random() * 8); // Increased personalities
var randomnessFactor = Math.random();
- // Priority 1: Check if AI can win immediately (always do this, but with some variation)
+ // Priority 1: Check if AI can win immediately
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (checkWinCondition(2)) {
@@ -593,13 +687,13 @@
winningMoves.push(cell);
}
cell.value = 0;
}
- // Sometimes make a suboptimal move instead of winning (5% chance for unpredictability)
- if (winningMoves.length > 0 && randomnessFactor > 0.05) {
+ // Always take winning move (reduced randomness from 5% to 2%)
+ if (winningMoves.length > 0 && randomnessFactor > 0.02) {
return winningMoves[Math.floor(Math.random() * winningMoves.length)];
}
- // Priority 2: Block player from winning (with some variation)
+ // Priority 2: Block player from winning
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (checkWinCondition(1)) {
@@ -607,124 +701,318 @@
blockingMoves.push(cell);
}
cell.value = 0;
}
- // Sometimes fail to block (10% chance for less predictable play)
- if (blockingMoves.length > 0 && randomnessFactor > 0.1) {
+ // Almost always block (reduced fail chance from 10% to 5%)
+ if (blockingMoves.length > 0 && randomnessFactor > 0.05) {
return blockingMoves[Math.floor(Math.random() * blockingMoves.length)];
}
- // Priority 3: Different AI personalities with varying strategies
+ // Priority 3: Check for fork opportunities
+ forkMoves = checkForFork(2);
+ if (forkMoves.length > 0 && randomnessFactor > 0.15) {
+ return forkMoves[Math.floor(Math.random() * forkMoves.length)];
+ }
+ // Priority 4: Block player forks
+ blockForkMoves = checkForFork(1);
+ if (blockForkMoves.length > 0 && randomnessFactor > 0.2) {
+ // Force player to defend instead of creating fork
+ return blockForkMoves[Math.floor(Math.random() * blockForkMoves.length)];
+ }
+ // Priority 5: Advanced tactical personalities
var moveChoices = [];
+ var moveScores = [];
if (aiPersonality === 0) {
- // Aggressive corner player
- if (cornerCells.length > 0) {
+ // Perfect player - uses optimal strategy
+ if (emptyCells.length === 9) {
+ // First move: prefer corner
moveChoices = cornerCells.slice();
- if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved && Math.random() < 0.3) {
- moveChoices.push(grid[1][1]);
+ } else if (emptyCells.length === 8) {
+ // Second move response
+ if (grid[1][1].value === 1) {
+ // Player took center, take corner
+ moveChoices = cornerCells.slice();
+ } else {
+ // Player took corner or edge, take center
+ if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
+ moveChoices.push(grid[1][1]);
+ }
}
+ } else {
+ // Evaluate all positions
+ for (var i = 0; i < emptyCells.length; i++) {
+ var score = evaluatePosition(emptyCells[i]);
+ moveScores.push({
+ cell: emptyCells[i],
+ score: score
+ });
+ }
+ moveScores.sort(function (a, b) {
+ return b.score - a.score;
+ });
+ // Take top scoring moves
+ var topScore = moveScores[0].score;
+ for (var i = 0; i < moveScores.length; i++) {
+ if (moveScores[i].score >= topScore - 1) {
+ moveChoices.push(moveScores[i].cell);
+ }
+ }
}
} else if (aiPersonality === 1) {
- // Center-focused player
+ // Trap setter - tries to create winning patterns
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
- moveChoices.push(grid[1][1]); // Double weight for center
+ moveChoices.push(grid[1][1]); // Double weight
}
- if (cornerCells.length > 0 && Math.random() < 0.4) {
- moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
+ // Look for L-shaped patterns
+ if (grid[0][0].value === 2 && grid[2][2].value === 0 && !grid[2][2].isPlayerReserved) {
+ moveChoices.push(grid[2][2]);
}
+ if (grid[0][2].value === 2 && grid[2][0].value === 0 && !grid[2][0].isPlayerReserved) {
+ moveChoices.push(grid[2][0]);
+ }
+ // Add corners for trap potential
+ if (cornerCells.length > 0) {
+ moveChoices = moveChoices.concat(cornerCells);
+ }
} else if (aiPersonality === 2) {
- // Edge-preferring player (unusual strategy)
- if (edgeCells.length > 0) {
- moveChoices = edgeCells.slice();
+ // Defensive player - blocks and controls center
+ if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
+ moveChoices.push(grid[1][1]);
+ moveChoices.push(grid[1][1]);
+ moveChoices.push(grid[1][1]); // Triple weight for center
}
- if (Math.random() < 0.3 && cornerCells.length > 0) {
- moveChoices.push(cornerCells[0]);
+ // Prefer moves that block multiple lines
+ for (var i = 0; i < emptyCells.length; i++) {
+ var blockCount = countWinningLines(emptyCells[i].row, emptyCells[i].col, 1);
+ if (blockCount >= 2) {
+ moveChoices.push(emptyCells[i]);
+ }
}
+ if (moveChoices.length === 0 && cornerCells.length > 0) {
+ moveChoices = cornerCells.slice();
+ }
} else if (aiPersonality === 3) {
- // Anti-pattern player (opposite corner strategy)
- var hasOppositeCorner = false;
- if (grid[0][0].value === 1 && grid[2][2].value === 0 && !grid[2][2].isPlayerReserved) {
- moveChoices.push(grid[2][2]);
- hasOppositeCorner = true;
+ // Mirror player - plays symmetrically
+ var playerMoves = [];
+ for (var r = 0; r < 3; r++) {
+ for (var c = 0; c < 3; c++) {
+ if (grid[r][c].value === 1) {
+ playerMoves.push({
+ row: r,
+ col: c
+ });
+ }
+ }
}
- if (grid[0][2].value === 1 && grid[2][0].value === 0 && !grid[2][0].isPlayerReserved) {
- moveChoices.push(grid[2][0]);
- hasOppositeCorner = true;
+ if (playerMoves.length > 0) {
+ var lastMove = playerMoves[playerMoves.length - 1];
+ // Try to mirror across center
+ var mirrorRow = 2 - lastMove.row;
+ var mirrorCol = 2 - lastMove.col;
+ if (grid[mirrorRow][mirrorCol].value === 0 && !grid[mirrorRow][mirrorCol].isPlayerReserved) {
+ moveChoices.push(grid[mirrorRow][mirrorCol]);
+ moveChoices.push(grid[mirrorRow][mirrorCol]); // Double weight
+ }
}
- if (grid[2][0].value === 1 && grid[0][2].value === 0 && !grid[0][2].isPlayerReserved) {
- moveChoices.push(grid[0][2]);
- hasOppositeCorner = true;
+ // Add strategic positions
+ if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
+ moveChoices.push(grid[1][1]);
}
- if (grid[2][2].value === 1 && grid[0][0].value === 0 && !grid[0][0].isPlayerReserved) {
- moveChoices.push(grid[0][0]);
- hasOppositeCorner = true;
+ if (cornerCells.length > 0) {
+ moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
}
- if (!hasOppositeCorner) {
- // Fallback to center or corner
+ } else if (aiPersonality === 4) {
+ // Edge control player - unusual but effective
+ if (edgeCells.length > 0) {
+ // Prefer edges that connect to existing pieces
+ for (var i = 0; i < edgeCells.length; i++) {
+ var edge = edgeCells[i];
+ var adjacentAI = 0;
+ // Check adjacent cells
+ var checkPositions = [{
+ r: edge.row - 1,
+ c: edge.col
+ }, {
+ r: edge.row + 1,
+ c: edge.col
+ }, {
+ r: edge.row,
+ c: edge.col - 1
+ }, {
+ r: edge.row,
+ c: edge.col + 1
+ }];
+ for (var j = 0; j < checkPositions.length; j++) {
+ var pos = checkPositions[j];
+ if (pos.r >= 0 && pos.r < 3 && pos.c >= 0 && pos.c < 3) {
+ if (grid[pos.r][pos.c].value === 2) {
+ adjacentAI++;
+ }
+ }
+ }
+ if (adjacentAI > 0) {
+ moveChoices.push(edge);
+ moveChoices.push(edge); // Double weight for connected edges
+ }
+ }
+ if (moveChoices.length === 0) {
+ moveChoices = edgeCells.slice();
+ }
+ }
+ // Sometimes take center
+ if (Math.random() < 0.3 && grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
+ moveChoices.push(grid[1][1]);
+ }
+ } else if (aiPersonality === 5) {
+ // Chaos player - creates complex board states
+ var complexityScore = [];
+ for (var i = 0; i < emptyCells.length; i++) {
+ var cell = emptyCells[i];
+ // Calculate how many lines this move affects
+ var linesAffected = 0;
+ if (true) linesAffected++; // Row
+ if (true) linesAffected++; // Column
+ if (cell.row === cell.col || cell.row + cell.col === 2) {
+ linesAffected++; // Diagonal
+ }
+ complexityScore.push({
+ cell: cell,
+ complexity: linesAffected
+ });
+ }
+ // Prefer high complexity moves
+ complexityScore.sort(function (a, b) {
+ return b.complexity - a.complexity;
+ });
+ for (var i = 0; i < Math.min(3, complexityScore.length); i++) {
+ moveChoices.push(complexityScore[i].cell);
+ }
+ } else if (aiPersonality === 6) {
+ // Pattern player - follows specific winning patterns
+ var patterns = [
+ // Corner-opposite-corner
+ [{
+ r: 0,
+ c: 0
+ }, {
+ r: 2,
+ c: 2
+ }], [{
+ r: 0,
+ c: 2
+ }, {
+ r: 2,
+ c: 0
+ }],
+ // L-shapes
+ [{
+ r: 0,
+ c: 0
+ }, {
+ r: 0,
+ c: 2
+ }], [{
+ r: 0,
+ c: 0
+ }, {
+ r: 2,
+ c: 0
+ }], [{
+ r: 2,
+ c: 2
+ }, {
+ r: 2,
+ c: 0
+ }], [{
+ r: 2,
+ c: 2
+ }, {
+ r: 0,
+ c: 2
+ }]];
+ for (var p = 0; p < patterns.length; p++) {
+ var pattern = patterns[p];
+ var hasFirst = grid[pattern[0].r][pattern[0].c].value === 2;
+ var secondEmpty = grid[pattern[1].r][pattern[1].c].value === 0 && !grid[pattern[1].r][pattern[1].c].isPlayerReserved;
+ if (hasFirst && secondEmpty) {
+ moveChoices.push(grid[pattern[1].r][pattern[1].c]);
+ moveChoices.push(grid[pattern[1].r][pattern[1].c]); // Double weight
+ }
+ }
+ // Default to smart positions
+ if (moveChoices.length === 0) {
if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
- moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
+ moveChoices = moveChoices.concat(cornerCells);
}
}
} else {
- // Random balanced player
- var choices = [];
- if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
- choices.push(grid[1][1]);
+ // Adaptive player - changes strategy based on game state
+ var gamePhase = 9 - emptyCells.length; // 0-8, higher = later
+ if (gamePhase <= 2) {
+ // Early game: control key positions
+ if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
+ moveChoices.push(grid[1][1]);
+ moveChoices.push(grid[1][1]);
+ }
+ if (cornerCells.length > 0) {
+ moveChoices = moveChoices.concat(cornerCells);
+ }
+ } else if (gamePhase <= 5) {
+ // Mid game: create threats
+ for (var i = 0; i < emptyCells.length; i++) {
+ var threatLevel = countWinningLines(emptyCells[i].row, emptyCells[i].col, 2);
+ if (threatLevel >= 1) {
+ moveChoices.push(emptyCells[i]);
+ if (threatLevel >= 2) {
+ moveChoices.push(emptyCells[i]); // Extra weight for multi-threats
+ }
+ }
+ }
+ } else {
+ // Late game: optimize winning chances
+ for (var i = 0; i < emptyCells.length; i++) {
+ moveChoices.push(emptyCells[i]);
+ }
}
- if (cornerCells.length > 0) {
- choices = choices.concat(cornerCells);
- }
- if (edgeCells.length > 0 && Math.random() < 0.3) {
- choices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]);
- }
- moveChoices = choices;
}
- // Add some randomness to choices regardless of personality
- if (Math.random() < 0.15) {
- // 15% chance to add a completely random valid move
+ // Add calculated randomness
+ if (Math.random() < 0.1) {
+ // 10% chance to add unexpected move
if (validCells.length > 0) {
- moveChoices.push(validCells[Math.floor(Math.random() * validCells.length)]);
+ var randomCell = validCells[Math.floor(Math.random() * validCells.length)];
+ moveChoices.push(randomCell);
}
}
- // If we have strategic choices, pick randomly from them
+ // If we have strategic choices, pick from them
if (moveChoices.length > 0) {
- return moveChoices[Math.floor(Math.random() * moveChoices.length)];
- }
- // Priority 4: Intelligent fallback with variation
- var fallbackChoices = [];
- var fallbackStrategy = Math.floor(Math.random() * 3);
- if (fallbackStrategy === 0) {
- // Corner-first strategy
- if (cornerCells.length > 0) {
- fallbackChoices = cornerCells.slice();
+ // Sometimes pick the most frequent choice (if duplicates exist)
+ var choiceFrequency = {};
+ for (var i = 0; i < moveChoices.length; i++) {
+ var key = moveChoices[i].row + ',' + moveChoices[i].col;
+ choiceFrequency[key] = (choiceFrequency[key] || 0) + 1;
}
- if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved && Math.random() < 0.5) {
- fallbackChoices.push(grid[1][1]);
+ // Create weighted selection
+ var weightedChoices = [];
+ for (var i = 0; i < moveChoices.length; i++) {
+ weightedChoices.push(moveChoices[i]);
}
- } else if (fallbackStrategy === 1) {
- // Center-first strategy
- if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
- fallbackChoices.push(grid[1][1]);
- }
- if (cornerCells.length > 0) {
- fallbackChoices = fallbackChoices.concat(cornerCells);
- }
- } else {
- // Mixed strategy
- if (cornerCells.length > 0) {
- fallbackChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
- }
- if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
- fallbackChoices.push(grid[1][1]);
- }
- if (edgeCells.length > 0 && Math.random() < 0.4) {
- fallbackChoices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]);
- }
+ return weightedChoices[Math.floor(Math.random() * weightedChoices.length)];
}
- // Final fallback: any valid cell
+ // Final fallback: intelligent selection
+ var fallbackChoices = [];
+ // Prioritize based on position value
+ if (grid[1][1].value === 0 && !grid[1][1].isPlayerReserved) {
+ fallbackChoices.push(grid[1][1]);
+ }
+ if (cornerCells.length > 0) {
+ fallbackChoices = fallbackChoices.concat(cornerCells);
+ }
+ if (edgeCells.length > 0 && Math.random() < 0.3) {
+ fallbackChoices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]);
+ }
if (fallbackChoices.length === 0) {
fallbackChoices = validCells;
}
if (fallbackChoices.length > 0) {