/****
* 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;