Code viewer for World: A* World
/* Initialise any constants. */
const ch = 600;
const cw = 900;
const diagonal = true ;
const backcolor = 'white';
const closedcolor = 'lightpink';
const opencolor = 'lightgreen';
const pathcolor = 'darkred';
const wallAmount = AB.randomFloatAtoB(0, 0.6);
const wallcolor = 'black';

/* Initialise any variables. */
var random = AB.randomIntAtoB(1, 5);
var cols = 9 * random;
var grid = new Array(cols);
var rows = 6 * random;

/* The set of open and closed nodes. */
var closedSet = [];
var openSet = [];

/* The start and end nodes. */
var end;
var start;

/* The width and height of each cell in the grid. */
var w, h;

/* The path taken. */
var path = [];

/* The heuristic evaluation function that we will use. */
function heuristic(a, b) {
    /* If diagonal moves are allowed, calculate the 2D distance between a and b. */
    if (diagonal) return (dist(a.i, a.j, b.i, b.j));
    /* Otherwise, calculate the distance across, plus the distance down. */
    else return (abs(a.i - b.i) + abs(a.j - b.j));
}

/* Delete the specified element from the specified array. */
function removeFromArray(arr, elt) {
    for (var i = arr.length - 1; i >= 0; i--) {
        if (arr[i] == elt) {
            arr.splice(i, 1);
        }
    }
}

/* Represents a single spot on the grid. */
function Spot(i, j) {
    /* The coordinates for the spot. */
    this.i = i;
    this.j = j;

    /* The f, g, and h values to be used in our heuristic. */
    this.f = 0;
    this.g = 0;
    this.h = 0;

    /* The spot in question's neighbours. */
    this.neighbors = [];

    /* The previous spot that was traversed to reach this spot. */
    this.previous = undefined;

    /* Whether or not this spot is a wall. */
    if (random(1) < wallAmount) this.wall = true;
    else this.wall = false;

    /* Display the spot in question. */
    this.show = function(col) {
        if (this.wall) {
            fill(wallcolor);
            noStroke();
            rect(this.i * w, this.j * h, w, h);
        } else if (col) {
            fill(col);
            rect(this.i * w, this.j * h, w, h);
        }
    };
  
    /* Determine the neighbours of this spot. */
    this.addNeighbors = function(grid) {
        var i = this.i;
        var j = this.j;
    
        if (i < cols - 1) this.neighbors.push(grid[i + 1][j]);
        if (i > 0) this.neighbors.push(grid[i - 1][j]);
        if (j < rows - 1) this.neighbors.push(grid[i][j + 1]);
        if (j > 0) this.neighbors.push(grid[i][j - 1]);
    
        if (diagonal) {
            if (i > 0 && j > 0) this.neighbors.push(grid[i - 1][j - 1]);
            if (i < cols - 1 && j > 0) this.neighbors.push(grid[i + 1][j - 1]);
            if (i > 0 && j < rows - 1) this.neighbors.push(grid[i - 1][j + 1]);
            if (i < cols - 1 && j < rows - 1) this.neighbors.push(grid[i + 1][j + 1]);
        }
    }
}

function setup() {
    frameRate(60)
    createCanvas(cw, ch);
    w = width / cols;
    h = height / rows;
    
    for (var i = 0; i < cols; i++) 
        grid[i] = new Array(rows);

    for (var i = 0; i < cols; i++) 
        for (var j = 0; j < rows; j++) 
            grid[i][j] = new Spot(i, j);
  
    for (var i = 0; i < cols; i++) 
        for (var j = 0; j < rows; j++) 
            grid[i][j].addNeighbors(grid);

    start = grid[0][0];
    end = grid[cols - 1][rows - 1];
    start.wall = false;
    end.wall = false;

    openSet.push(start);
    console.log('Starting search...');
}

function draw() {
    if (openSet.length > 0) {
        var winner = 0;
    
        for (var i = 0; i < openSet.length; i++)
            if (openSet[i].f < openSet[winner].f) 
                winner = i;
        
        var current = openSet[winner];

        if (current === end) {
            noLoop();
            console.log("Success - found path.");
        }

        removeFromArray(openSet, current);
        closedSet.push(current);

        var neighbors = current.neighbors;
    
        for (var i = 0; i < neighbors.length; i++) {
            var neighbor = neighbors[i];

            if (!closedSet.includes(neighbor) && !neighbor.wall) {
                var tempG = current.g + heuristic(neighbor, current);

                var newPath = false;
                if (openSet.includes(neighbor)) {
                    console.log('Comparing current spot (' + current.i + ',' + current.j + ') with neighbour (' + neighbor.i + ',' + neighbor.j + '):')
                    console.log('f(a) - ' + current.f, ', g(a) - ' + current.g + ', h(a) - ' + current.h)
                    console.log('f(b) - ' + neighbor.f, ', g(b) - ' + neighbor.g + ', h(b) - ' + neighbor.h)
                    if (tempG < neighbor.g) {
                        neighbor.g = tempG;
                        newPath = true;
                    }
                } else {
                    neighbor.g = tempG;
                    newPath = true;
                    openSet.push(neighbor);
                }

                if (newPath) {
                    neighbor.h = heuristic(neighbor, end);
                    neighbor.f = neighbor.g + neighbor.h;
                    neighbor.previous = current;
                }
            }
        }
    } else {
        console.log('Fail - no path exists.');
        noLoop();
        return;
    }
    
    background(backcolor);
    
    for (var i = 0; i < cols; i++) 
        for (var j = 0; j < rows; j++) 
            grid[i][j].show();

    for (var i = 0; i < closedSet.length; i++) 
        closedSet[i].show(closedcolor);

    for (var i = 0; i < openSet.length; i++) 
        openSet[i].show(opencolor);

    path = [];
    var temp = current;
    path.push(temp);
    while (temp.previous) {
        path.push(temp.previous);
        temp = temp.previous;
    }
  
    if (diagonal) {
        noFill();
        stroke(pathcolor);
        strokeWeight(w / 8);
        beginShape();
        
        for (var i = 0; i < path.length; i++) 
            vertex((path[i].i * w) + w / 2, (path[i].j * h) + h / 2);
        
        endShape();
    } else {
        for (var i = 0; i < path.length; i++) 
            path[i].show(pathcolor);
    }
}