/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var GridCell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.marker = null; // 'X', 'O', or null
self.markerGraphic = null;
// Create invisible clickable area
var clickArea = self.attachAsset('cellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.setMarker = function (type) {
if (self.marker !== null) return false;
self.marker = type;
if (type === 'X') {
self.markerGraphic = new Text2('X', {
size: 100,
fill: 0xff4444
});
self.markerGraphic.anchor.set(0.5, 0.5);
self.addChild(self.markerGraphic);
} else if (type === 'O') {
self.markerGraphic = new Text2('O', {
size: 100,
fill: 0x4444ff
});
self.markerGraphic.anchor.set(0.5, 0.5);
self.addChild(self.markerGraphic);
}
if (self.markerGraphic) {
self.markerGraphic.alpha = 0;
tween(self.markerGraphic, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
tween(self.markerGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
delay: 200
});
}
return true;
};
self.reset = function () {
if (self.markerGraphic) {
self.removeChild(self.markerGraphic);
self.markerGraphic = null;
}
self.marker = null;
};
self.highlight = function () {
clickArea.alpha = 0.3;
tween(clickArea, {
alpha: 0
}, {
duration: 300
});
};
self.down = function (x, y, obj) {
if (gameState === 'playing' && self.marker === null) {
self.highlight();
makePlayerMove(self.row, self.col);
}
};
return self;
});
var TicTacBoard = Container.expand(function () {
var self = Container.call(this);
self.grid = [];
self.cells = [];
// Initialize 3x3 grid
for (var i = 0; i < 3; i++) {
self.grid[i] = [];
for (var j = 0; j < 3; j++) {
self.grid[i][j] = null;
}
}
// Create visual grid lines - classic 4-line pattern extending full screen
// First vertical line (left)
var vLine1 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: 0,
height: 2732
});
// Second vertical line (right)
var vLine2 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 250,
y: 0,
height: 2732
});
// First horizontal line (top)
var hLine1 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -250,
width: 2048,
height: 8,
rotation: 0
});
// Second horizontal line (bottom)
var hLine2 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 250,
width: 2048,
height: 8,
rotation: 0
});
// Create grid cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = new GridCell(row, col);
cell.x = col * 500 - 500;
cell.y = row * 500 - 500;
self.addChild(cell);
self.cells.push(cell);
}
}
self.placeMarker = function (row, col, marker) {
if (self.grid[row][col] !== null) return false;
self.grid[row][col] = marker;
var cell = self.cells[row * 3 + col];
return cell.setMarker(marker);
};
self.checkWinner = function () {
// Check rows
for (var i = 0; i < 3; i++) {
if (self.grid[i][0] && self.grid[i][0] === self.grid[i][1] && self.grid[i][1] === self.grid[i][2]) {
return {
winner: self.grid[i][0],
line: 'row',
index: i
};
}
}
// Check columns
for (var i = 0; i < 3; i++) {
if (self.grid[0][i] && self.grid[0][i] === self.grid[1][i] && self.grid[1][i] === self.grid[2][i]) {
return {
winner: self.grid[0][i],
line: 'col',
index: i
};
}
}
// Check diagonals
if (self.grid[0][0] && self.grid[0][0] === self.grid[1][1] && self.grid[1][1] === self.grid[2][2]) {
return {
winner: self.grid[0][0],
line: 'diag',
index: 0
};
}
if (self.grid[0][2] && self.grid[0][2] === self.grid[1][1] && self.grid[1][1] === self.grid[2][0]) {
return {
winner: self.grid[0][2],
line: 'diag',
index: 1
};
}
return null;
};
self.isFull = function () {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (self.grid[i][j] === null) return false;
}
}
return true;
};
self.reset = function () {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
self.grid[i][j] = null;
}
}
for (var i = 0; i < self.cells.length; i++) {
self.cells[i].reset();
}
};
self.getEmptyCells = function () {
var empty = [];
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (self.grid[i][j] === null) {
empty.push({
row: i,
col: j
});
}
}
}
return empty;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// RGB background color variables
var backgroundHue = 0;
var colorSpeed = 1;
// Game state variables
var gameState = 'playing'; // 'playing', 'gameOver', 'victory'
var currentPlayer = 'X'; // Player is always X
var currentLevel = storage.level || 1;
var board;
var levelText;
var statusText;
var victoryBanner;
var aiDifficulty;
// Initialize UI
function initializeUI() {
levelText = new Text2('Level ' + currentLevel, {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
levelText.y = 100;
statusText = new Text2('Your Turn (X)', {
size: 50,
fill: 0xFFFF00
});
statusText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(statusText);
statusText.y = -200;
}
// Initialize game board
function initializeBoard() {
board = new TicTacBoard();
board.x = 2048 / 2;
board.y = 2732 / 2;
game.addChild(board);
}
// Calculate AI difficulty based on level
function calculateAIDifficulty() {
if (currentLevel <= 10) {
aiDifficulty = 0.1; // Very easy
} else if (currentLevel <= 50) {
aiDifficulty = 0.3; // Easy
} else if (currentLevel <= 200) {
aiDifficulty = 0.5; // Medium
} else if (currentLevel <= 1000) {
aiDifficulty = 0.7; // Hard
} else {
aiDifficulty = 0.9; // Very hard
}
}
// Player makes a move
function makePlayerMove(row, col) {
if (gameState !== 'playing' || currentPlayer !== 'X') return;
if (board.placeMarker(row, col, 'X')) {
LK.getSound('placeMarker').play();
var result = board.checkWinner();
if (result) {
handleGameEnd(result.winner);
return;
}
if (board.isFull()) {
handleGameEnd('draw');
return;
}
currentPlayer = 'O';
statusText.setText('AI Turn (O)');
statusText.tint = 0x4444ff;
// AI makes move after delay
LK.setTimeout(function () {
makeAIMove();
}, 500);
}
}
// AI makes a move
function makeAIMove() {
if (gameState !== 'playing' || currentPlayer !== 'O') return;
var move;
if (Math.random() < aiDifficulty) {
move = getBestAIMove();
} else {
move = getRandomAIMove();
}
if (move && board.placeMarker(move.row, move.col, 'O')) {
LK.getSound('placeMarker').play();
var result = board.checkWinner();
if (result) {
handleGameEnd(result.winner);
return;
}
if (board.isFull()) {
handleGameEnd('draw');
return;
}
currentPlayer = 'X';
statusText.setText('Your Turn (X)');
statusText.tint = 0xff4444;
}
}
// Get best AI move using minimax
function getBestAIMove() {
var bestScore = -Infinity;
var bestMove = null;
var emptyCells = board.getEmptyCells();
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
board.grid[cell.row][cell.col] = 'O';
var score = minimax(board.grid, 0, false);
board.grid[cell.row][cell.col] = null;
if (score > bestScore) {
bestScore = score;
bestMove = cell;
}
}
return bestMove;
}
// Get random AI move
function getRandomAIMove() {
var emptyCells = board.getEmptyCells();
if (emptyCells.length > 0) {
var randomIndex = Math.floor(Math.random() * emptyCells.length);
return emptyCells[randomIndex];
}
return null;
}
// Minimax algorithm for AI
function minimax(grid, depth, isMaximizing) {
var result = checkWinnerGrid(grid);
if (result === 'O') return 10 - depth;
if (result === 'X') return depth - 10;
if (isGridFull(grid)) return 0;
if (isMaximizing) {
var bestScore = -Infinity;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === null) {
grid[i][j] = 'O';
var score = minimax(grid, depth + 1, false);
grid[i][j] = null;
bestScore = Math.max(score, bestScore);
}
}
}
return bestScore;
} else {
var bestScore = Infinity;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === null) {
grid[i][j] = 'X';
var score = minimax(grid, depth + 1, true);
grid[i][j] = null;
bestScore = Math.min(score, bestScore);
}
}
}
return bestScore;
}
}
// Check winner for grid (used in minimax)
function checkWinnerGrid(grid) {
// Check rows
for (var i = 0; i < 3; i++) {
if (grid[i][0] && grid[i][0] === grid[i][1] && grid[i][1] === grid[i][2]) {
return grid[i][0];
}
}
// Check columns
for (var i = 0; i < 3; i++) {
if (grid[0][i] && grid[0][i] === grid[1][i] && grid[1][i] === grid[2][i]) {
return grid[0][i];
}
}
// Check diagonals
if (grid[0][0] && grid[0][0] === grid[1][1] && grid[1][1] === grid[2][2]) {
return grid[0][0];
}
if (grid[0][2] && grid[0][2] === grid[1][1] && grid[1][1] === grid[2][0]) {
return grid[0][2];
}
return null;
}
// Check if grid is full (used in minimax)
function isGridFull(grid) {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === null) return false;
}
}
return true;
}
// Handle game end
function handleGameEnd(winner) {
gameState = 'gameOver';
if (winner === 'X') {
// Player wins
LK.getSound('victory').play();
statusText.setText('Victory! Level ' + currentLevel + ' Complete!');
statusText.tint = 0x00ff00;
// Show victory banner
showVictoryBanner();
// Progress to next level
currentLevel++;
if (currentLevel > 10000) currentLevel = 10000;
storage.level = currentLevel;
// Reset for next level after delay
LK.setTimeout(function () {
resetGame();
}, 3000);
} else if (winner === 'O') {
// AI wins
LK.getSound('defeat').play();
statusText.setText('Defeat! Try Level ' + currentLevel + ' Again');
statusText.tint = 0xff0000;
// Reset after delay
LK.setTimeout(function () {
resetGame();
}, 2000);
} else {
// Draw
statusText.setText('Draw! Try Level ' + currentLevel + ' Again');
statusText.tint = 0xffaa00;
// Reset after delay
LK.setTimeout(function () {
resetGame();
}, 2000);
}
}
// Show victory banner
function showVictoryBanner() {
if (victoryBanner) {
game.removeChild(victoryBanner);
}
victoryBanner = new Container();
var bannerBg = LK.getAsset('cellHighlight', {
width: 800,
height: 200,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 1.5,
alpha: 0.8
});
bannerBg.tint = 0x00ff00;
victoryBanner.addChild(bannerBg);
var bannerText = new Text2('LEVEL ' + currentLevel + ' COMPLETE!', {
size: 80,
fill: 0xFFFFFF
});
bannerText.anchor.set(0.5, 0.5);
victoryBanner.addChild(bannerText);
victoryBanner.x = 2048 / 2;
victoryBanner.y = 2732 / 2 - 300;
victoryBanner.alpha = 0;
game.addChild(victoryBanner);
// Animate banner
tween(victoryBanner, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500
});
tween(victoryBanner, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
delay: 500
});
}
// Reset game for new round
function resetGame() {
gameState = 'playing';
currentPlayer = 'X';
if (victoryBanner) {
game.removeChild(victoryBanner);
victoryBanner = null;
}
board.reset();
calculateAIDifficulty();
levelText.setText('Level ' + currentLevel);
statusText.setText('Your Turn (X)');
statusText.tint = 0xff4444;
}
// Initialize everything
initializeUI();
initializeBoard();
calculateAIDifficulty();
// Game update loop
game.update = function () {
// RGB color cycling background
backgroundHue = (backgroundHue + colorSpeed) % 360;
var hueRad = backgroundHue * Math.PI / 180;
// Convert HSV to RGB for smooth color transitions
var r = Math.floor(Math.sin(hueRad) * 127 + 128);
var g = Math.floor(Math.sin(hueRad + 2.094) * 127 + 128); // 2.094 = 2π/3
var b = Math.floor(Math.sin(hueRad + 4.188) * 127 + 128); // 4.188 = 4π/3
// Combine RGB values into hex color
var rgbColor = r << 16 | g << 8 | b;
game.setBackgroundColor(rgbColor);
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var GridCell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.marker = null; // 'X', 'O', or null
self.markerGraphic = null;
// Create invisible clickable area
var clickArea = self.attachAsset('cellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.setMarker = function (type) {
if (self.marker !== null) return false;
self.marker = type;
if (type === 'X') {
self.markerGraphic = new Text2('X', {
size: 100,
fill: 0xff4444
});
self.markerGraphic.anchor.set(0.5, 0.5);
self.addChild(self.markerGraphic);
} else if (type === 'O') {
self.markerGraphic = new Text2('O', {
size: 100,
fill: 0x4444ff
});
self.markerGraphic.anchor.set(0.5, 0.5);
self.addChild(self.markerGraphic);
}
if (self.markerGraphic) {
self.markerGraphic.alpha = 0;
tween(self.markerGraphic, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
tween(self.markerGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
delay: 200
});
}
return true;
};
self.reset = function () {
if (self.markerGraphic) {
self.removeChild(self.markerGraphic);
self.markerGraphic = null;
}
self.marker = null;
};
self.highlight = function () {
clickArea.alpha = 0.3;
tween(clickArea, {
alpha: 0
}, {
duration: 300
});
};
self.down = function (x, y, obj) {
if (gameState === 'playing' && self.marker === null) {
self.highlight();
makePlayerMove(self.row, self.col);
}
};
return self;
});
var TicTacBoard = Container.expand(function () {
var self = Container.call(this);
self.grid = [];
self.cells = [];
// Initialize 3x3 grid
for (var i = 0; i < 3; i++) {
self.grid[i] = [];
for (var j = 0; j < 3; j++) {
self.grid[i][j] = null;
}
}
// Create visual grid lines - classic 4-line pattern extending full screen
// First vertical line (left)
var vLine1 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: 0,
height: 2732
});
// Second vertical line (right)
var vLine2 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 250,
y: 0,
height: 2732
});
// First horizontal line (top)
var hLine1 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -250,
width: 2048,
height: 8,
rotation: 0
});
// Second horizontal line (bottom)
var hLine2 = self.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 250,
width: 2048,
height: 8,
rotation: 0
});
// Create grid cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = new GridCell(row, col);
cell.x = col * 500 - 500;
cell.y = row * 500 - 500;
self.addChild(cell);
self.cells.push(cell);
}
}
self.placeMarker = function (row, col, marker) {
if (self.grid[row][col] !== null) return false;
self.grid[row][col] = marker;
var cell = self.cells[row * 3 + col];
return cell.setMarker(marker);
};
self.checkWinner = function () {
// Check rows
for (var i = 0; i < 3; i++) {
if (self.grid[i][0] && self.grid[i][0] === self.grid[i][1] && self.grid[i][1] === self.grid[i][2]) {
return {
winner: self.grid[i][0],
line: 'row',
index: i
};
}
}
// Check columns
for (var i = 0; i < 3; i++) {
if (self.grid[0][i] && self.grid[0][i] === self.grid[1][i] && self.grid[1][i] === self.grid[2][i]) {
return {
winner: self.grid[0][i],
line: 'col',
index: i
};
}
}
// Check diagonals
if (self.grid[0][0] && self.grid[0][0] === self.grid[1][1] && self.grid[1][1] === self.grid[2][2]) {
return {
winner: self.grid[0][0],
line: 'diag',
index: 0
};
}
if (self.grid[0][2] && self.grid[0][2] === self.grid[1][1] && self.grid[1][1] === self.grid[2][0]) {
return {
winner: self.grid[0][2],
line: 'diag',
index: 1
};
}
return null;
};
self.isFull = function () {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (self.grid[i][j] === null) return false;
}
}
return true;
};
self.reset = function () {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
self.grid[i][j] = null;
}
}
for (var i = 0; i < self.cells.length; i++) {
self.cells[i].reset();
}
};
self.getEmptyCells = function () {
var empty = [];
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (self.grid[i][j] === null) {
empty.push({
row: i,
col: j
});
}
}
}
return empty;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// RGB background color variables
var backgroundHue = 0;
var colorSpeed = 1;
// Game state variables
var gameState = 'playing'; // 'playing', 'gameOver', 'victory'
var currentPlayer = 'X'; // Player is always X
var currentLevel = storage.level || 1;
var board;
var levelText;
var statusText;
var victoryBanner;
var aiDifficulty;
// Initialize UI
function initializeUI() {
levelText = new Text2('Level ' + currentLevel, {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
levelText.y = 100;
statusText = new Text2('Your Turn (X)', {
size: 50,
fill: 0xFFFF00
});
statusText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(statusText);
statusText.y = -200;
}
// Initialize game board
function initializeBoard() {
board = new TicTacBoard();
board.x = 2048 / 2;
board.y = 2732 / 2;
game.addChild(board);
}
// Calculate AI difficulty based on level
function calculateAIDifficulty() {
if (currentLevel <= 10) {
aiDifficulty = 0.1; // Very easy
} else if (currentLevel <= 50) {
aiDifficulty = 0.3; // Easy
} else if (currentLevel <= 200) {
aiDifficulty = 0.5; // Medium
} else if (currentLevel <= 1000) {
aiDifficulty = 0.7; // Hard
} else {
aiDifficulty = 0.9; // Very hard
}
}
// Player makes a move
function makePlayerMove(row, col) {
if (gameState !== 'playing' || currentPlayer !== 'X') return;
if (board.placeMarker(row, col, 'X')) {
LK.getSound('placeMarker').play();
var result = board.checkWinner();
if (result) {
handleGameEnd(result.winner);
return;
}
if (board.isFull()) {
handleGameEnd('draw');
return;
}
currentPlayer = 'O';
statusText.setText('AI Turn (O)');
statusText.tint = 0x4444ff;
// AI makes move after delay
LK.setTimeout(function () {
makeAIMove();
}, 500);
}
}
// AI makes a move
function makeAIMove() {
if (gameState !== 'playing' || currentPlayer !== 'O') return;
var move;
if (Math.random() < aiDifficulty) {
move = getBestAIMove();
} else {
move = getRandomAIMove();
}
if (move && board.placeMarker(move.row, move.col, 'O')) {
LK.getSound('placeMarker').play();
var result = board.checkWinner();
if (result) {
handleGameEnd(result.winner);
return;
}
if (board.isFull()) {
handleGameEnd('draw');
return;
}
currentPlayer = 'X';
statusText.setText('Your Turn (X)');
statusText.tint = 0xff4444;
}
}
// Get best AI move using minimax
function getBestAIMove() {
var bestScore = -Infinity;
var bestMove = null;
var emptyCells = board.getEmptyCells();
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
board.grid[cell.row][cell.col] = 'O';
var score = minimax(board.grid, 0, false);
board.grid[cell.row][cell.col] = null;
if (score > bestScore) {
bestScore = score;
bestMove = cell;
}
}
return bestMove;
}
// Get random AI move
function getRandomAIMove() {
var emptyCells = board.getEmptyCells();
if (emptyCells.length > 0) {
var randomIndex = Math.floor(Math.random() * emptyCells.length);
return emptyCells[randomIndex];
}
return null;
}
// Minimax algorithm for AI
function minimax(grid, depth, isMaximizing) {
var result = checkWinnerGrid(grid);
if (result === 'O') return 10 - depth;
if (result === 'X') return depth - 10;
if (isGridFull(grid)) return 0;
if (isMaximizing) {
var bestScore = -Infinity;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === null) {
grid[i][j] = 'O';
var score = minimax(grid, depth + 1, false);
grid[i][j] = null;
bestScore = Math.max(score, bestScore);
}
}
}
return bestScore;
} else {
var bestScore = Infinity;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === null) {
grid[i][j] = 'X';
var score = minimax(grid, depth + 1, true);
grid[i][j] = null;
bestScore = Math.min(score, bestScore);
}
}
}
return bestScore;
}
}
// Check winner for grid (used in minimax)
function checkWinnerGrid(grid) {
// Check rows
for (var i = 0; i < 3; i++) {
if (grid[i][0] && grid[i][0] === grid[i][1] && grid[i][1] === grid[i][2]) {
return grid[i][0];
}
}
// Check columns
for (var i = 0; i < 3; i++) {
if (grid[0][i] && grid[0][i] === grid[1][i] && grid[1][i] === grid[2][i]) {
return grid[0][i];
}
}
// Check diagonals
if (grid[0][0] && grid[0][0] === grid[1][1] && grid[1][1] === grid[2][2]) {
return grid[0][0];
}
if (grid[0][2] && grid[0][2] === grid[1][1] && grid[1][1] === grid[2][0]) {
return grid[0][2];
}
return null;
}
// Check if grid is full (used in minimax)
function isGridFull(grid) {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === null) return false;
}
}
return true;
}
// Handle game end
function handleGameEnd(winner) {
gameState = 'gameOver';
if (winner === 'X') {
// Player wins
LK.getSound('victory').play();
statusText.setText('Victory! Level ' + currentLevel + ' Complete!');
statusText.tint = 0x00ff00;
// Show victory banner
showVictoryBanner();
// Progress to next level
currentLevel++;
if (currentLevel > 10000) currentLevel = 10000;
storage.level = currentLevel;
// Reset for next level after delay
LK.setTimeout(function () {
resetGame();
}, 3000);
} else if (winner === 'O') {
// AI wins
LK.getSound('defeat').play();
statusText.setText('Defeat! Try Level ' + currentLevel + ' Again');
statusText.tint = 0xff0000;
// Reset after delay
LK.setTimeout(function () {
resetGame();
}, 2000);
} else {
// Draw
statusText.setText('Draw! Try Level ' + currentLevel + ' Again');
statusText.tint = 0xffaa00;
// Reset after delay
LK.setTimeout(function () {
resetGame();
}, 2000);
}
}
// Show victory banner
function showVictoryBanner() {
if (victoryBanner) {
game.removeChild(victoryBanner);
}
victoryBanner = new Container();
var bannerBg = LK.getAsset('cellHighlight', {
width: 800,
height: 200,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 1.5,
alpha: 0.8
});
bannerBg.tint = 0x00ff00;
victoryBanner.addChild(bannerBg);
var bannerText = new Text2('LEVEL ' + currentLevel + ' COMPLETE!', {
size: 80,
fill: 0xFFFFFF
});
bannerText.anchor.set(0.5, 0.5);
victoryBanner.addChild(bannerText);
victoryBanner.x = 2048 / 2;
victoryBanner.y = 2732 / 2 - 300;
victoryBanner.alpha = 0;
game.addChild(victoryBanner);
// Animate banner
tween(victoryBanner, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500
});
tween(victoryBanner, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
delay: 500
});
}
// Reset game for new round
function resetGame() {
gameState = 'playing';
currentPlayer = 'X';
if (victoryBanner) {
game.removeChild(victoryBanner);
victoryBanner = null;
}
board.reset();
calculateAIDifficulty();
levelText.setText('Level ' + currentLevel);
statusText.setText('Your Turn (X)');
statusText.tint = 0xff4444;
}
// Initialize everything
initializeUI();
initializeBoard();
calculateAIDifficulty();
// Game update loop
game.update = function () {
// RGB color cycling background
backgroundHue = (backgroundHue + colorSpeed) % 360;
var hueRad = backgroundHue * Math.PI / 180;
// Convert HSV to RGB for smooth color transitions
var r = Math.floor(Math.sin(hueRad) * 127 + 128);
var g = Math.floor(Math.sin(hueRad + 2.094) * 127 + 128); // 2.094 = 2π/3
var b = Math.floor(Math.sin(hueRad + 4.188) * 127 + 128); // 4.188 = 4π/3
// Combine RGB values into hex color
var rgbColor = r << 16 | g << 8 | b;
game.setBackgroundColor(rgbColor);
};