/**** * Classes ****/ var AIPlayer = Container.expand(function () { var self = Container.call(this); self.decision = new Decision(); self.observePlayer = function (playerMoveIndex) { // AI logic to observe player's move and decide next move self.decision.playerMoves.push(playerMoveIndex); self.decision.availableCells.splice(self.decision.availableCells.indexOf(playerMoveIndex), 1); // Predict player's next move var predictedMove = self.decision.predictPlayerMove(); console.log("Predicted player's next move: ", predictedMove); }; self.makeMove = function () { if (!game.gameOver && !game.aiCooldownActive) { LK.setTimeout(function () { grid.forEach(function (cell) { cell.interactive = false; }); self.decision.decide(function (chosenIndex) { if (chosenIndex !== undefined && !grid[chosenIndex].taken) { var indicatorShape = grid[chosenIndex].attachAsset('indicator', { anchorX: 0.5, anchorY: 0.5 }); LK.setTimeout(function () { indicatorShape.destroy(); grid[chosenIndex].setPlayerValue('O'); self.decision.aiMoves.push(chosenIndex); self.decision.availableCells.splice(self.decision.availableCells.indexOf(chosenIndex), 1); game.checkGameState(); if (!game.gameOver) { game.aiTurn = false; grid.forEach(function (cell) { cell.interactive = true; // Re-enable player input after AI move }); } }, game.aiCooldown); } else { game.aiTurn = false; game.aiCooldownActive = false; // Ensure AI cooldown is reset grid.forEach(function (cell) { cell.interactive = true; // Re-enable player input after AI move }); } }); }, game.aiCooldown); game.aiCooldownActive = true; LK.setTimeout(function () { game.aiCooldownActive = false; game.aiTurn = false; // Ensure AI turn is reset }, game.aiCooldown); } }; // Add a method to undo the last move self.undoLastMove = function () { if (self.decision.aiMoves.length > 0) { var lastMoveIndex = self.decision.aiMoves.pop(); grid[lastMoveIndex].taken = false; grid[lastMoveIndex].value = null; grid[lastMoveIndex].removeChildren(); self.decision.availableCells.push(lastMoveIndex); } }; }); // Define the Cell class for the tic tac toe grid var Cell = Container.expand(function (x, y, index) { var self = Container.call(this); self.index = index; self.taken = false; self.value = null; var cellGraphics = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.interactive = true; self.on('down', function () { if (!self.taken && !game.aiTurn && !game.gameOver) { self.setPlayerValue('X'); game.checkGameState(); if (!game.gameOver) { game.aiPlayer.observePlayer(self.index); game.aiTurn = true; game.aiPlay(); } } }); self.setPlayerValue = function (value) { self.taken = true; self.value = value; var shape = value === 'X' ? 'xShape' : 'oShape'; var color = value === 'X' ? 0xFF0000 : 0x0000FF; var playerShape = self.attachAsset(shape, { anchorX: 0.5, anchorY: 0.5, color: color }); }; }); // Initialize power-up assets var Decision = Container.expand(function () { var self = Container.call(this); self.predictPlayerMove = function () { // Analyze player's move history to predict their next move var moveCounts = Array(9).fill(0); self.playerMoves.forEach(function (move) { moveCounts[move]++; }); // Find the cell with the highest count var predictedMove = moveCounts.indexOf(Math.max.apply(Math, _toConsumableArray(moveCounts))); // If the predicted move is already taken, choose a random available cell if (self.availableCells.includes(predictedMove)) { return predictedMove; } else { return self.availableCells[Math.floor(Math.random() * self.availableCells.length)]; } }; self.decide = function (callback) { var chosenIndex = self.availableCells[Math.floor(Math.random() * self.availableCells.length)]; var winningMoveIndex = -1; var blockMoveIndex = -1; winConditions.forEach(function (condition) { var aiCount = condition.filter(function (index) { return self.aiMoves.includes(index); }).length; var playerCount = condition.filter(function (index) { return self.playerMoves.includes(index); }).length; var availableCount = condition.filter(function (index) { return self.availableCells.includes(index); }).length; if (aiCount === 2 && availableCount === 1) { winningMoveIndex = condition.find(function (index) { return self.availableCells.includes(index); }); } if (playerCount === 2 && availableCount === 1) { blockMoveIndex = condition.find(function (index) { return self.availableCells.includes(index); }); } }); var chosenCell = winningMoveIndex !== -1 ? winningMoveIndex : blockMoveIndex !== -1 ? blockMoveIndex : self.availableCells.sort(function (a, b) { return a - b; })[0]; if (typeof callback === 'function') { callback(chosenCell); } }; self.findEmptySide = function () { var sideIndices = [1, 3, 5, 7]; var emptySides = sideIndices.filter(function (index) { return self.availableCells.includes(index); }); return emptySides.length > 0 ? emptySides[Math.floor(Math.random() * emptySides.length)] : -1; }; self.findOppositeCorner = function () { var playerCorners = [0, 2, 6, 8].filter(function (index) { return self.playerMoves.includes(index); }); var oppositeCorners = { 0: 8, 2: 6, 6: 2, 8: 0 }; var availableOppositeCorners = playerCorners.map(function (index) { return oppositeCorners[index]; }).filter(function (index) { return self.availableCells.includes(index); }); return availableOppositeCorners.length > 0 ? availableOppositeCorners[0] : -1; }; self.availableCells = []; self.playerMoves = []; self.aiMoves = []; self.observe = function (playerMoveIndex) { self.playerMoves.push(playerMoveIndex); self.availableCells.splice(self.availableCells.indexOf(playerMoveIndex), 1); }; self.rethink = function (callback) { // Simulate a more human-like decision-making process var potentialMoves = self.availableCells.map(function (cellIndex) { return { index: cellIndex, score: Math.random() // Assign a random score to simulate human-like thinking }; }); // Sort potential moves by score to simulate prioritization potentialMoves.sort(function (a, b) { return b.score - a.score; }); // Choose the move with the highest score var chosenIndex = potentialMoves[0].index; if (typeof callback === 'function') { callback(chosenIndex); } }; self.decide = function (callback) { // Advanced AI learning feature // This AI will analyze the entire game history to predict the player's next move // and adjust its strategy dynamically to counter the player's tendencies. // Removed the call to non-existent function 'predictAndCounterPlayerMove' // Implementing a placeholder for choosing a random available cell as a temporary fix var winningMoveIndex = -1; var blockMoveIndex = -1; var aiForkMoveIndex = self.findForkMove('ai'); var playerForkMoveIndex = self.findForkMove('player'); winConditions.forEach(function (condition) { var aiCount = condition.filter(function (index) { return self.aiMoves.includes(index); }).length; var playerCount = condition.filter(function (index) { return self.playerMoves.includes(index); }).length; var availableCount = condition.filter(function (index) { return self.availableCells.includes(index); }).length; if (aiCount === 2 && availableCount === 1) { winningMoveIndex = condition.find(function (index) { return self.availableCells.includes(index); }); } if (playerCount === 2 && availableCount === 1) { blockMoveIndex = condition.find(function (index) { return self.availableCells.includes(index); }); } }); var chosenIndex = winningMoveIndex !== -1 ? winningMoveIndex : blockMoveIndex !== -1 ? blockMoveIndex : aiForkMoveIndex !== -1 ? aiForkMoveIndex : playerForkMoveIndex !== -1 ? playerForkMoveIndex : self.availableCells[Math.floor(Math.random() * self.availableCells.length)]; self.findTrapMove = function () { var trapMoveIndex = -1; var potentialTraps = winConditions.filter(function (condition) { var aiCount = condition.filter(function (index) { return self.aiMoves.includes(index); }).length; var availableCount = condition.filter(function (index) { return self.availableCells.includes(index); }).length; return aiCount === 1 && availableCount === 2; }); if (potentialTraps.length >= 2) { var intersections = potentialTraps.reduce(function (acc, condition) { return acc.concat(condition.filter(function (index) { return self.availableCells.includes(index); })); }, []); var counts = intersections.reduce(function (acc, index) { acc[index] = (acc[index] || 0) + 1; return acc; }, {}); var maxCount = Math.max.apply(null, Object.values(counts)); if (maxCount === 2) { trapMoveIndex = parseInt(Object.keys(counts).find(function (key) { return counts[key] === maxCount; }), 10); } } return trapMoveIndex; }; self.findForkBlock = function (playerType) { var moves = playerType === 'ai' ? self.aiMoves : self.playerMoves; var forkBlockIndex = -1; self.availableCells.some(function (cellIndex) { var forkCount = 0; winConditions.forEach(function (condition) { if (condition.includes(cellIndex)) { var playerCount = condition.filter(function (index) { return moves.includes(index); }).length; var availableCount = condition.filter(function (index) { return self.availableCells.includes(index) && index !== cellIndex; }).length; if (playerCount === 1 && availableCount === 1) { forkCount++; if (forkCount > 1) { forkBlockIndex = cellIndex; return true; } } } }); if (forkCount > 1) { forkBlockIndex = cellIndex; return true; } return false; }); return forkBlockIndex; }; var centerIndex = 4; var cornerIndices = [0, 2, 6, 8]; var oppositeCornerIndex = self.findOppositeCorner(); var emptyCornerIndex = cornerIndices.find(function (index) { return self.availableCells.includes(index); }); var emptySideIndex = self.findEmptySide(); var centerIndex = 4; var isFirstMove = self.aiMoves.length === 0 && self.playerMoves.length === 0; var aiForkMoveIndex = self.findForkMove('ai'); var playerForkMoveIndex = self.findForkMove('player'); var isFirstMove = self.aiMoves.length === 0 && self.playerMoves.length === 0; var centerIndex = 4; var isFirstMoveCenterAvailable = isFirstMove && self.availableCells.includes(centerIndex); var chosenCell = winningMoveIndex !== -1 ? winningMoveIndex : blockMoveIndex !== -1 ? blockMoveIndex : aiForkMoveIndex !== -1 ? aiForkMoveIndex : playerForkMoveIndex !== -1 ? playerForkMoveIndex : isFirstMoveCenterAvailable ? centerIndex : emptyCornerIndex !== undefined ? emptyCornerIndex : oppositeCornerIndex !== -1 ? oppositeCornerIndex : emptySideIndex !== -1 ? emptySideIndex : self.availableCells.sort(function (a, b) { return a - b; })[0]; if (typeof callback === 'function') { callback(chosenCell); } }; self.findForkMove = function (playerType) { var moves = playerType === 'ai' ? self.aiMoves : self.playerMoves; var forkMoveIndex = -1; self.availableCells.some(function (cellIndex) { var forkCount = 0; winConditions.forEach(function (condition) { if (condition.includes(cellIndex)) { var playerCount = condition.filter(function (index) { return moves.includes(index); }).length; var availableCount = condition.filter(function (index) { return self.availableCells.includes(index) && index !== cellIndex; }).length; if (playerCount === 1 && availableCount === 2) { forkCount++; if (forkCount > 1) { forkMoveIndex = cellIndex; return true; } } } }); if (forkCount > 1) { forkMoveIndex = cellIndex; return true; } return false; }); return forkMoveIndex; }; for (var i = 0; i < 9; i++) { self.availableCells.push(i); } // Method to adjust AI difficulty self.adjustDifficulty = function (level) { switch (level) { case 1: // Easy this.predictPlayerMove = function () { return this.availableCells[Math.floor(Math.random() * this.availableCells.length)]; }; break; case 2: // Medium // Implement medium difficulty logic here break; case 3: // Hard // Implement hard difficulty logic here, possibly using more advanced strategies break; case 4: // Extreme // Implement extreme difficulty logic, making the AI nearly unbeatable // Implement extreme difficulty logic, making the AI nearly unbeatable this.decide = function (callback) { // Enhanced AI decision-making logic for extreme difficulty // Utilize a more sophisticated algorithm to evaluate and choose the best move // This could involve analyzing multiple future moves ahead (like in chess algorithms) // and considering both offensive and defensive strategies based on the current state of the game. // Placeholder for advanced decision-making algorithm // Example placeholder logic if (typeof callback === 'function') { callback(chosenIndex); } }; // Method for predicting and countering the player's move based on game history self.predictAndCounterPlayerMove = function () { // Analyze player's move patterns and tendencies var playerTendency = self.analyzePlayerTendencies(); var counterMoveIndex = -1; // Based on analysis, predict player's next move and decide on a counter strategy if (playerTendency.favorCorners) { counterMoveIndex = self.findCenterOrSide(); } else if (playerTendency.favorCenter) { counterMoveIndex = self.findEmptyCorner(); } else { // If no specific tendency, choose a strategic move counterMoveIndex = self.findStrategicMove(); } // If no strategic move is found, fallback to a random available cell return counterMoveIndex !== -1 ? counterMoveIndex : self.availableCells[Math.floor(Math.random() * self.availableCells.length)]; }; // Method to analyze player's move tendencies and return an analysis object self.analyzePlayerTendencies = function () { var tendencies = { favorCorners: false, favorCenter: false // Additional tendencies can be added here }; // Analyze the player's moves to identify tendencies var cornerMoves = [0, 2, 6, 8]; var centerMove = 4; var playerCornerMoves = self.playerMoves.filter(function (move) { return cornerMoves.includes(move); }).length; var playerCenterMoves = self.playerMoves.includes(centerMove) ? 1 : 0; // Determine tendencies based on move history tendencies.favorCorners = playerCornerMoves > playerCenterMoves; tendencies.favorCenter = playerCenterMoves > 0; return tendencies; }; // Method to find an empty corner, prioritizing corners not adjacent to the player's last move self.findEmptyCorner = function () { var cornerIndices = [0, 2, 6, 8]; var emptyCorners = cornerIndices.filter(function (index) { return self.availableCells.includes(index); }); return emptyCorners.length > 0 ? emptyCorners[Math.floor(Math.random() * emptyCorners.length)] : -1; }; // Method to find the center or an empty side, based on availability self.findCenterOrSide = function () { var centerIndex = 4; var sideIndices = [1, 3, 5, 7]; var emptySides = sideIndices.filter(function (index) { return self.availableCells.includes(index); }); if (self.availableCells.includes(centerIndex)) { return centerIndex; } else if (emptySides.length > 0) { return emptySides[Math.floor(Math.random() * emptySides.length)]; } else { return -1; } }; break; default: // Default to medium difficulty if an unknown level is provided break; } }; }); // Initialize star asset // Define the PowerUp class for special abilities on the board var PowerUp = Container.expand(function (x, y, type) { var self = Container.call(this); self.x = x; self.y = y; self.type = type; // 'extraTurn' or 'removeAIMove' var powerUpGraphics = self.attachAsset(type === 'extraTurn' ? 'extraTurnShape' : 'removeAIMoveShape', { anchorX: 0.5, anchorY: 0.5 }); self.interactive = true; self.on('down', function () { if (self.type === 'extraTurn') { game.playerExtraTurn = true; } else if (self.type === 'removeAIMove') { game.aiPlayer.undoLastMove(); } self.destroy(); }); }); var Rethink = Container.expand(function () { var self = Container.call(this); self.simulateHumanDecision = function (availableCells, callback) { // Simulate a more human-like decision-making process var potentialMoves = availableCells.map(function (cellIndex) { return { index: cellIndex, score: Math.random() // Assign a random score to simulate human-like thinking }; }); // Sort potential moves by score to simulate prioritization potentialMoves.sort(function (a, b) { return b.score - a.score; }); // Simulate a delay to mimic human decision-making LK.setTimeout(function () { // Choose the move with the highest score var chosenIndex = potentialMoves[0].index; if (typeof callback === 'function') { callback(chosenIndex); } }, 1000); // 1 second delay }; }); // Define the Star class for the dynamic background var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('starShape', { anchorX: 0.5, anchorY: 0.5 }); self.speed = Math.random() * 2 + 1; // Random speed for each star self._move_migrated = function () { self.y += self.speed; if (self.y > 2732) { // Reset star position when it goes off-screen self.y = -50; self.x = Math.random() * 2048; } }; }); var Training = Container.expand(function () { var self = Container.call(this); self.history = []; self.recordGameOutcome = function (playerMoves, aiMoves, outcome) { self.history.push({ playerMoves: playerMoves.slice(), aiMoves: aiMoves.slice(), outcome: outcome }); }; self.analyzeHistory = function () { // Use the analyzed history to adjust AI strategies var bestPattern = null; var bestScore = -Infinity; for (var pattern in patternCounts) { var score = patternCounts[pattern].wins - patternCounts[pattern].losses; if (score > bestScore) { bestScore = score; bestPattern = pattern; } } if (bestPattern) { console.log("AI adjusting strategy based on pattern:", bestPattern); } var patternCounts = {}; self.history.forEach(function (game) { var pattern = game.playerMoves.join('-'); if (!patternCounts[pattern]) { patternCounts[pattern] = { wins: 0, losses: 0, draws: 0 }; } if (game.outcome === 'AI Wins') { patternCounts[pattern].losses++; } else if (game.outcome === 'Player Wins') { patternCounts[pattern].wins++; } else { patternCounts[pattern].draws++; } }); console.log("Pattern analysis complete:", patternCounts); // This could involve identifying patterns in player moves and outcomes // and adjusting AI strategies accordingly console.log("Analyzing game history for AI improvement..."); // Placeholder for analysis logic }; self.learnFromHistory = function () { // Use the analyzed history to adjust AI strategies self.analyzeHistory(); console.log("AI learning from game history..."); // Placeholder for learning logic }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ // Initialize performance monitoring system var performanceMonitor = { frameTimes: [], maxFrameTimes: 60, addFrameTime: function addFrameTime(time) { this.frameTimes.push(time); if (this.frameTimes.length > this.maxFrameTimes) { this.frameTimes.shift(); } }, getAverageFrameTime: function getAverageFrameTime() { var total = this.frameTimes.reduce(function (sum, time) { return sum + time; }, 0); return total / this.frameTimes.length; }, logPerformance: function logPerformance() { console.log("Average Frame Time: " + this.getAverageFrameTime().toFixed(2) + "ms"); } }; // Hook into the game loop to monitor performance LK.on('tick', function () { var performance = window.performance || { now: function now() { return new Date().getTime(); } }; var startTime = performance.now(); // Call the original tick function var originalTick = LK.tick; LK.tick = function () { originalTick.call(LK); }; var endTime = performance.now(); performanceMonitor.addFrameTime(endTime - startTime); performanceMonitor.logPerformance(); }); // Initialize game state management system var gameStateManager = { states: [], maxStates: 10, saveState: function saveState(state) { this.states.push(state); if (this.states.length > this.maxStates) { this.states.shift(); } }, loadState: function loadState() { return this.states.length > 0 ? this.states.pop() : null; }, resetStates: function resetStates() { this.states = []; } }; // Example usage of game state management system function saveCurrentGameState() { var currentState = { grid: grid.map(function (cell) { return { index: cell.index, taken: cell.taken, value: cell.value }; }), aiTurn: game.aiTurn, gameOver: game.gameOver, playerWins: game.playerWins, aiWins: game.aiWins, level: game.level }; gameStateManager.saveState(currentState); } function loadPreviousGameState() { var previousState = gameStateManager.loadState(); if (previousState) { grid.forEach(function (cell, index) { cell.index = previousState.grid[index].index; cell.taken = previousState.grid[index].taken; cell.value = previousState.grid[index].value; }); game.aiTurn = previousState.aiTurn; game.gameOver = previousState.gameOver; game.playerWins = previousState.playerWins; game.aiWins = previousState.aiWins; game.level = previousState.level; } } // Initialize AI decision indicator function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) { return Array.from(r); } } function _arrayWithoutHoles(r) { if (Array.isArray(r)) { return _arrayLikeToArray(r); } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } var aiDecisionIndicator = new Text2('AI deciding...', { size: 50, fill: 0xFFFFFF }); aiDecisionIndicator.anchor.set(0.5, 0); aiDecisionIndicator.x = 2048 / 2; aiDecisionIndicator.y = 100; LK.gui.top.addChild(aiDecisionIndicator); // Function to update AI decision indicator with countdown function updateAIDecisionIndicator(countdown) { aiDecisionIndicator.setText('AI decides in: ' + countdown + 's'); } // Countdown logic for AI decision indicator var countdown = 3; // AI decision countdown in seconds var countdownInterval = LK.setInterval(function () { if (countdown > 0) { updateAIDecisionIndicator(countdown); countdown--; } else { LK.clearInterval(countdownInterval); aiDecisionIndicator.setText('AI deciding...'); } }, 1000); // Initialize power-up assets var stars = []; for (var i = 0; i < 100; i++) { var star = new Star(); star.x = Math.random() * 2048; star.y = Math.random() * 2732; game.addChild(star); stars.push(star); } // Animate stars LK.on('tick', function () { stars.forEach(function (star) { star._move_migrated(); }); }); // Initialize star asset var grid = []; // Initialize the tic tac toe grid function initializeGrid() { var gridSize = 3; var cellSize = 400; var startX = (2048 - gridSize * cellSize) / 2 + cellSize / 2; var startY = (2732 - gridSize * cellSize) / 2 + cellSize / 2; for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var index = i * gridSize + j; var cell = new Cell(startX + j * cellSize, startY + i * cellSize, index); game.addChild(cell); grid.push(cell); } } } game.aiPlayer = new AIPlayer(); game.training = new Training(); initializeGrid(); // Define win conditions var winConditions = [[0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns [0, 4, 8], [2, 4, 6] // Diagonals ]; // Define game logic // Initialize dynamic difficulty adjustment game.level = 1; // Start at level 1 game.playerWins = 0; game.aiWins = 0; game.adjustDifficulty = function () { // Adjust difficulty based on player's win rate var totalGames = game.playerWins + game.aiWins; var winRate = totalGames > 0 ? game.playerWins / totalGames : 0; if (winRate < 0.3) { game.level = 1; // Easy } else if (winRate >= 0.3 && winRate < 0.6) { game.level = 2; // Medium } else if (winRate >= 0.6 && winRate < 0.8) { game.level = 3; // Hard } else { game.level = 4; // Extreme } game.aiPlayer.decision.adjustDifficulty(game.level); // Update level display levelCounter.setText('Level: ' + game.level); }; game.playerWins = 0; game.aiWins = 0; var levelCounter = new Text2('Level: ' + game.level, { size: 50, fill: 0xFFFFFF }); levelCounter.anchor.set(0.5, 0); levelCounter.x = 2048 / 2; levelCounter.y = 50; LK.gui.top.addChild(levelCounter); game.aiTurn = false; game.aiCooldown = 300; // Reduced cooldown time in milliseconds for faster AI response game.gameOver = false; game.checkGameState = function () { // Failsafe check for game softlock or problems if (game.failsafeTriggered) { LK.showGameOver(); return; } // Check for win conditions var winConditions = [[0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns [0, 4, 8], [2, 4, 6] // Diagonals ]; for (var i = 0; i < winConditions.length; i++) { var condition = winConditions[i]; if (grid[condition[0]].value && grid[condition[0]].value === grid[condition[1]].value && grid[condition[0]].value === grid[condition[2]].value) { game.gameOver = true; for (var i = 0; i < 3; i++) { LK.setTimeout(function () { LK.effects.flashScreen(0x00FF00, 300); }, i * 600); } // Highlight the winning line with a different color condition.forEach(function (index) { var winningIndicator = grid[index].attachAsset('indicator', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFD700 // Gold color for winning line }); winningIndicator.alpha = 0.7; // Slight transparency for effect }); var winner = grid[condition[0]].value === 'X' ? 'You Win!' : 'AI Wins!'; var winText = new Text2(winner, { size: 150, fill: 0xFFFFFF }); winText.anchor.set(0.5, 0.5); winText.x = 2048 / 2; winText.y = 2732 / 2; LK.gui.center.addChild(winText); if (grid[condition[0]].value === 'O') { game.training.recordGameOutcome(game.aiPlayer.decision.playerMoves, game.aiPlayer.decision.aiMoves, 'AI Wins'); game.training.learnFromHistory(); for (var i = 0; i < 3; i++) { LK.setTimeout(function () { LK.effects.flashScreen(0xFF0000, 300); }, i * 600); } LK.setTimeout(function () { LK.showGameOver(); game.level = 1; // Reset level to 1 levelCounter.setText('Level: ' + game.level); // Reset game state grid.forEach(function (cell) { cell.destroy(); }); grid = []; game.aiPlayer.decision = new Decision(); // Reset AI decision state game.aiTurn = false; // Reset AI turn state game.gameOver = false; // Reset game over state initializeGrid(); grid.forEach(function (cell) { cell.interactive = true; // Re-enable player input }); // Reset player and AI win counts game.playerWins = 0; game.aiWins = 0; }, 1800); } else { game.training.recordGameOutcome(game.aiPlayer.decision.playerMoves, game.aiPlayer.decision.aiMoves, 'Player Wins'); game.training.learnFromHistory(); LK.setTimeout(function () { grid.forEach(function (cell) { cell.destroy(); }); grid = []; game.aiPlayer.decision = new Decision(); // Reset AI decision state game.aiTurn = false; // Reset AI turn state game.gameOver = false; // Reset game over state initializeGrid(); grid.forEach(function (cell) { cell.interactive = true; // Re-enable player input }); // Removed duplicate AI cooldown and turn reset logic grid.forEach(function (cell) { cell.interactive = true; // Re-enable player input after game state check }); game.level++; // Increase the level levelCounter.setText('Level: ' + game.level); }, 2000); } return; } } // Check for draw var draw = grid.every(function (cell) { return cell.taken; }); if (draw) { game.gameOver = true; game.training.recordGameOutcome(game.aiPlayer.decision.playerMoves, game.aiPlayer.decision.aiMoves, 'Draw'); game.training.learnFromHistory(); var flashCount = 0; var flashInterval = LK.setInterval(function () { LK.effects.flashScreen(0xA52A2A, 300); flashCount++; if (flashCount >= 4) { LK.clearInterval(flashInterval); grid.forEach(function (cell) { cell.destroy(); }); grid = []; game.aiPlayer.decision = new Decision(); game.aiTurn = false; // Reset AI turn state game.gameOver = false; // Reset game over state initializeGrid(); } }, 600); } }; game.aiPlay = function () { if (game.aiTurn) { LK.setTimeout(function () { game.aiPlayer.makeMove(); }, game.aiCooldown); } else { grid.forEach(function (cell) { cell.interactive = true; // Re-enable player input if AI turn is not active }); } }; // Start the game with the player's turn game.aiTurn = false;
/****
* Classes
****/
var AIPlayer = Container.expand(function () {
var self = Container.call(this);
self.decision = new Decision();
self.observePlayer = function (playerMoveIndex) {
// AI logic to observe player's move and decide next move
self.decision.playerMoves.push(playerMoveIndex);
self.decision.availableCells.splice(self.decision.availableCells.indexOf(playerMoveIndex), 1);
// Predict player's next move
var predictedMove = self.decision.predictPlayerMove();
console.log("Predicted player's next move: ", predictedMove);
};
self.makeMove = function () {
if (!game.gameOver && !game.aiCooldownActive) {
LK.setTimeout(function () {
grid.forEach(function (cell) {
cell.interactive = false;
});
self.decision.decide(function (chosenIndex) {
if (chosenIndex !== undefined && !grid[chosenIndex].taken) {
var indicatorShape = grid[chosenIndex].attachAsset('indicator', {
anchorX: 0.5,
anchorY: 0.5
});
LK.setTimeout(function () {
indicatorShape.destroy();
grid[chosenIndex].setPlayerValue('O');
self.decision.aiMoves.push(chosenIndex);
self.decision.availableCells.splice(self.decision.availableCells.indexOf(chosenIndex), 1);
game.checkGameState();
if (!game.gameOver) {
game.aiTurn = false;
grid.forEach(function (cell) {
cell.interactive = true; // Re-enable player input after AI move
});
}
}, game.aiCooldown);
} else {
game.aiTurn = false;
game.aiCooldownActive = false; // Ensure AI cooldown is reset
grid.forEach(function (cell) {
cell.interactive = true; // Re-enable player input after AI move
});
}
});
}, game.aiCooldown);
game.aiCooldownActive = true;
LK.setTimeout(function () {
game.aiCooldownActive = false;
game.aiTurn = false; // Ensure AI turn is reset
}, game.aiCooldown);
}
};
// Add a method to undo the last move
self.undoLastMove = function () {
if (self.decision.aiMoves.length > 0) {
var lastMoveIndex = self.decision.aiMoves.pop();
grid[lastMoveIndex].taken = false;
grid[lastMoveIndex].value = null;
grid[lastMoveIndex].removeChildren();
self.decision.availableCells.push(lastMoveIndex);
}
};
});
// Define the Cell class for the tic tac toe grid
var Cell = Container.expand(function (x, y, index) {
var self = Container.call(this);
self.index = index;
self.taken = false;
self.value = null;
var cellGraphics = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.interactive = true;
self.on('down', function () {
if (!self.taken && !game.aiTurn && !game.gameOver) {
self.setPlayerValue('X');
game.checkGameState();
if (!game.gameOver) {
game.aiPlayer.observePlayer(self.index);
game.aiTurn = true;
game.aiPlay();
}
}
});
self.setPlayerValue = function (value) {
self.taken = true;
self.value = value;
var shape = value === 'X' ? 'xShape' : 'oShape';
var color = value === 'X' ? 0xFF0000 : 0x0000FF;
var playerShape = self.attachAsset(shape, {
anchorX: 0.5,
anchorY: 0.5,
color: color
});
};
});
// Initialize power-up assets
var Decision = Container.expand(function () {
var self = Container.call(this);
self.predictPlayerMove = function () {
// Analyze player's move history to predict their next move
var moveCounts = Array(9).fill(0);
self.playerMoves.forEach(function (move) {
moveCounts[move]++;
});
// Find the cell with the highest count
var predictedMove = moveCounts.indexOf(Math.max.apply(Math, _toConsumableArray(moveCounts)));
// If the predicted move is already taken, choose a random available cell
if (self.availableCells.includes(predictedMove)) {
return predictedMove;
} else {
return self.availableCells[Math.floor(Math.random() * self.availableCells.length)];
}
};
self.decide = function (callback) {
var chosenIndex = self.availableCells[Math.floor(Math.random() * self.availableCells.length)];
var winningMoveIndex = -1;
var blockMoveIndex = -1;
winConditions.forEach(function (condition) {
var aiCount = condition.filter(function (index) {
return self.aiMoves.includes(index);
}).length;
var playerCount = condition.filter(function (index) {
return self.playerMoves.includes(index);
}).length;
var availableCount = condition.filter(function (index) {
return self.availableCells.includes(index);
}).length;
if (aiCount === 2 && availableCount === 1) {
winningMoveIndex = condition.find(function (index) {
return self.availableCells.includes(index);
});
}
if (playerCount === 2 && availableCount === 1) {
blockMoveIndex = condition.find(function (index) {
return self.availableCells.includes(index);
});
}
});
var chosenCell = winningMoveIndex !== -1 ? winningMoveIndex : blockMoveIndex !== -1 ? blockMoveIndex : self.availableCells.sort(function (a, b) {
return a - b;
})[0];
if (typeof callback === 'function') {
callback(chosenCell);
}
};
self.findEmptySide = function () {
var sideIndices = [1, 3, 5, 7];
var emptySides = sideIndices.filter(function (index) {
return self.availableCells.includes(index);
});
return emptySides.length > 0 ? emptySides[Math.floor(Math.random() * emptySides.length)] : -1;
};
self.findOppositeCorner = function () {
var playerCorners = [0, 2, 6, 8].filter(function (index) {
return self.playerMoves.includes(index);
});
var oppositeCorners = {
0: 8,
2: 6,
6: 2,
8: 0
};
var availableOppositeCorners = playerCorners.map(function (index) {
return oppositeCorners[index];
}).filter(function (index) {
return self.availableCells.includes(index);
});
return availableOppositeCorners.length > 0 ? availableOppositeCorners[0] : -1;
};
self.availableCells = [];
self.playerMoves = [];
self.aiMoves = [];
self.observe = function (playerMoveIndex) {
self.playerMoves.push(playerMoveIndex);
self.availableCells.splice(self.availableCells.indexOf(playerMoveIndex), 1);
};
self.rethink = function (callback) {
// Simulate a more human-like decision-making process
var potentialMoves = self.availableCells.map(function (cellIndex) {
return {
index: cellIndex,
score: Math.random() // Assign a random score to simulate human-like thinking
};
});
// Sort potential moves by score to simulate prioritization
potentialMoves.sort(function (a, b) {
return b.score - a.score;
});
// Choose the move with the highest score
var chosenIndex = potentialMoves[0].index;
if (typeof callback === 'function') {
callback(chosenIndex);
}
};
self.decide = function (callback) {
// Advanced AI learning feature
// This AI will analyze the entire game history to predict the player's next move
// and adjust its strategy dynamically to counter the player's tendencies.
// Removed the call to non-existent function 'predictAndCounterPlayerMove'
// Implementing a placeholder for choosing a random available cell as a temporary fix
var winningMoveIndex = -1;
var blockMoveIndex = -1;
var aiForkMoveIndex = self.findForkMove('ai');
var playerForkMoveIndex = self.findForkMove('player');
winConditions.forEach(function (condition) {
var aiCount = condition.filter(function (index) {
return self.aiMoves.includes(index);
}).length;
var playerCount = condition.filter(function (index) {
return self.playerMoves.includes(index);
}).length;
var availableCount = condition.filter(function (index) {
return self.availableCells.includes(index);
}).length;
if (aiCount === 2 && availableCount === 1) {
winningMoveIndex = condition.find(function (index) {
return self.availableCells.includes(index);
});
}
if (playerCount === 2 && availableCount === 1) {
blockMoveIndex = condition.find(function (index) {
return self.availableCells.includes(index);
});
}
});
var chosenIndex = winningMoveIndex !== -1 ? winningMoveIndex : blockMoveIndex !== -1 ? blockMoveIndex : aiForkMoveIndex !== -1 ? aiForkMoveIndex : playerForkMoveIndex !== -1 ? playerForkMoveIndex : self.availableCells[Math.floor(Math.random() * self.availableCells.length)];
self.findTrapMove = function () {
var trapMoveIndex = -1;
var potentialTraps = winConditions.filter(function (condition) {
var aiCount = condition.filter(function (index) {
return self.aiMoves.includes(index);
}).length;
var availableCount = condition.filter(function (index) {
return self.availableCells.includes(index);
}).length;
return aiCount === 1 && availableCount === 2;
});
if (potentialTraps.length >= 2) {
var intersections = potentialTraps.reduce(function (acc, condition) {
return acc.concat(condition.filter(function (index) {
return self.availableCells.includes(index);
}));
}, []);
var counts = intersections.reduce(function (acc, index) {
acc[index] = (acc[index] || 0) + 1;
return acc;
}, {});
var maxCount = Math.max.apply(null, Object.values(counts));
if (maxCount === 2) {
trapMoveIndex = parseInt(Object.keys(counts).find(function (key) {
return counts[key] === maxCount;
}), 10);
}
}
return trapMoveIndex;
};
self.findForkBlock = function (playerType) {
var moves = playerType === 'ai' ? self.aiMoves : self.playerMoves;
var forkBlockIndex = -1;
self.availableCells.some(function (cellIndex) {
var forkCount = 0;
winConditions.forEach(function (condition) {
if (condition.includes(cellIndex)) {
var playerCount = condition.filter(function (index) {
return moves.includes(index);
}).length;
var availableCount = condition.filter(function (index) {
return self.availableCells.includes(index) && index !== cellIndex;
}).length;
if (playerCount === 1 && availableCount === 1) {
forkCount++;
if (forkCount > 1) {
forkBlockIndex = cellIndex;
return true;
}
}
}
});
if (forkCount > 1) {
forkBlockIndex = cellIndex;
return true;
}
return false;
});
return forkBlockIndex;
};
var centerIndex = 4;
var cornerIndices = [0, 2, 6, 8];
var oppositeCornerIndex = self.findOppositeCorner();
var emptyCornerIndex = cornerIndices.find(function (index) {
return self.availableCells.includes(index);
});
var emptySideIndex = self.findEmptySide();
var centerIndex = 4;
var isFirstMove = self.aiMoves.length === 0 && self.playerMoves.length === 0;
var aiForkMoveIndex = self.findForkMove('ai');
var playerForkMoveIndex = self.findForkMove('player');
var isFirstMove = self.aiMoves.length === 0 && self.playerMoves.length === 0;
var centerIndex = 4;
var isFirstMoveCenterAvailable = isFirstMove && self.availableCells.includes(centerIndex);
var chosenCell = winningMoveIndex !== -1 ? winningMoveIndex : blockMoveIndex !== -1 ? blockMoveIndex : aiForkMoveIndex !== -1 ? aiForkMoveIndex : playerForkMoveIndex !== -1 ? playerForkMoveIndex : isFirstMoveCenterAvailable ? centerIndex : emptyCornerIndex !== undefined ? emptyCornerIndex : oppositeCornerIndex !== -1 ? oppositeCornerIndex : emptySideIndex !== -1 ? emptySideIndex : self.availableCells.sort(function (a, b) {
return a - b;
})[0];
if (typeof callback === 'function') {
callback(chosenCell);
}
};
self.findForkMove = function (playerType) {
var moves = playerType === 'ai' ? self.aiMoves : self.playerMoves;
var forkMoveIndex = -1;
self.availableCells.some(function (cellIndex) {
var forkCount = 0;
winConditions.forEach(function (condition) {
if (condition.includes(cellIndex)) {
var playerCount = condition.filter(function (index) {
return moves.includes(index);
}).length;
var availableCount = condition.filter(function (index) {
return self.availableCells.includes(index) && index !== cellIndex;
}).length;
if (playerCount === 1 && availableCount === 2) {
forkCount++;
if (forkCount > 1) {
forkMoveIndex = cellIndex;
return true;
}
}
}
});
if (forkCount > 1) {
forkMoveIndex = cellIndex;
return true;
}
return false;
});
return forkMoveIndex;
};
for (var i = 0; i < 9; i++) {
self.availableCells.push(i);
}
// Method to adjust AI difficulty
self.adjustDifficulty = function (level) {
switch (level) {
case 1:
// Easy
this.predictPlayerMove = function () {
return this.availableCells[Math.floor(Math.random() * this.availableCells.length)];
};
break;
case 2:
// Medium
// Implement medium difficulty logic here
break;
case 3:
// Hard
// Implement hard difficulty logic here, possibly using more advanced strategies
break;
case 4:
// Extreme
// Implement extreme difficulty logic, making the AI nearly unbeatable
// Implement extreme difficulty logic, making the AI nearly unbeatable
this.decide = function (callback) {
// Enhanced AI decision-making logic for extreme difficulty
// Utilize a more sophisticated algorithm to evaluate and choose the best move
// This could involve analyzing multiple future moves ahead (like in chess algorithms)
// and considering both offensive and defensive strategies based on the current state of the game.
// Placeholder for advanced decision-making algorithm
// Example placeholder logic
if (typeof callback === 'function') {
callback(chosenIndex);
}
};
// Method for predicting and countering the player's move based on game history
self.predictAndCounterPlayerMove = function () {
// Analyze player's move patterns and tendencies
var playerTendency = self.analyzePlayerTendencies();
var counterMoveIndex = -1;
// Based on analysis, predict player's next move and decide on a counter strategy
if (playerTendency.favorCorners) {
counterMoveIndex = self.findCenterOrSide();
} else if (playerTendency.favorCenter) {
counterMoveIndex = self.findEmptyCorner();
} else {
// If no specific tendency, choose a strategic move
counterMoveIndex = self.findStrategicMove();
}
// If no strategic move is found, fallback to a random available cell
return counterMoveIndex !== -1 ? counterMoveIndex : self.availableCells[Math.floor(Math.random() * self.availableCells.length)];
};
// Method to analyze player's move tendencies and return an analysis object
self.analyzePlayerTendencies = function () {
var tendencies = {
favorCorners: false,
favorCenter: false
// Additional tendencies can be added here
};
// Analyze the player's moves to identify tendencies
var cornerMoves = [0, 2, 6, 8];
var centerMove = 4;
var playerCornerMoves = self.playerMoves.filter(function (move) {
return cornerMoves.includes(move);
}).length;
var playerCenterMoves = self.playerMoves.includes(centerMove) ? 1 : 0;
// Determine tendencies based on move history
tendencies.favorCorners = playerCornerMoves > playerCenterMoves;
tendencies.favorCenter = playerCenterMoves > 0;
return tendencies;
};
// Method to find an empty corner, prioritizing corners not adjacent to the player's last move
self.findEmptyCorner = function () {
var cornerIndices = [0, 2, 6, 8];
var emptyCorners = cornerIndices.filter(function (index) {
return self.availableCells.includes(index);
});
return emptyCorners.length > 0 ? emptyCorners[Math.floor(Math.random() * emptyCorners.length)] : -1;
};
// Method to find the center or an empty side, based on availability
self.findCenterOrSide = function () {
var centerIndex = 4;
var sideIndices = [1, 3, 5, 7];
var emptySides = sideIndices.filter(function (index) {
return self.availableCells.includes(index);
});
if (self.availableCells.includes(centerIndex)) {
return centerIndex;
} else if (emptySides.length > 0) {
return emptySides[Math.floor(Math.random() * emptySides.length)];
} else {
return -1;
}
};
break;
default:
// Default to medium difficulty if an unknown level is provided
break;
}
};
});
// Initialize star asset
// Define the PowerUp class for special abilities on the board
var PowerUp = Container.expand(function (x, y, type) {
var self = Container.call(this);
self.x = x;
self.y = y;
self.type = type; // 'extraTurn' or 'removeAIMove'
var powerUpGraphics = self.attachAsset(type === 'extraTurn' ? 'extraTurnShape' : 'removeAIMoveShape', {
anchorX: 0.5,
anchorY: 0.5
});
self.interactive = true;
self.on('down', function () {
if (self.type === 'extraTurn') {
game.playerExtraTurn = true;
} else if (self.type === 'removeAIMove') {
game.aiPlayer.undoLastMove();
}
self.destroy();
});
});
var Rethink = Container.expand(function () {
var self = Container.call(this);
self.simulateHumanDecision = function (availableCells, callback) {
// Simulate a more human-like decision-making process
var potentialMoves = availableCells.map(function (cellIndex) {
return {
index: cellIndex,
score: Math.random() // Assign a random score to simulate human-like thinking
};
});
// Sort potential moves by score to simulate prioritization
potentialMoves.sort(function (a, b) {
return b.score - a.score;
});
// Simulate a delay to mimic human decision-making
LK.setTimeout(function () {
// Choose the move with the highest score
var chosenIndex = potentialMoves[0].index;
if (typeof callback === 'function') {
callback(chosenIndex);
}
}, 1000); // 1 second delay
};
});
// Define the Star class for the dynamic background
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('starShape', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 2 + 1; // Random speed for each star
self._move_migrated = function () {
self.y += self.speed;
if (self.y > 2732) {
// Reset star position when it goes off-screen
self.y = -50;
self.x = Math.random() * 2048;
}
};
});
var Training = Container.expand(function () {
var self = Container.call(this);
self.history = [];
self.recordGameOutcome = function (playerMoves, aiMoves, outcome) {
self.history.push({
playerMoves: playerMoves.slice(),
aiMoves: aiMoves.slice(),
outcome: outcome
});
};
self.analyzeHistory = function () {
// Use the analyzed history to adjust AI strategies
var bestPattern = null;
var bestScore = -Infinity;
for (var pattern in patternCounts) {
var score = patternCounts[pattern].wins - patternCounts[pattern].losses;
if (score > bestScore) {
bestScore = score;
bestPattern = pattern;
}
}
if (bestPattern) {
console.log("AI adjusting strategy based on pattern:", bestPattern);
}
var patternCounts = {};
self.history.forEach(function (game) {
var pattern = game.playerMoves.join('-');
if (!patternCounts[pattern]) {
patternCounts[pattern] = {
wins: 0,
losses: 0,
draws: 0
};
}
if (game.outcome === 'AI Wins') {
patternCounts[pattern].losses++;
} else if (game.outcome === 'Player Wins') {
patternCounts[pattern].wins++;
} else {
patternCounts[pattern].draws++;
}
});
console.log("Pattern analysis complete:", patternCounts);
// This could involve identifying patterns in player moves and outcomes
// and adjusting AI strategies accordingly
console.log("Analyzing game history for AI improvement...");
// Placeholder for analysis logic
};
self.learnFromHistory = function () {
// Use the analyzed history to adjust AI strategies
self.analyzeHistory();
console.log("AI learning from game history...");
// Placeholder for learning logic
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Init game with black background
});
/****
* Game Code
****/
// Initialize performance monitoring system
var performanceMonitor = {
frameTimes: [],
maxFrameTimes: 60,
addFrameTime: function addFrameTime(time) {
this.frameTimes.push(time);
if (this.frameTimes.length > this.maxFrameTimes) {
this.frameTimes.shift();
}
},
getAverageFrameTime: function getAverageFrameTime() {
var total = this.frameTimes.reduce(function (sum, time) {
return sum + time;
}, 0);
return total / this.frameTimes.length;
},
logPerformance: function logPerformance() {
console.log("Average Frame Time: " + this.getAverageFrameTime().toFixed(2) + "ms");
}
};
// Hook into the game loop to monitor performance
LK.on('tick', function () {
var performance = window.performance || {
now: function now() {
return new Date().getTime();
}
};
var startTime = performance.now();
// Call the original tick function
var originalTick = LK.tick;
LK.tick = function () {
originalTick.call(LK);
};
var endTime = performance.now();
performanceMonitor.addFrameTime(endTime - startTime);
performanceMonitor.logPerformance();
});
// Initialize game state management system
var gameStateManager = {
states: [],
maxStates: 10,
saveState: function saveState(state) {
this.states.push(state);
if (this.states.length > this.maxStates) {
this.states.shift();
}
},
loadState: function loadState() {
return this.states.length > 0 ? this.states.pop() : null;
},
resetStates: function resetStates() {
this.states = [];
}
};
// Example usage of game state management system
function saveCurrentGameState() {
var currentState = {
grid: grid.map(function (cell) {
return {
index: cell.index,
taken: cell.taken,
value: cell.value
};
}),
aiTurn: game.aiTurn,
gameOver: game.gameOver,
playerWins: game.playerWins,
aiWins: game.aiWins,
level: game.level
};
gameStateManager.saveState(currentState);
}
function loadPreviousGameState() {
var previousState = gameStateManager.loadState();
if (previousState) {
grid.forEach(function (cell, index) {
cell.index = previousState.grid[index].index;
cell.taken = previousState.grid[index].taken;
cell.value = previousState.grid[index].value;
});
game.aiTurn = previousState.aiTurn;
game.gameOver = previousState.gameOver;
game.playerWins = previousState.playerWins;
game.aiWins = previousState.aiWins;
game.level = previousState.level;
}
}
// Initialize AI decision indicator
function _toConsumableArray(r) {
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) {
return _arrayLikeToArray(r, a);
}
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function _iterableToArray(r) {
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) {
return Array.from(r);
}
}
function _arrayWithoutHoles(r) {
if (Array.isArray(r)) {
return _arrayLikeToArray(r);
}
}
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) {
n[e] = r[e];
}
return n;
}
var aiDecisionIndicator = new Text2('AI deciding...', {
size: 50,
fill: 0xFFFFFF
});
aiDecisionIndicator.anchor.set(0.5, 0);
aiDecisionIndicator.x = 2048 / 2;
aiDecisionIndicator.y = 100;
LK.gui.top.addChild(aiDecisionIndicator);
// Function to update AI decision indicator with countdown
function updateAIDecisionIndicator(countdown) {
aiDecisionIndicator.setText('AI decides in: ' + countdown + 's');
}
// Countdown logic for AI decision indicator
var countdown = 3; // AI decision countdown in seconds
var countdownInterval = LK.setInterval(function () {
if (countdown > 0) {
updateAIDecisionIndicator(countdown);
countdown--;
} else {
LK.clearInterval(countdownInterval);
aiDecisionIndicator.setText('AI deciding...');
}
}, 1000);
// Initialize power-up assets
var stars = [];
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
game.addChild(star);
stars.push(star);
}
// Animate stars
LK.on('tick', function () {
stars.forEach(function (star) {
star._move_migrated();
});
});
// Initialize star asset
var grid = [];
// Initialize the tic tac toe grid
function initializeGrid() {
var gridSize = 3;
var cellSize = 400;
var startX = (2048 - gridSize * cellSize) / 2 + cellSize / 2;
var startY = (2732 - gridSize * cellSize) / 2 + cellSize / 2;
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
var index = i * gridSize + j;
var cell = new Cell(startX + j * cellSize, startY + i * cellSize, index);
game.addChild(cell);
grid.push(cell);
}
}
}
game.aiPlayer = new AIPlayer();
game.training = new Training();
initializeGrid();
// Define win conditions
var winConditions = [[0, 1, 2], [3, 4, 5], [6, 7, 8],
// Rows
[0, 3, 6], [1, 4, 7], [2, 5, 8],
// Columns
[0, 4, 8], [2, 4, 6] // Diagonals
];
// Define game logic
// Initialize dynamic difficulty adjustment
game.level = 1; // Start at level 1
game.playerWins = 0;
game.aiWins = 0;
game.adjustDifficulty = function () {
// Adjust difficulty based on player's win rate
var totalGames = game.playerWins + game.aiWins;
var winRate = totalGames > 0 ? game.playerWins / totalGames : 0;
if (winRate < 0.3) {
game.level = 1; // Easy
} else if (winRate >= 0.3 && winRate < 0.6) {
game.level = 2; // Medium
} else if (winRate >= 0.6 && winRate < 0.8) {
game.level = 3; // Hard
} else {
game.level = 4; // Extreme
}
game.aiPlayer.decision.adjustDifficulty(game.level);
// Update level display
levelCounter.setText('Level: ' + game.level);
};
game.playerWins = 0;
game.aiWins = 0;
var levelCounter = new Text2('Level: ' + game.level, {
size: 50,
fill: 0xFFFFFF
});
levelCounter.anchor.set(0.5, 0);
levelCounter.x = 2048 / 2;
levelCounter.y = 50;
LK.gui.top.addChild(levelCounter);
game.aiTurn = false;
game.aiCooldown = 300; // Reduced cooldown time in milliseconds for faster AI response
game.gameOver = false;
game.checkGameState = function () {
// Failsafe check for game softlock or problems
if (game.failsafeTriggered) {
LK.showGameOver();
return;
}
// Check for win conditions
var winConditions = [[0, 1, 2], [3, 4, 5], [6, 7, 8],
// Rows
[0, 3, 6], [1, 4, 7], [2, 5, 8],
// Columns
[0, 4, 8], [2, 4, 6] // Diagonals
];
for (var i = 0; i < winConditions.length; i++) {
var condition = winConditions[i];
if (grid[condition[0]].value && grid[condition[0]].value === grid[condition[1]].value && grid[condition[0]].value === grid[condition[2]].value) {
game.gameOver = true;
for (var i = 0; i < 3; i++) {
LK.setTimeout(function () {
LK.effects.flashScreen(0x00FF00, 300);
}, i * 600);
}
// Highlight the winning line with a different color
condition.forEach(function (index) {
var winningIndicator = grid[index].attachAsset('indicator', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFD700 // Gold color for winning line
});
winningIndicator.alpha = 0.7; // Slight transparency for effect
});
var winner = grid[condition[0]].value === 'X' ? 'You Win!' : 'AI Wins!';
var winText = new Text2(winner, {
size: 150,
fill: 0xFFFFFF
});
winText.anchor.set(0.5, 0.5);
winText.x = 2048 / 2;
winText.y = 2732 / 2;
LK.gui.center.addChild(winText);
if (grid[condition[0]].value === 'O') {
game.training.recordGameOutcome(game.aiPlayer.decision.playerMoves, game.aiPlayer.decision.aiMoves, 'AI Wins');
game.training.learnFromHistory();
for (var i = 0; i < 3; i++) {
LK.setTimeout(function () {
LK.effects.flashScreen(0xFF0000, 300);
}, i * 600);
}
LK.setTimeout(function () {
LK.showGameOver();
game.level = 1; // Reset level to 1
levelCounter.setText('Level: ' + game.level);
// Reset game state
grid.forEach(function (cell) {
cell.destroy();
});
grid = [];
game.aiPlayer.decision = new Decision(); // Reset AI decision state
game.aiTurn = false; // Reset AI turn state
game.gameOver = false; // Reset game over state
initializeGrid();
grid.forEach(function (cell) {
cell.interactive = true; // Re-enable player input
});
// Reset player and AI win counts
game.playerWins = 0;
game.aiWins = 0;
}, 1800);
} else {
game.training.recordGameOutcome(game.aiPlayer.decision.playerMoves, game.aiPlayer.decision.aiMoves, 'Player Wins');
game.training.learnFromHistory();
LK.setTimeout(function () {
grid.forEach(function (cell) {
cell.destroy();
});
grid = [];
game.aiPlayer.decision = new Decision(); // Reset AI decision state
game.aiTurn = false; // Reset AI turn state
game.gameOver = false; // Reset game over state
initializeGrid();
grid.forEach(function (cell) {
cell.interactive = true; // Re-enable player input
});
// Removed duplicate AI cooldown and turn reset logic
grid.forEach(function (cell) {
cell.interactive = true; // Re-enable player input after game state check
});
game.level++; // Increase the level
levelCounter.setText('Level: ' + game.level);
}, 2000);
}
return;
}
}
// Check for draw
var draw = grid.every(function (cell) {
return cell.taken;
});
if (draw) {
game.gameOver = true;
game.training.recordGameOutcome(game.aiPlayer.decision.playerMoves, game.aiPlayer.decision.aiMoves, 'Draw');
game.training.learnFromHistory();
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
LK.effects.flashScreen(0xA52A2A, 300);
flashCount++;
if (flashCount >= 4) {
LK.clearInterval(flashInterval);
grid.forEach(function (cell) {
cell.destroy();
});
grid = [];
game.aiPlayer.decision = new Decision();
game.aiTurn = false; // Reset AI turn state
game.gameOver = false; // Reset game over state
initializeGrid();
}
}, 600);
}
};
game.aiPlay = function () {
if (game.aiTurn) {
LK.setTimeout(function () {
game.aiPlayer.makeMove();
}, game.aiCooldown);
} else {
grid.forEach(function (cell) {
cell.interactive = true; // Re-enable player input if AI turn is not active
});
}
};
// Start the game with the player's turn
game.aiTurn = false;