Code viewer for Mind: Complex Mind (clone by Tha...

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