User prompt
Faster movement
User prompt
Make the maze bigger and the ai move faster
Code edit (1 edits merged)
Please save this source code
User prompt
Maze Master: AI Learning Adventure
Initial prompt
A randomly generated maze with a bot that uses RL to learn the maze when it reaches a dead end it restarts with its info still the same but everytime you load the game its brain resets
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AIBot = Container.expand(function () {
var self = Container.call(this);
self.visual = self.attachAsset('bot', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.memory = {}; // Stores path memory
self.currentPath = []; // Stores current path
self.possibleMoves = []; // Stores possible moves from current position
self.isMoving = false;
self.hasWon = false;
self.moveTo = function (x, y, duration) {
if (self.isMoving) {
return;
}
self.isMoving = true;
tween(self, {
x: x,
y: y
}, {
duration: duration || 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isMoving = false;
}
});
};
self.setGridPosition = function (x, y) {
self.gridX = x;
self.gridY = y;
};
self.getMemoryKey = function (x, y) {
return x + ',' + y;
};
self.rememberCell = function (x, y, value) {
var key = self.getMemoryKey(x, y);
self.memory[key] = value;
};
self.getCellMemory = function (x, y) {
var key = self.getMemoryKey(x, y);
return self.memory[key];
};
self.addToPath = function (x, y) {
self.currentPath.push({
x: x,
y: y
});
};
self.reset = function () {
self.currentPath = [];
self.possibleMoves = [];
self.isMoving = false;
self.hasWon = false;
};
self.clearMemory = function () {
self.memory = {};
};
return self;
});
var MazeCell = Container.expand(function (x, y, type) {
var self = Container.call(this);
self.gridX = x;
self.gridY = y;
self.type = type || 'wall';
self.visited = false;
self.deadEnd = false;
// Visual representation
self.visual = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.setType = function (newType) {
self.type = newType;
self.removeChild(self.visual);
self.visual = self.attachAsset(newType, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.markVisited = function () {
if (self.type === 'path' && !self.visited) {
self.visited = true;
self.removeChild(self.visual);
self.visual = self.attachAsset('visited', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
self.markDeadEnd = function () {
if (self.type === 'path' && !self.deadEnd) {
self.deadEnd = true;
self.removeChild(self.visual);
self.visual = self.attachAsset('deadEnd', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
return self;
});
var MazeGame = Container.expand(function () {
var self = Container.call(this);
// Maze properties
self.mazeWidth = 15;
self.mazeHeight = 15;
self.cellSize = 40;
self.cells = [];
self.startCell = {
x: 1,
y: 1
};
self.endCell = {
x: self.mazeWidth - 2,
y: self.mazeHeight - 2
};
// AI Bot
self.bot = new AIBot();
self.addChild(self.bot);
// Game state
self.gameRunning = false;
self.moveInterval = null;
self.moveDelay = 300; // milliseconds between moves
self.consecutiveDeadEnds = 0;
self.initialize = function () {
self.generateMaze();
self.positionBot();
self.bot.clearMemory();
LK.playMusic('bgMusic');
};
self.generateMaze = function () {
// Clear existing cells
for (var i = 0; i < self.cells.length; i++) {
for (var j = 0; j < self.cells[i].length; j++) {
if (self.cells[i][j]) {
self.removeChild(self.cells[i][j]);
}
}
}
// Initialize all cells as walls
self.cells = [];
for (var x = 0; x < self.mazeWidth; x++) {
self.cells[x] = [];
for (var y = 0; y < self.mazeHeight; y++) {
var cell = new MazeCell(x, y, 'wall');
cell.x = x * self.cellSize;
cell.y = y * self.cellSize;
self.cells[x][y] = cell;
self.addChild(cell);
}
}
// Generate maze using recursive backtracking
self.generateMazeRecursive(self.startCell.x, self.startCell.y);
// Set start and end cells
self.cells[self.startCell.x][self.startCell.y].setType('start');
self.cells[self.endCell.x][self.endCell.y].setType('end');
};
self.generateMazeRecursive = function (x, y) {
// Mark current cell as path
self.cells[x][y].setType('path');
// Define directions: up, right, down, left
var directions = [{
dx: 0,
dy: -2
},
// up
{
dx: 2,
dy: 0
},
// right
{
dx: 0,
dy: 2
},
// down
{
dx: -2,
dy: 0
} // left
];
// Shuffle directions
shuffleArray(directions);
// Explore each direction
for (var i = 0; i < directions.length; i++) {
var dx = directions[i].dx;
var dy = directions[i].dy;
var newX = x + dx;
var newY = y + dy;
// Check if the new cell is within bounds and is a wall
if (newX > 0 && newX < self.mazeWidth - 1 && newY > 0 && newY < self.mazeHeight - 1 && self.cells[newX][newY].type === 'wall') {
// Create a passage by making the cell between current and new a path
self.cells[x + dx / 2][y + dy / 2].setType('path');
// Continue maze generation from the new cell
self.generateMazeRecursive(newX, newY);
}
}
};
self.positionBot = function () {
// Position bot at start cell
self.bot.setGridPosition(self.startCell.x, self.startCell.y);
self.bot.x = self.startCell.x * self.cellSize;
self.bot.y = self.startCell.y * self.cellSize;
self.bot.addToPath(self.startCell.x, self.startCell.y);
};
self.startGame = function () {
if (self.gameRunning) {
return;
}
self.gameRunning = true;
self.moveInterval = LK.setInterval(function () {
self.makeAIMove();
}, self.moveDelay);
};
self.stopGame = function () {
if (!self.gameRunning) {
return;
}
self.gameRunning = false;
if (self.moveInterval) {
LK.clearInterval(self.moveInterval);
self.moveInterval = null;
}
};
self.makeAIMove = function () {
if (!self.gameRunning || self.bot.isMoving) {
return;
}
// Check if bot reached the end
if (self.bot.gridX === self.endCell.x && self.bot.gridY === self.endCell.y) {
self.onBotReachedEnd();
return;
}
// Get possible moves
self.getPossibleMoves();
// If no moves are available, backtrack
if (self.bot.possibleMoves.length === 0) {
self.onDeadEnd();
return;
}
// Choose best move based on memory
var bestMove = self.chooseBestMove();
// Mark current cell as visited
self.cells[self.bot.gridX][self.bot.gridY].markVisited();
// Remember this cell
self.bot.rememberCell(self.bot.gridX, self.bot.gridY, 'visited');
// Update bot position
self.bot.setGridPosition(bestMove.x, bestMove.y);
self.bot.addToPath(bestMove.x, bestMove.y);
// Move bot visually
self.bot.moveTo(bestMove.x * self.cellSize, bestMove.y * self.cellSize);
// Play move sound
LK.getSound('move').play();
};
self.getPossibleMoves = function () {
var x = self.bot.gridX;
var y = self.bot.gridY;
self.bot.possibleMoves = [];
// Check four directions
var directions = [{
x: x,
y: y - 1
},
// up
{
x: x + 1,
y: y
},
// right
{
x: x,
y: y + 1
},
// down
{
x: x - 1,
y: y
} // left
];
for (var i = 0; i < directions.length; i++) {
var nx = directions[i].x;
var ny = directions[i].y;
// Check if the cell is within bounds and is a path or end
if (nx >= 0 && nx < self.mazeWidth && ny >= 0 && ny < self.mazeHeight && (self.cells[nx][ny].type === 'path' || self.cells[nx][ny].type === 'end' || self.cells[nx][ny].type === 'start')) {
// Check if the cell is not marked as dead end in memory
var cellMemory = self.bot.getCellMemory(nx, ny);
if (cellMemory !== 'deadEnd') {
self.bot.possibleMoves.push({
x: nx,
y: ny
});
}
}
}
};
self.chooseBestMove = function () {
var moves = self.bot.possibleMoves;
var bestMoves = [];
var bestScore = -Infinity;
// Score each move
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
var score = self.scoreMove(move);
if (score > bestScore) {
bestScore = score;
bestMoves = [move];
} else if (score === bestScore) {
bestMoves.push(move);
}
}
// Randomly choose among best moves
return bestMoves[Math.floor(Math.random() * bestMoves.length)];
};
self.scoreMove = function (move) {
var memory = self.bot.getCellMemory(move.x, move.y);
// Prioritize the end cell
if (move.x === self.endCell.x && move.y === self.endCell.y) {
return 100;
}
// Avoid visited cells
if (memory === 'visited') {
return -10;
}
// Prefer unexplored cells
return 10;
};
self.onDeadEnd = function () {
self.consecutiveDeadEnds++;
// Mark current path as dead end in memory
for (var i = self.bot.currentPath.length - 1; i >= 0; i--) {
var pathCell = self.bot.currentPath[i];
var cellMemory = self.bot.getCellMemory(pathCell.x, pathCell.y);
if (cellMemory !== 'deadEnd') {
self.bot.rememberCell(pathCell.x, pathCell.y, 'deadEnd');
self.cells[pathCell.x][pathCell.y].markDeadEnd();
// Break if we find a cell with multiple exits
self.getPossibleMovesForCell(pathCell.x, pathCell.y);
if (self.bot.possibleMoves.length > 1) {
break;
}
}
}
// Play dead end sound
LK.getSound('deadend').play();
// Reset bot to start
self.bot.reset();
self.positionBot();
// If we're stuck in a loop, slow down and eventually reset
if (self.consecutiveDeadEnds > 10) {
self.moveDelay = Math.min(1000, self.moveDelay + 50);
if (self.consecutiveDeadEnds > 20) {
self.initialize();
self.consecutiveDeadEnds = 0;
self.moveDelay = 300;
}
}
};
self.getPossibleMovesForCell = function (x, y) {
self.bot.possibleMoves = [];
// Check four directions
var directions = [{
x: x,
y: y - 1
},
// up
{
x: x + 1,
y: y
},
// right
{
x: x,
y: y + 1
},
// down
{
x: x - 1,
y: y
} // left
];
for (var i = 0; i < directions.length; i++) {
var nx = directions[i].x;
var ny = directions[i].y;
// Check if the cell is within bounds and is a path or end
if (nx >= 0 && nx < self.mazeWidth && ny >= 0 && ny < self.mazeHeight && (self.cells[nx][ny].type === 'path' || self.cells[nx][ny].type === 'end' || self.cells[nx][ny].type === 'start')) {
self.bot.possibleMoves.push({
x: nx,
y: ny
});
}
}
};
self.onBotReachedEnd = function () {
self.stopGame();
self.bot.hasWon = true;
// Play win sound
LK.getSound('win').play();
// Show winning message
LK.showYouWin();
};
return self;
});
/****
* Initialize Game
****/
// Utility function to shuffle an array
var game = new LK.Game({
backgroundColor: 0x121212
});
/****
* Game Code
****/
// Utility function to shuffle an array
// Create status text
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
var statusText = new Text2('AI Maze Learning', {
size: 40,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
// Create stats text
var statsText = new Text2('Moves: 0 | Memory: 0', {
size: 30,
fill: 0xCCCCCC
});
statsText.anchor.set(0.5, 0);
statsText.y = 50;
LK.gui.top.addChild(statsText);
// Create instructions text
var instructionsText = new Text2('Watch the AI learn to solve the maze.\nGreen blocks mark visited paths.\nRed blocks mark dead ends.', {
size: 25,
fill: 0xAAAAAA
});
instructionsText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionsText);
// Create reset button
var resetButton = new Text2('RESET MAZE', {
size: 35,
fill: 0xFFFFFF
});
resetButton.anchor.set(0.5, 1);
resetButton.y = -60;
resetButton.interactive = true;
LK.gui.bottom.addChild(resetButton);
// Create maze game
var mazeGame = new MazeGame();
game.addChild(mazeGame);
// Position the maze in the center of the screen
var centerMaze = function centerMaze() {
var mazePixelWidth = mazeGame.mazeWidth * mazeGame.cellSize;
var mazePixelHeight = mazeGame.mazeHeight * mazeGame.cellSize;
mazeGame.x = (2048 - mazePixelWidth) / 2;
mazeGame.y = (2732 - mazePixelHeight) / 2;
};
// Initialize the game
var initGame = function initGame() {
mazeGame.initialize();
centerMaze();
mazeGame.startGame();
updateStats();
};
// Reset button handlers
resetButton.down = function () {
initGame();
};
// Update stats display
var updateStats = function updateStats() {
var memoryCount = Object.keys(mazeGame.bot.memory).length;
statsText.setText('Moves: ' + mazeGame.bot.currentPath.length + ' | Memory: ' + memoryCount);
};
// Initialize the game when loaded
initGame();
// Game update function
game.update = function () {
// Update stats if game is running
if (mazeGame.gameRunning) {
updateStats();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,501 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var AIBot = Container.expand(function () {
+ var self = Container.call(this);
+ self.visual = self.attachAsset('bot', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.gridX = 0;
+ self.gridY = 0;
+ self.memory = {}; // Stores path memory
+ self.currentPath = []; // Stores current path
+ self.possibleMoves = []; // Stores possible moves from current position
+ self.isMoving = false;
+ self.hasWon = false;
+ self.moveTo = function (x, y, duration) {
+ if (self.isMoving) {
+ return;
+ }
+ self.isMoving = true;
+ tween(self, {
+ x: x,
+ y: y
+ }, {
+ duration: duration || 300,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ self.isMoving = false;
+ }
+ });
+ };
+ self.setGridPosition = function (x, y) {
+ self.gridX = x;
+ self.gridY = y;
+ };
+ self.getMemoryKey = function (x, y) {
+ return x + ',' + y;
+ };
+ self.rememberCell = function (x, y, value) {
+ var key = self.getMemoryKey(x, y);
+ self.memory[key] = value;
+ };
+ self.getCellMemory = function (x, y) {
+ var key = self.getMemoryKey(x, y);
+ return self.memory[key];
+ };
+ self.addToPath = function (x, y) {
+ self.currentPath.push({
+ x: x,
+ y: y
+ });
+ };
+ self.reset = function () {
+ self.currentPath = [];
+ self.possibleMoves = [];
+ self.isMoving = false;
+ self.hasWon = false;
+ };
+ self.clearMemory = function () {
+ self.memory = {};
+ };
+ return self;
+});
+var MazeCell = Container.expand(function (x, y, type) {
+ var self = Container.call(this);
+ self.gridX = x;
+ self.gridY = y;
+ self.type = type || 'wall';
+ self.visited = false;
+ self.deadEnd = false;
+ // Visual representation
+ self.visual = self.attachAsset(self.type, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.setType = function (newType) {
+ self.type = newType;
+ self.removeChild(self.visual);
+ self.visual = self.attachAsset(newType, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ };
+ self.markVisited = function () {
+ if (self.type === 'path' && !self.visited) {
+ self.visited = true;
+ self.removeChild(self.visual);
+ self.visual = self.attachAsset('visited', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ };
+ self.markDeadEnd = function () {
+ if (self.type === 'path' && !self.deadEnd) {
+ self.deadEnd = true;
+ self.removeChild(self.visual);
+ self.visual = self.attachAsset('deadEnd', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ };
+ return self;
+});
+var MazeGame = Container.expand(function () {
+ var self = Container.call(this);
+ // Maze properties
+ self.mazeWidth = 15;
+ self.mazeHeight = 15;
+ self.cellSize = 40;
+ self.cells = [];
+ self.startCell = {
+ x: 1,
+ y: 1
+ };
+ self.endCell = {
+ x: self.mazeWidth - 2,
+ y: self.mazeHeight - 2
+ };
+ // AI Bot
+ self.bot = new AIBot();
+ self.addChild(self.bot);
+ // Game state
+ self.gameRunning = false;
+ self.moveInterval = null;
+ self.moveDelay = 300; // milliseconds between moves
+ self.consecutiveDeadEnds = 0;
+ self.initialize = function () {
+ self.generateMaze();
+ self.positionBot();
+ self.bot.clearMemory();
+ LK.playMusic('bgMusic');
+ };
+ self.generateMaze = function () {
+ // Clear existing cells
+ for (var i = 0; i < self.cells.length; i++) {
+ for (var j = 0; j < self.cells[i].length; j++) {
+ if (self.cells[i][j]) {
+ self.removeChild(self.cells[i][j]);
+ }
+ }
+ }
+ // Initialize all cells as walls
+ self.cells = [];
+ for (var x = 0; x < self.mazeWidth; x++) {
+ self.cells[x] = [];
+ for (var y = 0; y < self.mazeHeight; y++) {
+ var cell = new MazeCell(x, y, 'wall');
+ cell.x = x * self.cellSize;
+ cell.y = y * self.cellSize;
+ self.cells[x][y] = cell;
+ self.addChild(cell);
+ }
+ }
+ // Generate maze using recursive backtracking
+ self.generateMazeRecursive(self.startCell.x, self.startCell.y);
+ // Set start and end cells
+ self.cells[self.startCell.x][self.startCell.y].setType('start');
+ self.cells[self.endCell.x][self.endCell.y].setType('end');
+ };
+ self.generateMazeRecursive = function (x, y) {
+ // Mark current cell as path
+ self.cells[x][y].setType('path');
+ // Define directions: up, right, down, left
+ var directions = [{
+ dx: 0,
+ dy: -2
+ },
+ // up
+ {
+ dx: 2,
+ dy: 0
+ },
+ // right
+ {
+ dx: 0,
+ dy: 2
+ },
+ // down
+ {
+ dx: -2,
+ dy: 0
+ } // left
+ ];
+ // Shuffle directions
+ shuffleArray(directions);
+ // Explore each direction
+ for (var i = 0; i < directions.length; i++) {
+ var dx = directions[i].dx;
+ var dy = directions[i].dy;
+ var newX = x + dx;
+ var newY = y + dy;
+ // Check if the new cell is within bounds and is a wall
+ if (newX > 0 && newX < self.mazeWidth - 1 && newY > 0 && newY < self.mazeHeight - 1 && self.cells[newX][newY].type === 'wall') {
+ // Create a passage by making the cell between current and new a path
+ self.cells[x + dx / 2][y + dy / 2].setType('path');
+ // Continue maze generation from the new cell
+ self.generateMazeRecursive(newX, newY);
+ }
+ }
+ };
+ self.positionBot = function () {
+ // Position bot at start cell
+ self.bot.setGridPosition(self.startCell.x, self.startCell.y);
+ self.bot.x = self.startCell.x * self.cellSize;
+ self.bot.y = self.startCell.y * self.cellSize;
+ self.bot.addToPath(self.startCell.x, self.startCell.y);
+ };
+ self.startGame = function () {
+ if (self.gameRunning) {
+ return;
+ }
+ self.gameRunning = true;
+ self.moveInterval = LK.setInterval(function () {
+ self.makeAIMove();
+ }, self.moveDelay);
+ };
+ self.stopGame = function () {
+ if (!self.gameRunning) {
+ return;
+ }
+ self.gameRunning = false;
+ if (self.moveInterval) {
+ LK.clearInterval(self.moveInterval);
+ self.moveInterval = null;
+ }
+ };
+ self.makeAIMove = function () {
+ if (!self.gameRunning || self.bot.isMoving) {
+ return;
+ }
+ // Check if bot reached the end
+ if (self.bot.gridX === self.endCell.x && self.bot.gridY === self.endCell.y) {
+ self.onBotReachedEnd();
+ return;
+ }
+ // Get possible moves
+ self.getPossibleMoves();
+ // If no moves are available, backtrack
+ if (self.bot.possibleMoves.length === 0) {
+ self.onDeadEnd();
+ return;
+ }
+ // Choose best move based on memory
+ var bestMove = self.chooseBestMove();
+ // Mark current cell as visited
+ self.cells[self.bot.gridX][self.bot.gridY].markVisited();
+ // Remember this cell
+ self.bot.rememberCell(self.bot.gridX, self.bot.gridY, 'visited');
+ // Update bot position
+ self.bot.setGridPosition(bestMove.x, bestMove.y);
+ self.bot.addToPath(bestMove.x, bestMove.y);
+ // Move bot visually
+ self.bot.moveTo(bestMove.x * self.cellSize, bestMove.y * self.cellSize);
+ // Play move sound
+ LK.getSound('move').play();
+ };
+ self.getPossibleMoves = function () {
+ var x = self.bot.gridX;
+ var y = self.bot.gridY;
+ self.bot.possibleMoves = [];
+ // Check four directions
+ var directions = [{
+ x: x,
+ y: y - 1
+ },
+ // up
+ {
+ x: x + 1,
+ y: y
+ },
+ // right
+ {
+ x: x,
+ y: y + 1
+ },
+ // down
+ {
+ x: x - 1,
+ y: y
+ } // left
+ ];
+ for (var i = 0; i < directions.length; i++) {
+ var nx = directions[i].x;
+ var ny = directions[i].y;
+ // Check if the cell is within bounds and is a path or end
+ if (nx >= 0 && nx < self.mazeWidth && ny >= 0 && ny < self.mazeHeight && (self.cells[nx][ny].type === 'path' || self.cells[nx][ny].type === 'end' || self.cells[nx][ny].type === 'start')) {
+ // Check if the cell is not marked as dead end in memory
+ var cellMemory = self.bot.getCellMemory(nx, ny);
+ if (cellMemory !== 'deadEnd') {
+ self.bot.possibleMoves.push({
+ x: nx,
+ y: ny
+ });
+ }
+ }
+ }
+ };
+ self.chooseBestMove = function () {
+ var moves = self.bot.possibleMoves;
+ var bestMoves = [];
+ var bestScore = -Infinity;
+ // Score each move
+ for (var i = 0; i < moves.length; i++) {
+ var move = moves[i];
+ var score = self.scoreMove(move);
+ if (score > bestScore) {
+ bestScore = score;
+ bestMoves = [move];
+ } else if (score === bestScore) {
+ bestMoves.push(move);
+ }
+ }
+ // Randomly choose among best moves
+ return bestMoves[Math.floor(Math.random() * bestMoves.length)];
+ };
+ self.scoreMove = function (move) {
+ var memory = self.bot.getCellMemory(move.x, move.y);
+ // Prioritize the end cell
+ if (move.x === self.endCell.x && move.y === self.endCell.y) {
+ return 100;
+ }
+ // Avoid visited cells
+ if (memory === 'visited') {
+ return -10;
+ }
+ // Prefer unexplored cells
+ return 10;
+ };
+ self.onDeadEnd = function () {
+ self.consecutiveDeadEnds++;
+ // Mark current path as dead end in memory
+ for (var i = self.bot.currentPath.length - 1; i >= 0; i--) {
+ var pathCell = self.bot.currentPath[i];
+ var cellMemory = self.bot.getCellMemory(pathCell.x, pathCell.y);
+ if (cellMemory !== 'deadEnd') {
+ self.bot.rememberCell(pathCell.x, pathCell.y, 'deadEnd');
+ self.cells[pathCell.x][pathCell.y].markDeadEnd();
+ // Break if we find a cell with multiple exits
+ self.getPossibleMovesForCell(pathCell.x, pathCell.y);
+ if (self.bot.possibleMoves.length > 1) {
+ break;
+ }
+ }
+ }
+ // Play dead end sound
+ LK.getSound('deadend').play();
+ // Reset bot to start
+ self.bot.reset();
+ self.positionBot();
+ // If we're stuck in a loop, slow down and eventually reset
+ if (self.consecutiveDeadEnds > 10) {
+ self.moveDelay = Math.min(1000, self.moveDelay + 50);
+ if (self.consecutiveDeadEnds > 20) {
+ self.initialize();
+ self.consecutiveDeadEnds = 0;
+ self.moveDelay = 300;
+ }
+ }
+ };
+ self.getPossibleMovesForCell = function (x, y) {
+ self.bot.possibleMoves = [];
+ // Check four directions
+ var directions = [{
+ x: x,
+ y: y - 1
+ },
+ // up
+ {
+ x: x + 1,
+ y: y
+ },
+ // right
+ {
+ x: x,
+ y: y + 1
+ },
+ // down
+ {
+ x: x - 1,
+ y: y
+ } // left
+ ];
+ for (var i = 0; i < directions.length; i++) {
+ var nx = directions[i].x;
+ var ny = directions[i].y;
+ // Check if the cell is within bounds and is a path or end
+ if (nx >= 0 && nx < self.mazeWidth && ny >= 0 && ny < self.mazeHeight && (self.cells[nx][ny].type === 'path' || self.cells[nx][ny].type === 'end' || self.cells[nx][ny].type === 'start')) {
+ self.bot.possibleMoves.push({
+ x: nx,
+ y: ny
+ });
+ }
+ }
+ };
+ self.onBotReachedEnd = function () {
+ self.stopGame();
+ self.bot.hasWon = true;
+ // Play win sound
+ LK.getSound('win').play();
+ // Show winning message
+ LK.showYouWin();
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
+// Utility function to shuffle an array
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x121212
+});
+
+/****
+* Game Code
+****/
+// Utility function to shuffle an array
+// Create status text
+function shuffleArray(array) {
+ for (var i = array.length - 1; i > 0; i--) {
+ var j = Math.floor(Math.random() * (i + 1));
+ var temp = array[i];
+ array[i] = array[j];
+ array[j] = temp;
+ }
+ return array;
+}
+var statusText = new Text2('AI Maze Learning', {
+ size: 40,
+ fill: 0xFFFFFF
+});
+statusText.anchor.set(0.5, 0);
+LK.gui.top.addChild(statusText);
+// Create stats text
+var statsText = new Text2('Moves: 0 | Memory: 0', {
+ size: 30,
+ fill: 0xCCCCCC
+});
+statsText.anchor.set(0.5, 0);
+statsText.y = 50;
+LK.gui.top.addChild(statsText);
+// Create instructions text
+var instructionsText = new Text2('Watch the AI learn to solve the maze.\nGreen blocks mark visited paths.\nRed blocks mark dead ends.', {
+ size: 25,
+ fill: 0xAAAAAA
+});
+instructionsText.anchor.set(0.5, 1);
+LK.gui.bottom.addChild(instructionsText);
+// Create reset button
+var resetButton = new Text2('RESET MAZE', {
+ size: 35,
+ fill: 0xFFFFFF
+});
+resetButton.anchor.set(0.5, 1);
+resetButton.y = -60;
+resetButton.interactive = true;
+LK.gui.bottom.addChild(resetButton);
+// Create maze game
+var mazeGame = new MazeGame();
+game.addChild(mazeGame);
+// Position the maze in the center of the screen
+var centerMaze = function centerMaze() {
+ var mazePixelWidth = mazeGame.mazeWidth * mazeGame.cellSize;
+ var mazePixelHeight = mazeGame.mazeHeight * mazeGame.cellSize;
+ mazeGame.x = (2048 - mazePixelWidth) / 2;
+ mazeGame.y = (2732 - mazePixelHeight) / 2;
+};
+// Initialize the game
+var initGame = function initGame() {
+ mazeGame.initialize();
+ centerMaze();
+ mazeGame.startGame();
+ updateStats();
+};
+// Reset button handlers
+resetButton.down = function () {
+ initGame();
+};
+// Update stats display
+var updateStats = function updateStats() {
+ var memoryCount = Object.keys(mazeGame.bot.memory).length;
+ statsText.setText('Moves: ' + mazeGame.bot.currentPath.length + ' | Memory: ' + memoryCount);
+};
+// Initialize the game when loaded
+initGame();
+// Game update function
+game.update = function () {
+ // Update stats if game is running
+ if (mazeGame.gameRunning) {
+ updateStats();
+ }
+};
\ No newline at end of file