/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { scores: [] }); /**** * Classes ****/ var GridCell = Container.expand(function (gridX, gridY) { var self = Container.call(this); self.gridX = gridX; self.gridY = gridY; self.value = 0; self.isHighlighted = false; var borderBg = self.attachAsset('gridBorder', { anchorX: 0.5, anchorY: 0.5 }); borderBg.alpha = 1; // Ensure border is fully visible borderBg.tint = 0xffffff; // Ensure white color var cellBg = self.attachAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); var highlightBg = self.attachAsset('gridCellHighlight', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.valueText = new Text2('', { size: 60, fill: 0xFFFFFF }); self.valueText.anchor.set(0.5, 0.5); self.addChild(self.valueText); self.highlight = function () { if (!self.isHighlighted) { self.isHighlighted = true; tween(highlightBg, { alpha: 0.7 }, { duration: 200 }); } }; self.unhighlight = function () { if (self.isHighlighted) { self.isHighlighted = false; tween(highlightBg, { alpha: 0 }, { duration: 200 }); } }; self.setValue = function (newValue) { self.value = newValue; if (self.value > 0) { self.valueText.setText(self.value.toString()); } else { self.valueText.setText(''); } }; self.down = function (x, y, obj) { if (gameState === 'playing') { handleCellClick(self.gridX, self.gridY); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Create space background with stars, nebulas, planets and asteroids for (var i = 0; i < 300; i++) { var star = game.addChild(LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5 })); star.x = Math.random() * 2048; star.y = Math.random() * 2732; star.alpha = Math.random() * 0.8 + 0.2; } // Add nebulas for depth for (var i = 0; i < 15; i++) { var nebula = game.addChild(LK.getAsset('nebula', { anchorX: 0.5, anchorY: 0.5 })); nebula.x = Math.random() * 2048; nebula.y = Math.random() * 2732; nebula.alpha = Math.random() * 0.3 + 0.1; nebula.scaleX = Math.random() * 2 + 0.5; nebula.scaleY = Math.random() * 2 + 0.5; var colors = [0x4B0082, 0x8A2BE2, 0x9932CC, 0x483D8B]; nebula.tint = colors[Math.floor(Math.random() * colors.length)]; } // Add distant planets for (var i = 0; i < 8; i++) { var planet = game.addChild(LK.getAsset('planet', { anchorX: 0.5, anchorY: 0.5 })); planet.x = Math.random() * 2048; planet.y = Math.random() * 2732; planet.alpha = Math.random() * 0.6 + 0.3; planet.scaleX = Math.random() * 1.5 + 0.5; planet.scaleY = Math.random() * 1.5 + 0.5; var planetColors = [0x8B4513, 0xFF4500, 0x32CD32, 0x4169E1, 0xDC143C]; planet.tint = planetColors[Math.floor(Math.random() * planetColors.length)]; } // Add floating asteroids for (var i = 0; i < 25; i++) { var asteroid = game.addChild(LK.getAsset('asteroid', { anchorX: 0.5, anchorY: 0.5 })); asteroid.x = Math.random() * 2048; asteroid.y = Math.random() * 2732; asteroid.alpha = Math.random() * 0.7 + 0.2; asteroid.scaleX = Math.random() * 1.2 + 0.3; asteroid.scaleY = Math.random() * 1.2 + 0.3; asteroid.rotation = Math.random() * Math.PI * 2; } // Game state var gameState = 'playing'; // 'playing', 'won', 'lost' var playerX = 0; var playerY = 0; var totalSum = 0; var moveCount = 0; var maxMoves = 100; // Grid setup var gridSize = 10; var cellSize = 180; var gridStartX = (2048 - gridSize * cellSize) / 2; var gridStartY = 200; var grid = []; // UI elements var totalText = new Text2('Total: 0', { size: 80, fill: 0xFFFFFF }); totalText.anchor.set(0.5, 0); totalText.x = 2048 / 2; totalText.y = 50; game.addChild(totalText); var movesText = new Text2('Moves: 0/100', { size: 60, fill: 0xFFFFFF }); movesText.anchor.set(0.5, 0); movesText.x = 2048 / 2; movesText.y = 2600; game.addChild(movesText); var instructionText = new Text2('Click to move! Reach 100 moves to win!', { size: 50, fill: 0xFFFF00 }); instructionText.anchor.set(0.5, 1); instructionText.x = 2048 / 2; instructionText.y = 2700; game.addChild(instructionText); // Create grid for (var x = 0; x < gridSize; x++) { grid[x] = []; for (var y = 0; y < gridSize; y++) { var cell = new GridCell(x, y); cell.x = gridStartX + x * cellSize + cellSize / 2; cell.y = gridStartY + y * cellSize + cellSize / 2; grid[x][y] = cell; game.addChild(cell); // Ensure border is always on top and visible cell.children[0].alpha = 1; cell.children[0].tint = 0xffffff; } } // Player indicator var playerIndicator = game.addChild(LK.getAsset('playerIndicator', { anchorX: 0.5, anchorY: 0.5 })); function updatePlayerPosition() { playerIndicator.x = grid[playerX][playerY].x; playerIndicator.y = grid[playerX][playerY].y - 60; } function updateValidMoves() { // Clear all highlights for (var x = 0; x < gridSize; x++) { for (var y = 0; y < gridSize; y++) { grid[x][y].unhighlight(); } } // If this is the first move (moveCount is 0), highlight all empty cells if (moveCount === 0) { for (var x = 0; x < gridSize; x++) { for (var y = 0; y < gridSize; y++) { if (grid[x][y].value === 0) { grid[x][y].highlight(); } } } } else { // Highlight valid moves from current position, but only if they are empty (value === 0) var validMoves = getValidMoves(playerX, playerY); for (var i = 0; i < validMoves.length; i++) { var move = validMoves[i]; if (grid[move.x][move.y].value === 0) { grid[move.x][move.y].highlight(); } } } } function getValidMoves(x, y) { var moves = []; // 3 squares orthogonal moves var orthogonalMoves = [{ x: x + 3, y: y }, // right 3 { x: x - 3, y: y }, // left 3 { x: x, y: y + 3 }, // down 3 { x: x, y: y - 3 } // up 3 ]; // 2 square diagonal moves var diagonalMoves = [{ x: x + 2, y: y + 2 }, // down-right { x: x + 2, y: y - 2 }, // up-right { x: x - 2, y: y + 2 }, // down-left { x: x - 2, y: y - 2 } // up-left ]; var allMoves = orthogonalMoves.concat(diagonalMoves); for (var i = 0; i < allMoves.length; i++) { var move = allMoves[i]; if (move.x >= 0 && move.x < gridSize && move.y >= 0 && move.y < gridSize) { moves.push(move); } } return moves; } function isValidMove(fromX, fromY, toX, toY) { var validMoves = getValidMoves(fromX, fromY); for (var i = 0; i < validMoves.length; i++) { var move = validMoves[i]; if (move.x === toX && move.y === toY) { return true; } } return false; } function handleCellClick(clickX, clickY) { if (gameState !== 'playing') { return; } // Check if cell has already been clicked (has a value) if (grid[clickX][clickY].value > 0) { // Cell already clicked, play invalid sound and flash red LK.getSound('invalid').play(); LK.effects.flashObject(grid[clickX][clickY], 0xff0000, 500); return; } if (moveCount === 0 || isValidMove(playerX, playerY, clickX, clickY)) { // Valid move LK.getSound('move').play(); playerX = clickX; playerY = clickY; moveCount++; // Set the cell value to the current move count (1, 2, 3...100) grid[clickX][clickY].setValue(moveCount); // Update total totalSum = 0; for (var x = 0; x < gridSize; x++) { for (var y = 0; y < gridSize; y++) { totalSum += grid[x][y].value; } } updatePlayerPosition(); updateValidMoves(); updateUI(); // Check win condition if (moveCount >= 100) { gameState = 'won'; saveScore(); showVictoryScreen(); } else { // Check if there are any valid moves left (empty cells that can be reached) var validMoves = getValidMoves(playerX, playerY); var hasValidMoves = false; for (var i = 0; i < validMoves.length; i++) { if (grid[validMoves[i].x][validMoves[i].y].value === 0) { hasValidMoves = true; break; } } if (!hasValidMoves) { gameState = 'lost'; saveScore(); showLoseScreen(); } } } else { // Invalid move LK.getSound('invalid').play(); LK.effects.flashObject(grid[clickX][clickY], 0xff0000, 500); } } function updateUI() { totalText.setText('Total: ' + totalSum); movesText.setText('Moves: ' + moveCount + '/' + maxMoves); if (moveCount >= 100) { totalText.fill = 0x00ff00; } else if (moveCount >= maxMoves * 0.8) { movesText.style = { fill: 0xff6600 }; } } function saveScore() { // Ensure storage.scores is initialized as an array var scores = storage.scores; if (!scores || !Array.isArray(scores)) { scores = []; try { storage.scores = scores; } catch (e) { // If storage assignment fails, continue with local array console.log('Failed to initialize scores in storage'); } } var newScore = { score: totalSum, moves: moveCount, totalSum: totalSum, timestamp: Date.now() }; // Safely push the new score try { scores.push(newScore); } catch (e) { // If push fails, create new array with the score scores = [newScore]; try { storage.scores = scores; } catch (e2) { // If storage assignment fails, continue without saving console.log('Failed to save scores to storage'); } } // Sort by highest total score descending scores.sort(function (a, b) { return b.totalSum - a.totalSum; }); // Keep only top 10 if (scores.length > 10) { scores = scores.slice(0, 10); try { storage.scores = scores; } catch (e) { // If storage assignment fails, continue without saving console.log('Failed to save scores to storage'); } } } function showVictoryScreen() { // Create victory display positioned in center of screen var victoryContainer = new Container(); victoryContainer.x = 2048 / 2; victoryContainer.y = 2732 / 2; // Add full screen cream background var background = victoryContainer.attachAsset('fullScreenCreamBackground', { anchorX: 0.5, anchorY: 0.5 }); // Victory title var victoryText = new Text2('Victory!', { size: 160, fill: 0x00FF00, font: "'Arial', sans-serif" }); victoryText.anchor.set(0.5, 0.5); victoryText.y = -100; victoryContainer.addChild(victoryText); // Genius message var geniusText = new Text2('You are a genius.', { size: 120, fill: 0x000000, font: "'Arial', sans-serif" }); geniusText.anchor.set(0.5, 0.5); geniusText.y = 0; victoryContainer.addChild(geniusText); // Total score display var totalScoreText = new Text2('Total Score: ' + totalSum, { size: 100, fill: 0x000000, font: "'Arial', sans-serif" }); totalScoreText.anchor.set(0.5, 0.5); totalScoreText.y = 80; victoryContainer.addChild(totalScoreText); game.addChild(victoryContainer); // Show leaderboard after brief delay LK.setTimeout(function () { showLeaderboard(); }, 3000); } function showLoseScreen() { // Create lose display positioned in center of screen var loseContainer = new Container(); loseContainer.x = 2048 / 2; loseContainer.y = 2732 / 2; // Add full screen cream background var background = loseContainer.attachAsset('fullScreenCreamBackground', { anchorX: 0.5, anchorY: 0.5 }); // Lose title var loseText = new Text2('Lose', { size: 160, fill: 0xFF0000, font: "'Arial', sans-serif" }); loseText.anchor.set(0.5, 0.5); loseText.y = -50; loseContainer.addChild(loseText); // Total score display prominently var totalScoreText = new Text2('Total Score: ' + totalSum, { size: 120, fill: 0x000000, font: "'Arial', sans-serif" }); totalScoreText.anchor.set(0.5, 0.5); totalScoreText.y = 50; loseContainer.addChild(totalScoreText); game.addChild(loseContainer); // Show leaderboard after brief delay LK.setTimeout(function () { showLeaderboard(); }, 3000); } function showLeaderboard() { // Create leaderboard display var leaderboardContainer = new Container(); leaderboardContainer.x = 2048 / 2; leaderboardContainer.y = 2732 / 2; // Add full screen cream background var background = leaderboardContainer.attachAsset('fullScreenCreamBackground', { anchorX: 0.5, anchorY: 0.5 }); // Get scores from storage for leaderboard var scores = storage.scores || []; var currentScore = totalSum; var playerRank = scores.length + 1; // Find player's rank based on total score for (var i = 0; i < scores.length; i++) { if (currentScore > scores[i].totalSum) { playerRank = i + 1; break; } } // Leaderboard title var leaderboardTitle = new Text2('Total Score Rankings', { size: 100, fill: 0x000000, font: "'Arial', sans-serif" }); leaderboardTitle.anchor.set(0.5, 0.5); leaderboardTitle.y = -400; leaderboardContainer.addChild(leaderboardTitle); // Display top 10 scores var yOffset = -320; var maxDisplay = Math.min(10, scores.length); for (var i = 0; i < maxDisplay; i++) { var rankDisplay = i + 1 + '.'; var scoreDisplay = 'Total: ' + scores[i].totalSum + ' (Moves: ' + scores[i].moves + ')'; var scoreText = new Text2(rankDisplay + ' ' + scoreDisplay, { size: 85, fill: 0x000000, font: "'Arial', sans-serif" }); scoreText.anchor.set(0.5, 0.5); scoreText.y = yOffset; leaderboardContainer.addChild(scoreText); yOffset += 60; } // If there are fewer than 10 scores, show empty slots for remaining positions for (var i = scores.length; i < 10; i++) { var rankDisplay = i + 1 + '.'; var scoreDisplay = '---'; var emptySlotText = new Text2(rankDisplay + ' ' + scoreDisplay, { size: 65, fill: 0x888888, font: "'Arial', sans-serif" }); emptySlotText.anchor.set(0.5, 0.5); emptySlotText.y = yOffset; leaderboardContainer.addChild(emptySlotText); yOffset += 60; } // Player rank var rankText = new Text2('Your Rank: #' + playerRank, { size: 70, fill: 0xFF0000, font: "'Arial', sans-serif" }); rankText.anchor.set(0.5, 0.5); rankText.y = yOffset + 60; leaderboardContainer.addChild(rankText); // Current player score var currentScoreText = new Text2('Your Total Score: ' + currentScore, { size: 65, fill: 0x0000FF, font: "'Arial', sans-serif" }); currentScoreText.anchor.set(0.5, 0.5); currentScoreText.y = yOffset + 120; leaderboardContainer.addChild(currentScoreText); game.addChild(leaderboardContainer); // Auto trigger game over after showing the leaderboard LK.setTimeout(function () { if (gameState === 'won') { LK.showYouWin(); } else { LK.showGameOver(); } }, 12000); } function showFinalScore() { // Create final score display positioned over the center of the grid var finalScoreContainer = new Container(); finalScoreContainer.x = 2048 / 2; finalScoreContainer.y = 2732 / 2; // Add full screen cream background var background = finalScoreContainer.attachAsset('fullScreenCreamBackground', { anchorX: 0.5, anchorY: 0.5 }); // Get scores from storage for leaderboard var scores = storage.scores || []; var currentScore = moveCount; var playerRank = scores.length + 1; // Find player's rank for (var i = 0; i < scores.length; i++) { if (currentScore > scores[i].score) { playerRank = i + 1; break; } } // Congratulations title var congratsText = new Text2('Congratulations!', { size: 100, fill: 0x000000, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); congratsText.anchor.set(0.5, 0.5); congratsText.y = -350; finalScoreContainer.addChild(congratsText); // Game completion message var completionText = new Text2("You've completed the game, but there are no more valid moves left.", { size: 50, fill: 0x000000, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); completionText.anchor.set(0.5, 0.5); completionText.y = -280; finalScoreContainer.addChild(completionText); // Final score message var finalScoreText = new Text2('Your final score is ' + currentScore + '.', { size: 65, fill: 0x000000, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.y = -220; finalScoreContainer.addChild(finalScoreText); // Leaderboard title var leaderboardTitle = new Text2("Here's how you rank among other players:", { size: 55, fill: 0x000000, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); leaderboardTitle.anchor.set(0.5, 0.5); leaderboardTitle.y = -150; finalScoreContainer.addChild(leaderboardTitle); // Display top scores with enhanced leaderboard var yOffset = -80; var maxDisplay = Math.min(10, scores.length); for (var i = 0; i < maxDisplay; i++) { var rankDisplay = i + 1 + '.'; var scoreDisplay = 'Score: ' + scores[i].score + ' (Moves: ' + scores[i].moves + ')'; var scoreText = new Text2(rankDisplay + ' ' + scoreDisplay, { size: 38, fill: 0x000000, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); scoreText.anchor.set(0.5, 0.5); scoreText.y = yOffset; finalScoreContainer.addChild(scoreText); yOffset += 35; } // Player rank var rankText = new Text2('Your position: ' + playerRank, { size: 60, fill: 0xff0000, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); rankText.anchor.set(0.5, 0.5); rankText.y = yOffset + 40; finalScoreContainer.addChild(rankText); // Display the highest number reached prominently in white color as requested var highestNumberText = new Text2('Score ' + moveCount.toString(), { size: 140, fill: 0xFFFFFF, font: "'Arial Black', 'Arial-Black', Impact, sans-serif" }); highestNumberText.anchor.set(0.5, 0.5); highestNumberText.y = 0; // Add the main score text centered prominently finalScoreContainer.addChild(highestNumberText); game.addChild(finalScoreContainer); // Auto trigger game over after showing the leaderboard LK.setTimeout(function () { LK.showGameOver(); }, 8000); } // Initialize game updatePlayerPosition(); updateValidMoves(); updateUI();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
scores: []
});
/****
* Classes
****/
var GridCell = Container.expand(function (gridX, gridY) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
self.value = 0;
self.isHighlighted = false;
var borderBg = self.attachAsset('gridBorder', {
anchorX: 0.5,
anchorY: 0.5
});
borderBg.alpha = 1; // Ensure border is fully visible
borderBg.tint = 0xffffff; // Ensure white color
var cellBg = self.attachAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
var highlightBg = self.attachAsset('gridCellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.valueText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
self.valueText.anchor.set(0.5, 0.5);
self.addChild(self.valueText);
self.highlight = function () {
if (!self.isHighlighted) {
self.isHighlighted = true;
tween(highlightBg, {
alpha: 0.7
}, {
duration: 200
});
}
};
self.unhighlight = function () {
if (self.isHighlighted) {
self.isHighlighted = false;
tween(highlightBg, {
alpha: 0
}, {
duration: 200
});
}
};
self.setValue = function (newValue) {
self.value = newValue;
if (self.value > 0) {
self.valueText.setText(self.value.toString());
} else {
self.valueText.setText('');
}
};
self.down = function (x, y, obj) {
if (gameState === 'playing') {
handleCellClick(self.gridX, self.gridY);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Create space background with stars, nebulas, planets and asteroids
for (var i = 0; i < 300; i++) {
var star = game.addChild(LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
}));
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.alpha = Math.random() * 0.8 + 0.2;
}
// Add nebulas for depth
for (var i = 0; i < 15; i++) {
var nebula = game.addChild(LK.getAsset('nebula', {
anchorX: 0.5,
anchorY: 0.5
}));
nebula.x = Math.random() * 2048;
nebula.y = Math.random() * 2732;
nebula.alpha = Math.random() * 0.3 + 0.1;
nebula.scaleX = Math.random() * 2 + 0.5;
nebula.scaleY = Math.random() * 2 + 0.5;
var colors = [0x4B0082, 0x8A2BE2, 0x9932CC, 0x483D8B];
nebula.tint = colors[Math.floor(Math.random() * colors.length)];
}
// Add distant planets
for (var i = 0; i < 8; i++) {
var planet = game.addChild(LK.getAsset('planet', {
anchorX: 0.5,
anchorY: 0.5
}));
planet.x = Math.random() * 2048;
planet.y = Math.random() * 2732;
planet.alpha = Math.random() * 0.6 + 0.3;
planet.scaleX = Math.random() * 1.5 + 0.5;
planet.scaleY = Math.random() * 1.5 + 0.5;
var planetColors = [0x8B4513, 0xFF4500, 0x32CD32, 0x4169E1, 0xDC143C];
planet.tint = planetColors[Math.floor(Math.random() * planetColors.length)];
}
// Add floating asteroids
for (var i = 0; i < 25; i++) {
var asteroid = game.addChild(LK.getAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
}));
asteroid.x = Math.random() * 2048;
asteroid.y = Math.random() * 2732;
asteroid.alpha = Math.random() * 0.7 + 0.2;
asteroid.scaleX = Math.random() * 1.2 + 0.3;
asteroid.scaleY = Math.random() * 1.2 + 0.3;
asteroid.rotation = Math.random() * Math.PI * 2;
}
// Game state
var gameState = 'playing'; // 'playing', 'won', 'lost'
var playerX = 0;
var playerY = 0;
var totalSum = 0;
var moveCount = 0;
var maxMoves = 100;
// Grid setup
var gridSize = 10;
var cellSize = 180;
var gridStartX = (2048 - gridSize * cellSize) / 2;
var gridStartY = 200;
var grid = [];
// UI elements
var totalText = new Text2('Total: 0', {
size: 80,
fill: 0xFFFFFF
});
totalText.anchor.set(0.5, 0);
totalText.x = 2048 / 2;
totalText.y = 50;
game.addChild(totalText);
var movesText = new Text2('Moves: 0/100', {
size: 60,
fill: 0xFFFFFF
});
movesText.anchor.set(0.5, 0);
movesText.x = 2048 / 2;
movesText.y = 2600;
game.addChild(movesText);
var instructionText = new Text2('Click to move! Reach 100 moves to win!', {
size: 50,
fill: 0xFFFF00
});
instructionText.anchor.set(0.5, 1);
instructionText.x = 2048 / 2;
instructionText.y = 2700;
game.addChild(instructionText);
// Create grid
for (var x = 0; x < gridSize; x++) {
grid[x] = [];
for (var y = 0; y < gridSize; y++) {
var cell = new GridCell(x, y);
cell.x = gridStartX + x * cellSize + cellSize / 2;
cell.y = gridStartY + y * cellSize + cellSize / 2;
grid[x][y] = cell;
game.addChild(cell);
// Ensure border is always on top and visible
cell.children[0].alpha = 1;
cell.children[0].tint = 0xffffff;
}
}
// Player indicator
var playerIndicator = game.addChild(LK.getAsset('playerIndicator', {
anchorX: 0.5,
anchorY: 0.5
}));
function updatePlayerPosition() {
playerIndicator.x = grid[playerX][playerY].x;
playerIndicator.y = grid[playerX][playerY].y - 60;
}
function updateValidMoves() {
// Clear all highlights
for (var x = 0; x < gridSize; x++) {
for (var y = 0; y < gridSize; y++) {
grid[x][y].unhighlight();
}
}
// If this is the first move (moveCount is 0), highlight all empty cells
if (moveCount === 0) {
for (var x = 0; x < gridSize; x++) {
for (var y = 0; y < gridSize; y++) {
if (grid[x][y].value === 0) {
grid[x][y].highlight();
}
}
}
} else {
// Highlight valid moves from current position, but only if they are empty (value === 0)
var validMoves = getValidMoves(playerX, playerY);
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (grid[move.x][move.y].value === 0) {
grid[move.x][move.y].highlight();
}
}
}
}
function getValidMoves(x, y) {
var moves = [];
// 3 squares orthogonal moves
var orthogonalMoves = [{
x: x + 3,
y: y
},
// right 3
{
x: x - 3,
y: y
},
// left 3
{
x: x,
y: y + 3
},
// down 3
{
x: x,
y: y - 3
} // up 3
];
// 2 square diagonal moves
var diagonalMoves = [{
x: x + 2,
y: y + 2
},
// down-right
{
x: x + 2,
y: y - 2
},
// up-right
{
x: x - 2,
y: y + 2
},
// down-left
{
x: x - 2,
y: y - 2
} // up-left
];
var allMoves = orthogonalMoves.concat(diagonalMoves);
for (var i = 0; i < allMoves.length; i++) {
var move = allMoves[i];
if (move.x >= 0 && move.x < gridSize && move.y >= 0 && move.y < gridSize) {
moves.push(move);
}
}
return moves;
}
function isValidMove(fromX, fromY, toX, toY) {
var validMoves = getValidMoves(fromX, fromY);
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (move.x === toX && move.y === toY) {
return true;
}
}
return false;
}
function handleCellClick(clickX, clickY) {
if (gameState !== 'playing') {
return;
}
// Check if cell has already been clicked (has a value)
if (grid[clickX][clickY].value > 0) {
// Cell already clicked, play invalid sound and flash red
LK.getSound('invalid').play();
LK.effects.flashObject(grid[clickX][clickY], 0xff0000, 500);
return;
}
if (moveCount === 0 || isValidMove(playerX, playerY, clickX, clickY)) {
// Valid move
LK.getSound('move').play();
playerX = clickX;
playerY = clickY;
moveCount++;
// Set the cell value to the current move count (1, 2, 3...100)
grid[clickX][clickY].setValue(moveCount);
// Update total
totalSum = 0;
for (var x = 0; x < gridSize; x++) {
for (var y = 0; y < gridSize; y++) {
totalSum += grid[x][y].value;
}
}
updatePlayerPosition();
updateValidMoves();
updateUI();
// Check win condition
if (moveCount >= 100) {
gameState = 'won';
saveScore();
showVictoryScreen();
} else {
// Check if there are any valid moves left (empty cells that can be reached)
var validMoves = getValidMoves(playerX, playerY);
var hasValidMoves = false;
for (var i = 0; i < validMoves.length; i++) {
if (grid[validMoves[i].x][validMoves[i].y].value === 0) {
hasValidMoves = true;
break;
}
}
if (!hasValidMoves) {
gameState = 'lost';
saveScore();
showLoseScreen();
}
}
} else {
// Invalid move
LK.getSound('invalid').play();
LK.effects.flashObject(grid[clickX][clickY], 0xff0000, 500);
}
}
function updateUI() {
totalText.setText('Total: ' + totalSum);
movesText.setText('Moves: ' + moveCount + '/' + maxMoves);
if (moveCount >= 100) {
totalText.fill = 0x00ff00;
} else if (moveCount >= maxMoves * 0.8) {
movesText.style = {
fill: 0xff6600
};
}
}
function saveScore() {
// Ensure storage.scores is initialized as an array
var scores = storage.scores;
if (!scores || !Array.isArray(scores)) {
scores = [];
try {
storage.scores = scores;
} catch (e) {
// If storage assignment fails, continue with local array
console.log('Failed to initialize scores in storage');
}
}
var newScore = {
score: totalSum,
moves: moveCount,
totalSum: totalSum,
timestamp: Date.now()
};
// Safely push the new score
try {
scores.push(newScore);
} catch (e) {
// If push fails, create new array with the score
scores = [newScore];
try {
storage.scores = scores;
} catch (e2) {
// If storage assignment fails, continue without saving
console.log('Failed to save scores to storage');
}
}
// Sort by highest total score descending
scores.sort(function (a, b) {
return b.totalSum - a.totalSum;
});
// Keep only top 10
if (scores.length > 10) {
scores = scores.slice(0, 10);
try {
storage.scores = scores;
} catch (e) {
// If storage assignment fails, continue without saving
console.log('Failed to save scores to storage');
}
}
}
function showVictoryScreen() {
// Create victory display positioned in center of screen
var victoryContainer = new Container();
victoryContainer.x = 2048 / 2;
victoryContainer.y = 2732 / 2;
// Add full screen cream background
var background = victoryContainer.attachAsset('fullScreenCreamBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Victory title
var victoryText = new Text2('Victory!', {
size: 160,
fill: 0x00FF00,
font: "'Arial', sans-serif"
});
victoryText.anchor.set(0.5, 0.5);
victoryText.y = -100;
victoryContainer.addChild(victoryText);
// Genius message
var geniusText = new Text2('You are a genius.', {
size: 120,
fill: 0x000000,
font: "'Arial', sans-serif"
});
geniusText.anchor.set(0.5, 0.5);
geniusText.y = 0;
victoryContainer.addChild(geniusText);
// Total score display
var totalScoreText = new Text2('Total Score: ' + totalSum, {
size: 100,
fill: 0x000000,
font: "'Arial', sans-serif"
});
totalScoreText.anchor.set(0.5, 0.5);
totalScoreText.y = 80;
victoryContainer.addChild(totalScoreText);
game.addChild(victoryContainer);
// Show leaderboard after brief delay
LK.setTimeout(function () {
showLeaderboard();
}, 3000);
}
function showLoseScreen() {
// Create lose display positioned in center of screen
var loseContainer = new Container();
loseContainer.x = 2048 / 2;
loseContainer.y = 2732 / 2;
// Add full screen cream background
var background = loseContainer.attachAsset('fullScreenCreamBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Lose title
var loseText = new Text2('Lose', {
size: 160,
fill: 0xFF0000,
font: "'Arial', sans-serif"
});
loseText.anchor.set(0.5, 0.5);
loseText.y = -50;
loseContainer.addChild(loseText);
// Total score display prominently
var totalScoreText = new Text2('Total Score: ' + totalSum, {
size: 120,
fill: 0x000000,
font: "'Arial', sans-serif"
});
totalScoreText.anchor.set(0.5, 0.5);
totalScoreText.y = 50;
loseContainer.addChild(totalScoreText);
game.addChild(loseContainer);
// Show leaderboard after brief delay
LK.setTimeout(function () {
showLeaderboard();
}, 3000);
}
function showLeaderboard() {
// Create leaderboard display
var leaderboardContainer = new Container();
leaderboardContainer.x = 2048 / 2;
leaderboardContainer.y = 2732 / 2;
// Add full screen cream background
var background = leaderboardContainer.attachAsset('fullScreenCreamBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Get scores from storage for leaderboard
var scores = storage.scores || [];
var currentScore = totalSum;
var playerRank = scores.length + 1;
// Find player's rank based on total score
for (var i = 0; i < scores.length; i++) {
if (currentScore > scores[i].totalSum) {
playerRank = i + 1;
break;
}
}
// Leaderboard title
var leaderboardTitle = new Text2('Total Score Rankings', {
size: 100,
fill: 0x000000,
font: "'Arial', sans-serif"
});
leaderboardTitle.anchor.set(0.5, 0.5);
leaderboardTitle.y = -400;
leaderboardContainer.addChild(leaderboardTitle);
// Display top 10 scores
var yOffset = -320;
var maxDisplay = Math.min(10, scores.length);
for (var i = 0; i < maxDisplay; i++) {
var rankDisplay = i + 1 + '.';
var scoreDisplay = 'Total: ' + scores[i].totalSum + ' (Moves: ' + scores[i].moves + ')';
var scoreText = new Text2(rankDisplay + ' ' + scoreDisplay, {
size: 85,
fill: 0x000000,
font: "'Arial', sans-serif"
});
scoreText.anchor.set(0.5, 0.5);
scoreText.y = yOffset;
leaderboardContainer.addChild(scoreText);
yOffset += 60;
}
// If there are fewer than 10 scores, show empty slots for remaining positions
for (var i = scores.length; i < 10; i++) {
var rankDisplay = i + 1 + '.';
var scoreDisplay = '---';
var emptySlotText = new Text2(rankDisplay + ' ' + scoreDisplay, {
size: 65,
fill: 0x888888,
font: "'Arial', sans-serif"
});
emptySlotText.anchor.set(0.5, 0.5);
emptySlotText.y = yOffset;
leaderboardContainer.addChild(emptySlotText);
yOffset += 60;
}
// Player rank
var rankText = new Text2('Your Rank: #' + playerRank, {
size: 70,
fill: 0xFF0000,
font: "'Arial', sans-serif"
});
rankText.anchor.set(0.5, 0.5);
rankText.y = yOffset + 60;
leaderboardContainer.addChild(rankText);
// Current player score
var currentScoreText = new Text2('Your Total Score: ' + currentScore, {
size: 65,
fill: 0x0000FF,
font: "'Arial', sans-serif"
});
currentScoreText.anchor.set(0.5, 0.5);
currentScoreText.y = yOffset + 120;
leaderboardContainer.addChild(currentScoreText);
game.addChild(leaderboardContainer);
// Auto trigger game over after showing the leaderboard
LK.setTimeout(function () {
if (gameState === 'won') {
LK.showYouWin();
} else {
LK.showGameOver();
}
}, 12000);
}
function showFinalScore() {
// Create final score display positioned over the center of the grid
var finalScoreContainer = new Container();
finalScoreContainer.x = 2048 / 2;
finalScoreContainer.y = 2732 / 2;
// Add full screen cream background
var background = finalScoreContainer.attachAsset('fullScreenCreamBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Get scores from storage for leaderboard
var scores = storage.scores || [];
var currentScore = moveCount;
var playerRank = scores.length + 1;
// Find player's rank
for (var i = 0; i < scores.length; i++) {
if (currentScore > scores[i].score) {
playerRank = i + 1;
break;
}
}
// Congratulations title
var congratsText = new Text2('Congratulations!', {
size: 100,
fill: 0x000000,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
congratsText.anchor.set(0.5, 0.5);
congratsText.y = -350;
finalScoreContainer.addChild(congratsText);
// Game completion message
var completionText = new Text2("You've completed the game, but there are no more valid moves left.", {
size: 50,
fill: 0x000000,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
completionText.anchor.set(0.5, 0.5);
completionText.y = -280;
finalScoreContainer.addChild(completionText);
// Final score message
var finalScoreText = new Text2('Your final score is ' + currentScore + '.', {
size: 65,
fill: 0x000000,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
finalScoreText.anchor.set(0.5, 0.5);
finalScoreText.y = -220;
finalScoreContainer.addChild(finalScoreText);
// Leaderboard title
var leaderboardTitle = new Text2("Here's how you rank among other players:", {
size: 55,
fill: 0x000000,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
leaderboardTitle.anchor.set(0.5, 0.5);
leaderboardTitle.y = -150;
finalScoreContainer.addChild(leaderboardTitle);
// Display top scores with enhanced leaderboard
var yOffset = -80;
var maxDisplay = Math.min(10, scores.length);
for (var i = 0; i < maxDisplay; i++) {
var rankDisplay = i + 1 + '.';
var scoreDisplay = 'Score: ' + scores[i].score + ' (Moves: ' + scores[i].moves + ')';
var scoreText = new Text2(rankDisplay + ' ' + scoreDisplay, {
size: 38,
fill: 0x000000,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
scoreText.anchor.set(0.5, 0.5);
scoreText.y = yOffset;
finalScoreContainer.addChild(scoreText);
yOffset += 35;
}
// Player rank
var rankText = new Text2('Your position: ' + playerRank, {
size: 60,
fill: 0xff0000,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
rankText.anchor.set(0.5, 0.5);
rankText.y = yOffset + 40;
finalScoreContainer.addChild(rankText);
// Display the highest number reached prominently in white color as requested
var highestNumberText = new Text2('Score ' + moveCount.toString(), {
size: 140,
fill: 0xFFFFFF,
font: "'Arial Black', 'Arial-Black', Impact, sans-serif"
});
highestNumberText.anchor.set(0.5, 0.5);
highestNumberText.y = 0;
// Add the main score text centered prominently
finalScoreContainer.addChild(highestNumberText);
game.addChild(finalScoreContainer);
// Auto trigger game over after showing the leaderboard
LK.setTimeout(function () {
LK.showGameOver();
}, 8000);
}
// Initialize game
updatePlayerPosition();
updateValidMoves();
updateUI();