Code viewer for World: CA1

// global vars
AB.clockTick = 100; // speed of run in pixels
AB.maxSteps = 1e3; // len of run before final score in pixels
AB.screenshotStep = 50;

const show3d = !0;

TEXTURE_WALL = "/uploads/duadur2/wallB.jpg";
TEXTURE_MAZE = "/uploads/c123ian/hedge.jpg";
TEXTURE_AGENT = "/uploads/c123ian/morty.png";
TEXTURE_ENEMY = "/uploads/c123ian/rick_yellow.jpg";
TEXTURE_Arrow = "/uploads/c123ian/portal.jpg";
// MUSIC_BACK = "/uploads/starter/Defense.Line.mp3";
SOUND_ALARM = "/uploads/starter/air.horn.mp3";

// 50 * 50
gridsize = 50; // num of squares changed to 50 x 50

// change box density to no. of squares / 3

NOBOXES = Math.trunc(gridsize * gridsize / 3); // density of maze, makes it havea lot of walls og val of 10
squaresize = 100; //size of square in pixels
MAXPOS = gridsize * squaresize; // cal to get density of maze
SKYCOLOR = 14548957;

startRadiusConst = .8 * MAXPOS;
maxRadiusConst = 10 * MAXPOS;
ABHandler.MAXCAMERAPOS = maxRadiusConst, ABHandler.GROUNDZERO = !0;

// change background world with unique names /uploads/c123ian/buttworld.jpg
const SKYBOX_ARRAY = ["/uploads/starter/dawnmountain-xpos.png", "/uploads/starter/dawnmountain-xneg.png", "/uploads/starter/dawnmountain-ypos.png", "/uploads/starter/dawnmountain-yneg.png", "/uploads/starter/dawnmountain-zpos.png", "/uploads/starter/dawnmountain-zneg.png"]

// the Mind's movement options
ACTION_LEFT = 0;
ACTION_RIGHT = 1;
ACTION_UP = 2;
ACTION_DOWN = 3;
ACTION_STAYSTILL = 4;

// Grid search
GRID_BLANK = 0;
GRID_WALL = 1;
GRID_MAZE = 2;

var BOXHEIGHT, theagent, theenemy, shape, thecube, thestar, wall_texture, agent_texture, enemy_texture, maze_texture, arrow_texture, ei, ej, ai, aj, badsteps, goodsteps, start, end, GRID = new Array(gridsize), xi = [], xj = [], starArray = [], openSet = [], closedSet = [], path = [];

function loadResources() { //sayn file loads, call initScene when all finished
    var e = new THREE.TextureLoader;
    var t = new THREE.TextureLoader;
    var a = new THREE.TextureLoader;
    var r = new THREE.TextureLoader;
    var n = new THREE.TextureLoader;

    e.load(TEXTURE_WALL, function (e) { e.minFilter = THREE.LinearFilter, wall_texture = e, asynchFinished() && initScene() });
    t.load(TEXTURE_AGENT, function (e) { e.minFilter = THREE.LinearFilter, agent_texture = e, asynchFinished() && initScene() });
    a.load(TEXTURE_ENEMY, function (e) { e.minFilter = THREE.LinearFilter, enemy_texture = e, asynchFinished() && initScene() });
    r.load(TEXTURE_MAZE, function (e) { e.minFilter = THREE.LinearFilter, maze_texture = e, asynchFinished() && initScene() });
    n.load(TEXTURE_Arrow, function (e) { e.minFilter = THREE.LinearFilter, arrow_texture = e, asynchFinished() && initScene() });

}

function asynchFinished() {
    return !!(wall_texture && agent_texture && enemy_texture && maze_texture && arrow_texture)
}

function occupied(e, t) {
    return ei == e && ej == t || (ai == e && aj == t || !!GRID[e][t].wall)
}

function translate(e, t) {
    var a = new THREE.Vector3;
    return a.y = 0, a.x = e * squaresize - MAXPOS / 2, a.z = t * squaresize - MAXPOS / 2, a
}

function heuristic(e, t) {
    return Math.abs(e.i - t.i) + Math.abs(e.j - t.j)
}

// remove elem from array, loop check elem, 
function removeFromArray(e, t) {
    //1) loop through array e backwards (if forward and delete, have to shift all elem)
    //2) check if has elem
    //3) if yes, splice elem (delete and add indx from the arr)
    for (var a = e.length - 1; a >= 0; a--)e[a] == t && e.splice(a, 1)
}

/// every obj will have a f,g,h val to cal at each Spot
///- f 
///- g (known dist so far to get to spot)
///- h (heuristic, educated guess 'as the crow flies')

// constuctor for grid of Spot 

function Spot(e, t) {
    // f value, g, h <- needed to cal a cost fir every cell/Spot (init at 0)
    // i abnd j with show() so each spot has func to show itself , so as we create each spot pass in i,j and know where it is
    this.i = e;
    this.j = t;
    this.f = 0;
    this.g = 0;
    this.h = 0;
    // where did I come from?
    this.neighbors = [], this.previous = void 0, 0 === e || e === gridsize - 1 || 0 === t || t === gridsize - 1 ? (this.wall = !0, shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (thecube = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({ map: wall_texture }), thecube.position.copy(translate(e, t)), ABWorld.scene.add(thecube)) : this.wall = !1;

    for (var a = 0; a <= NOBOXES; a++)e === xi[a] && t === xj[a] && (this.wall = !0);
    this.addNeighbors = function (e) {
        var t = this.i, a = this.j; t < gridsize - 1 && this.neighbors.push(e[t + 1][a]), t > 0 && this.neighbors.push(e[t - 1][a]), a < gridsize - 1 && this.neighbors.push(e[t][a + 1]), a > 0 && this.neighbors.push(e[t][a - 1])
    }
}

function initScene() {
    var e, t;
    for (e = 0; e < gridsize; e++)GRID[e] = new Array(gridsize);
    for (var a = 0, r = 1; r <= NOBOXES; r++)e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2), xi[a] = e, xj[a] = t, shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (thecube = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({ map: maze_texture }), thecube.position.copy(translate(e, t)), ABWorld.scene.add(thecube), a++; for (e = 0; e < gridsize; e++)for (t = 0; t < gridsize; t++)GRID[e][t] = new Spot(e, t); for (e = 0; e < gridsize; e++)for (t = 0; t < gridsize; t++)GRID[e][t].addNeighbors(GRID); do { e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2) } while (occupied(e, t)); ei = e, ej = t, shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (theenemy = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({ map: enemy_texture }), ABWorld.scene.add(theenemy), drawEnemy(); do { e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2) } while (occupied(e, t)); ai = e, aj = t, shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (theagent = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({ map: agent_texture }), ABWorld.scene.add(theagent), drawAgent(), ABWorld.scene.background = (new THREE.CubeTextureLoader).load(SKYBOX_ARRAY, function () { ABWorld.render(), AB.removeLoading(), AB.runReady = !0 })
}

// draw animation loop

function drawEnemy() {
    theenemy.position.copy(translate(ei, ej)), ABWorld.lookat.copy(theenemy.position)
}

function drawPath() {
    for (var e = 0; e < path.length - 2; e++)if (path.length > 2) { var t = path[e]; shape = new THREE.BoxGeometry(squaresize, .1, squaresize), (thestar = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({ map: arrow_texture }), starArray[e] = thestar.uuid, thestar.position.copy(translate(t.i, t.j)), ABWorld.scene.add(thestar) }
}

function drawAgent() {
    theagent.position.copy(translate(ai, aj)), ABWorld.follow.copy(theagent.position)
}

// AStar loop ----------------------------------------------------------------------------//
// openset are nodes that need to be eval
// closedset stores list of all nodes that finished being eval, dont need to revisit
// finsih when openset empty and no solution as cant rach target OR found target

// openSet starts with 1 node (starting node using start var [ei][ej])
// closedSet starts empty []

function AStar() {
    for (openSet = [], closedSet = [], path = [], start = GRID[ei][ej], end = GRID[ai][aj], openSet.push(start);  // end will be target?
        openSet.length > 0;) { //find lowest is the winner 
        for (var e = 0, t = 0; t < openSet.length; t++)openSet[t].f < openSet[e].f && (e = t);
        var a = openSet[e];
        // if found target a, 
        if (a === end) {
            console.log("success - fyou caught the target");
            break
        }
        // need to create remove method (a == current), see above
        removeFromArray(openSet, a), closedSet.push(a);
        // 1) check first node which default is the best thus add (push) elem from openSet to closedSet (flag as checked)
        //2) next we check the winning node's neighbours (as long as they have not already been checked and present on closedSet)
        var r = a.neighbors;

        for (t = 0; t < r.length; t++) {
            var n = r[t];
            if (!closedSet.includes(n) && !n.wall) {
                var o = a.g + heuristic(n, a), i = !1;
                openSet.includes(n) ? o < n.g && (n.g = o, i = !0) : (n.g = o, i = !0, openSet.push(n)), i && (n.h = heuristic(n, end), n.f = n.g + n.h, n.previous = a)
            }
        }
        var s = a;
        for ((path = []).push(s); s.previous;)path.push(s.previous), s = s.previous
    }
    for (t = 0; t < gridsize; t++)
        for (var u = 0; u < gridsize; u++)0 !== GRID[t][u].f && (GRID[t][u].f = 0, GRID[t][u].g = 0, GRID[t][u].h = 0, GRID[t][u].previous = void 0)
}
function removePath() {
    console.log("removing");
    for (var e = 0; e < starArray.length; e++) {
        var t = starArray[e]; const a = ABWorld.scene.getObjectByProperty("uuid", t); ABWorld.scene.remove(a)
    }
}

// moving enemy logic
function moveLogicalEnemy() {
    AStar(), drawPath();
    var e = path.length, t = path[e - 2]; occupied(t.i, t.j) || (ei = t.i, ej = t.j)
}
function sleep(e) {
    return new Promise(t => setTimeout(t, e))
}


function moveLogicalAgent(e) {
    var t = ai, a = aj; e == ACTION_LEFT ? t-- : e == ACTION_RIGHT ? t++ : e == ACTION_UP ? a++ : e == ACTION_DOWN && a--, occupied(t, a) || (ai = t, aj = a)
}
var OURKEYS = [37, 38, 39, 40]; function ourKeys(e) {
    return OURKEYS.includes(e.keyCode)
}

function keyHandler(e) {
    return !AB.runReady || (!ourKeys(e) || (37 == e.keyCode && moveLogicalAgent(ACTION_LEFT), 38 == e.keyCode && moveLogicalAgent(ACTION_DOWN), 39 == e.keyCode && moveLogicalAgent(ACTION_RIGHT), 40 == e.keyCode && moveLogicalAgent(ACTION_UP), e.stopPropagation(), e.preventDefault(), !1))
}

function badstep() {
    return Math.abs(ei - ai) < 2 && Math.abs(ej - aj) < 2
}

function agentBlocked() {
    return occupied(ai - 1, aj) && occupied(ai + 1, aj) && occupied(ai, aj + 1) && occupied(ai, aj - 1)
}

function updateStatusBefore(e) {
    AB.world.getState(); AB.msg(" Step: " + AB.step + " &nbsp; a = (" + e + ") ")
}

function updateStatusAfter() {
    AB.world.getState(); var e = goodsteps / AB.step * 100; AB.msg(" Bad steps: " + badsteps + " &nbsp; Good steps: " + goodsteps + " &nbsp; Score: " + e.toFixed(2) + "% ", 2)
}
AB.world.newRun = function () {
    AB.loadingScreen(), AB.runReady = !1, badsteps = 0, goodsteps = 0, BOXHEIGHT = squaresize, ABWorld.init3d(startRadiusConst, maxRadiusConst, 14548957), loadResources(), document.onkeydown = keyHandler
},
    AB.world.getState = function () {
        return [ai, aj, ei, ej, GRID]
    },

    AB.world.takeAction = function (e) {
        updateStatusBefore(e), moveLogicalAgent(e), AB.step % 2 == 0 && moveLogicalEnemy(), badstep() ? badsteps++ : goodsteps++, drawAgent(), drawEnemy(), updateStatusAfter(), agentBlocked() && (AB.abortRun = !0, goodsteps = 0, musicPause(), soundAlarm()), sleep(100).then(() => { removePath() })
    },
    AB.world.endRun = function () {
        musicPause(), AB.abortRun ? AB.msg(" <br> <font color=red> <B> Agent trapped. Final score zero. </B> </font>   ", 3) : AB.msg(" <br> <font color=green> <B> Run over. </B> </font>   ", 3)
    },
    AB.world.getScore = function () {
        var e = goodsteps / AB.maxSteps * 100; return Math.round(100 * e) / 100
    };
var backmusic = AB.backgroundMusic(MUSIC_BACK);
function musicPlay() {
    backmusic.play()
}
function musicPause() {
    backmusic.pause()
}
function soundAlarm() {
    new Audio(SOUND_ALARM).play()
}