// Cloned by Tharanya Satish on 15 Jul 2024 from Mind "Complex Mind" by Starter user
// Please leave this clone trail here.
// =================================================================================================
// Sample Mind for more complex starter World
// =================================================================================================
// World tells us agent position and enemy position
// World does not tell us of existence of walls
// if return invalid move (not empty square) World just ignores it and we miss a turn
AB.mind.getAction = function ( x ) // x is an array of [ ai, aj, ei, ej ]
{
var ai = x[0];
var aj = x[1];
var ei = x[2];
var ej = x[3];
// if strictly move away, will get stuck at wall, so introduce randomness
if ( ej < aj ) return ( AB.randomPick ( ACTION_UP, AB.randomPick(ACTION_RIGHT,ACTION_LEFT) ));
if ( ej > aj ) return ( AB.randomPick ( ACTION_DOWN, AB.randomPick(ACTION_RIGHT,ACTION_LEFT) ));
if ( ei < ai ) return ( AB.randomPick ( ACTION_RIGHT, AB.randomPick(ACTION_UP,ACTION_DOWN) ));
if ( ei > ai ) return ( AB.randomPick ( ACTION_LEFT, AB.randomPick(ACTION_UP,ACTION_DOWN) ));
return ( AB.randomIntAtoB (0,3) );
};
// Function to implement A* algorithm
function aStar(start, goal, grid) {
function heuristic(node, goal) {
return Math.abs(node[0] - goal[0]) + Math.abs(node[1] - goal[1]);
}
let openSet = new PriorityQueue((a, b) => a.f < b.f);
openSet.push({ node: start, g: 0, h: heuristic(start, goal), f: heuristic(start, goal), path: [] });
let closedSet = new Set();
while (!openSet.isEmpty()) {
let current = openSet.pop();
if (current.node[0] === goal[0] && current.node[1] === goal[1]) {
return current.path.concat([current.node]);
}
closedSet.add(current.node.toString());
let neighbors = [
[current.node[0] - 1, current.node[1]], // UP
[current.node[0] + 1, current.node[1]], // DOWN
[current.node[0], current.node[1] - 1], // LEFT
[current.node[0], current.node[1] + 1] // RIGHT
];
for (let neighbor of neighbors) {
if (closedSet.has(neighbor.toString()) || !isValid(neighbor, grid)) continue;
let g = current.g + 1;
let h = heuristic(neighbor, goal);
let f = g + h;
openSet.push({ node: neighbor, g, h, f, path: current.path.concat([current.node]) });
}
}
return []; // No path found
}
function isValid(node, grid) {
let x = node[0], y = node[1];
return x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] !== 'BLOCK';
}
// Modify enemy action to use A* algorithm
AB.mind.getAction = function (x) {
var ai = x[0];
var aj = x[1];
var ei = x[2];
var ej = x[3];
// Use A* to get the best path
let grid = AB.world.getGrid(); // Assuming this function returns the current grid with obstacles
let path = aStar([ei, ej], [ai, aj], grid);
if (path.length > 1) {
let nextMove = path[1];
if (nextMove[0] < ei) return ACTION_UP;
if (nextMove[0] > ei) return ACTION_DOWN;
if (nextMove[1] < ej) return ACTION_LEFT;
if (nextMove[1] > ej) return ACTION_RIGHT;
}
// Default move if no path is found
return AB.randomIntAtoB(0, 3);
};
// Function to update the appearance of the world
function updateWorldAppearance() {
// Update grid size
AB.world.setGridSize(20, 20); // Example: changing grid to 20x20
// Update box density
AB.world.setBoxDensity(0.3); // Example: setting box density to 30%
// Update run speed
AB.world.setRunSpeed(2); // Example: setting run speed to a faster rate
// Update background and images
AB.world.setBackgroundImage('path/to/background.png');
AB.world.setAgentImage('path/to/agent.png');
AB.world.setBoxImage('path/to/box.png');
AB.world.setEnemyImage('path/to/enemy.png');
// Update music
AB.world.setMusic('path/to/music.mp3');
}
// Call the function to update the world appearance
updateWorldAppearance();
// Priority Queue implementation for the A* algorithm
class PriorityQueue {
constructor(comparator = (a, b) => a > b) {
this._heap = [];
this._comparator = comparator;
}
size() {
return this._heap.length;
}
isEmpty() {
return this.size() === 0;
}
peek() {
return this._heap[0];
}
push(...values) {
values.forEach(value => {
this._heap.push(value);
this._siftUp();
});
return this.size();
}
pop() {
const poppedValue = this.peek();
const bottom = this.size() - 1;
if (bottom > 0) {
this._swap(0, bottom);
}
this._heap.pop();
this._siftDown();
return poppedValue;
}
_greater(i, j) {
return this._comparator(this._heap[i], this._heap[j]);
}
_swap(i, j) {
[this._heap[i], this._heap[j]] = [this._heap[j], this._heap[i]];
}
_siftUp() {
let node = this.size() - 1;
while (node > 0 && this._greater(node, Math.floor((node - 1) / 2))) {
this._swap(node, Math.floor((node - 1) / 2));
node = Math.floor((node - 1) / 2);
}
}
_siftDown() {
let node = 0;
while (
(node * 2 + 1 < this.size() && this._greater(node * 2 + 1, node)) ||
(node * 2 + 2 < this.size() && this._greater(node * 2 + 2, node))
) {
let maxChild = (node * 2 + 2 < this.size() && this._greater(node * 2 + 2, node * 2 + 1)) ? node * 2 + 2 : node * 2 + 1;
this._swap(node, maxChild);
node = maxChild;
}
}
}