Code viewer for World: Complex World (clone by yi...
// Cloned by Zephyr Chai on 6 Nov 2021 from World "Complex World (clone by yilin li)" by yilin li
// Please leave this clone trail here.

AB.clockTick = 100, AB.maxSteps = 1e3, AB.screenshotStep = 50;
const show3d = !0, TEXTURE_WALL = "/uploads/lin123/images.jpeg", TEXTURE_MAZE = "/uploads/lin123/300.jpeg",
    TEXTURE_AGENT = "/uploads/lin123/1280px-Fantomo_ruga.svg.png",
    TEXTURE_ENEMY = "/uploads/lin123/1920px-MOREmoji_pirate.svg.png", gridsize = 50,
    NOBOXES = Math.trunc(gridsize * gridsize / 3), squaresize = 100, MAXPOS = gridsize * squaresize,
    SKYCOLOR = 14548957, startRadiusConst = .8 * MAXPOS, maxRadiusConst = 10 * MAXPOS;
ABHandler.MAXCAMERAPOS = maxRadiusConst, ABHandler.GROUNDZERO = !0;
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"],
    ACTION_LEFT = 0, ACTION_RIGHT = 1, ACTION_UP = 2, ACTION_DOWN = 3, ACTION_STAYSTILL = 4, GRID_BLANK = 0,
    GRID_WALL = 1, GRID_MAZE = 2, diagonal = !0;
var BOXHeiGHT, theagent, theenemy, wall_texture, agent_texture, enemy_texture, maze_texture, ei, ej, ai, aj, badsteps,
    goodsteps, start, end, GRID = new Array(gridsize), openSet = [], closedSet = [], path = [];

function loadResources() {
    var e = new THREE.TextureLoader, t = new THREE.TextureLoader, n = new THREE.TextureLoader,
        a = 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()
    }), n.load(TEXTURE_ENEMY, function (e) {
        e.minFilter = THREE.LinearFilter, enemy_texture = e, asynchFinished() && initScene()
    }), a.load(TEXTURE_MAZE, function (e) {
        e.minFilter = THREE.LinearFilter, maze_texture = e, asynchFinished() && initScene()
    })
}

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

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

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

function initScene() {
    var e, t, n, a;
    for (e = 0; e < gridsize; e++) GRID[e] = new Array(gridsize);
    for (e = 0; e < gridsize; e++) for (t = 0; t < gridsize; t++) 0 == e || e == gridsize - 1 || 0 == t || t == gridsize - 1 ? (GRID[e][t] = GRID_WALL, n = new THREE.BoxGeometry(squaresize, BOXHeiGHT, squaresize), (a = new THREE.Mesh(n)).material = new THREE.MeshBasicMaterial({map: wall_texture}), a.position.copy(translate(e, t)), ABWorld.scene.add(a)) : GRID[e][t] = GRID_BLANK;
    for (var o = 1; o <= NOBOXES; o++) e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2), GRID[e][t] = GRID_MAZE, n = new THREE.BoxGeometry(squaresize, BOXHeiGHT, squaresize), (a = new THREE.Mesh(n)).material = new THREE.MeshBasicMaterial({map: maze_texture}), a.position.copy(translate(e, t)), ABWorld.scene.add(a);
    do {
        e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2)
    } while (occupied(e, t));
    ei = e, ej = t, n = new THREE.BoxGeometry(squaresize, BOXHeiGHT, squaresize), (theenemy = new THREE.Mesh(n)).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, n = new THREE.BoxGeometry(squaresize, BOXHeiGHT, squaresize), (theagent = new THREE.Mesh(n)).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
    })
}

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

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

// a* methods start
let openArr = [];
let closeArr = [];
function f(ti, tj) {
  return g(ti, tj) + h(ti, tj)
}
function g(ti, tj) {
    if (ti != ei && tj != ej) {
        return 14;
    }
    return 10;
}
function h(ti, tj) {
    D = 10;
    D2 = 14;
    dx = Math.abs(ti - ai);
    dy = Math.abs(tj - aj);
    return D * (dx + dy) + (D2 - 2 * D) * Math.min(dx, dy);
}

function isValid(ti, tj) {
    if (GRID[ti][tj] == GRID_WALL || GRID[ti][tj] == GRID_MAZE) {
        return false;
    }
    return true;
}
function getMinFTarget() {
    temp = -1;
    minCost = Number.MAX_VALUE;
    for (i = 0; i < openArr.length; i++) {
        currentCost = f(openArr[i].x, openArr[i].y);
        if (currentCost < minCost) {
            temp = i;
            minCost = currentCost;
        }
    }
    return temp;
}
function isStartPoint(node) {
    if (node.x == ei && node.y == ej) {
        return true;
    }
    return false;
}
function isTargetPoint(node) {
    if (node.x == ai && node.y == aj) {
        return true;
    }
    return false;
}
function isInArr(node, arr) {
    for (i = 0; i < arr.length; i++) {
        if (node.x == arr[i].x && node.y == arr[i].y) {
            return true;
        }
    }
    return false;
}
function isInOpenArr(node) {
    return isInArr(node, openArr);
}
function isInCloseArr(node) {
    return isInArr(node, closeArr);
}
function processPoint(ti, tj, parent) {
    if (!isValid(ti, tj)) {
        return;
    }
    node = {x: ti, y: tj, parent: parent, cost: f(ti, tj)};
    if (isInCloseArr(node)) {
        return;
    }
    if (!isInOpenArr(node)) {
        /*if (parent.parent == null && !isStartPoint(parent)) {
            console.log('error2, ', parent);
            return;
        }*/
        //console.log('push', node);
        //openArr.push({x: node.x, y: node.y, parent: {x: parent.x, y: parent.y, parent: parent.parent, cost: parent.cost}, cost:f(ti, tj)});
        openArr.push(node);
    }
}
function getMovement(node) {
    while(true) {
        if (isStartPoint(node.parent)) {
            ei = node.x;
            ej = node.y;
            return;
        }
        node = node.parent;
    }
}
function Astar() {
    openArr = [];
    closeArr = [];
    initialNode = {x: ei, y: ej, parent: null, cost: 0};
    openArr.push(initialNode);
    while(true) {
        i = getMinFTarget();
        if (i < 0) {
            console.log('a* failure');
            return;
        }
        currentNode = openArr[i];
        if (isTargetPoint(currentNode)) {
            getMovement(currentNode);
            return;
        }
        x = currentNode.x;
        y = currentNode.y;
        openArr.splice(i);
        closeArr.push(currentNode);
        
        processPoint(x-1, y+1, currentNode);
        processPoint(x-1, y, currentNode);
        processPoint(x-1, y-1, currentNode);
        processPoint(x, y+1, currentNode);
        processPoint(x, y-1, currentNode);
        processPoint(x+1, y+1, currentNode);
        processPoint(x+1, y, currentNode);
        processPoint(x+1, y-1, currentNode);
    }
}
// a* methods end

function moveLogicalEnemy() {
    // var e, t;
    // ei < ai && (e = AB.randomIntAtoB(ei, ei + 1)), ei == ai && (e = ei), ei > ai && (e = AB.randomIntAtoB(ei - 1, ei)), ej < aj && (t = AB.randomIntAtoB(ej, ej + 1)), ej == aj && (t = ej), ej > aj && (t = AB.randomIntAtoB(ej - 1, ej)), occupied(e, t) || (ei = e, ej = t)
    
    Astar();
}

function moveLogicalAgent(e) {
    var t = ai, n = aj;
    e == ACTION_LEFT ? t-- : e == ACTION_RIGHT ? t++ : e == ACTION_UP ? n++ : e == ACTION_DOWN && n--, occupied(t, n) || (ai = t, aj = n)
}

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) {
    var t = AB.world.getState();
    AB.msg(" Step: " + AB.step + " &nbsp; x = (" + t.toString() + ") &nbsp; a = (" + e + ") ")
}

function updateStatusAfter() {
    var e = AB.world.getState(), t = goodsteps / AB.step * 100;
    AB.msg(" &nbsp; y = (" + e.toString() + ") <br> Bad steps: " + badsteps + " &nbsp; Good steps: " + goodsteps + " &nbsp; Score: " + t.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]
}, 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())
}, 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()
}