// Cloned by David Jusev on 1 Dec 2022 from Mind "Complex Mind (clone by yilin li)" by yilin li
// Please leave this clone trail here.
// Cloned by yilin li on 25 Oct 2021 from World "Enemy Chase Agents" by Minhui Chen
// Please leave this clone trail here.
AB.clockTick = 100,
AB.maxSteps = 1e3,
AB.screenshotStep = 50;
const show3d = !0,
TEXTURE_WALL = "/uploads/minhui96/wall.jpg",
TEXTURE_MAZE = "/uploads/minhui96/maze.jpg",
TEXTURE_AGENT = "/uploads/minhui96/agent.jpg",
TEXTURE_ENEMY = "/uploads/minhui96/enemy.png",
MUSIC_BACK = "/uploads/starter/Defense.Line.mp3",
SOUND_ALARM = "/uploads/starter/air.horn.mp3",
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;
var BOXHEIGHT, theagent, theenemy, wall_texture, agent_texture, enemy_texture, maze_texture, ei, ej, ai, aj, badsteps, goodsteps, pathline, occ = new Array(gridsize),
GRID = new Array(gridsize);
function loadResources() {
var e = new THREE.TextureLoader,
a = new THREE.TextureLoader,
t = new THREE.TextureLoader,
i = new THREE.TextureLoader;
e.load(TEXTURE_WALL,
function(e) {
e.minFilter = THREE.LinearFilter,
wall_texture = e,
asynchFinished() && initScene()
}),
a.load(TEXTURE_AGENT,
function(e) {
e.minFilter = THREE.LinearFilter,
agent_texture = e,
asynchFinished() && initScene()
}),
t.load(TEXTURE_ENEMY,
function(e) {
e.minFilter = THREE.LinearFilter,
enemy_texture = e,
asynchFinished() && initScene()
}),
i.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, a) {
return ei == e && ej == a || (ai == e && aj == a || (occ[e][a] == GRID_WALL || occ[e][a] == GRID_MAZE))
}
function translate(e, a) {
var t = new THREE.Vector3;
return t.y = 0,
t.x = e * squaresize - MAXPOS / 2,
t.z = a * squaresize - MAXPOS / 2,
t
}
function initScene() {
var e, a, t, i;
for (e = 0; e < gridsize; e++) GRID[e] = new Array(gridsize);
for (e = 0; e < gridsize; e++) occ[e] = new Array(gridsize);
for (e = 0; e < gridsize; e++) for (a = 0; a < gridsize; a++) 0 === e || e == gridsize - 1 || 0 === a || a == gridsize - 1 ? (occ[e][a] = GRID_WALL, t = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (i = new THREE.Mesh(t)).material = new THREE.MeshBasicMaterial({
map: wall_texture
}), i.position.copy(translate(e, a)), ABWorld.scene.add(i)) : occ[e][a] = GRID_BLANK;
for (var o = 1; o <= NOBOXES; o++) e = AB.randomIntAtoB(1, gridsize - 2),
a = AB.randomIntAtoB(1, gridsize - 2),
occ[e][a] = GRID_MAZE,
t = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize),
(i = new THREE.Mesh(t)).material = new THREE.MeshBasicMaterial({
map: maze_texture
}),
i.position.copy(translate(e, a)),
ABWorld.scene.add(i);
for (e = 0; e < gridsize; e++) for (a = 0; a < gridsize; a++) GRID[e][a] = new Spot(e, a);
for (e = 0; e < gridsize; e++) for (a = 0; a < gridsize; a++) GRID[e][a].addNeighbors(GRID);
console.table(GRID);
do {
e = AB.randomIntAtoB(1, gridsize - 2), a = AB.randomIntAtoB(1, gridsize - 2)
} while ( occupied ( e , a ));
ei = e,
ej = a,
t = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize),
(theenemy = new THREE.Mesh(t)).material = new THREE.MeshBasicMaterial({
map: enemy_texture
}),
ABWorld.scene.add(theenemy),
drawEnemy();
do {
e = AB.randomIntAtoB(1, gridsize - 2), a = AB.randomIntAtoB(1, gridsize - 2)
} while ( occupied ( e , a ));
ai = e,
aj = a,
t = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize),
(theagent = new THREE.Mesh(t)).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)
}
const linecolor = 6750003;
function heuristic(e, a) {
var t = new THREE.Vector3(e.i, 0, e.j),
i = new THREE.Vector3(a.i, 0, a.j);
return t.distanceTo(i)
}
function removeFromArray(e, a) {
for (var t = e.length - 1; t >= 0; t--) e[t] == a && e.splice(t, 1)
}
function Spot(e, a) {
this.i = e,
this.j = a,
this.f = 0,
this.g = 0,
this.h = 0,
this.neighbors = [],
this.previous = void 0,
0 === occ[e][a] ? this.obstacle = !1 : this.obstacle = !0,
this.addNeighbors = function(e) {
var a = this.i,
t = this.j;
a < gridsize - 1 && this.neighbors.push(e[a + 1][t]),
a > 0 && this.neighbors.push(e[a - 1][t]),
t < gridsize - 1 && this.neighbors.push(e[a][t + 1]),
t > 0 && this.neighbors.push(e[a][t - 1]),
a > 0 && t > 0 && this.neighbors.push(e[a - 1][t - 1]),
a < gridsize - 1 && t > 0 && this.neighbors.push(e[a + 1][t - 1]),
a > 0 && t < gridsize - 1 && this.neighbors.push(e[a - 1][t + 1]),
a < gridsize - 1 && t < gridsize - 1 && this.neighbors.push(e[a + 1][t + 1])
}
}
function trap() {
return ! 1 === GRID[ai - 1][aj].obstacle && !0 === GRID[ai + 1][aj].obstacle && !0 === GRID[ai][aj - 1].obstacle && !0 === GRID[ai][aj + 1].obstacle ? 0 : !0 === GRID[ai - 1][aj].obstacle && !1 === GRID[ai + 1][aj].obstacle && !0 === GRID[ai][aj - 1].obstacle && !0 === GRID[ai][aj + 1].obstacle ? 1 : !0 === GRID[ai - 1][aj].obstacle && !0 === GRID[ai + 1][aj].obstacle && !1 === GRID[ai][aj - 1].obstacle && !0 === GRID[ai][aj + 1].obstacle ? 2 : !0 === GRID[ai - 1][aj].obstacle && !0 === GRID[ai + 1][aj].obstacle && !0 === GRID[ai][aj - 1].obstacle && !1 === GRID[ai][aj + 1].obstacle ? 3 : 4
}
function enemyPath() {
var e, a, t = [],
o = [],
n = [];
switch (e = GRID[ei][ej], trap()) {
case 0:
a = GRID[ai - 1][aj];
break;
case 1:
a = GRID[ai + 1][aj];
break;
case 2:
a = GRID[ai][aj - 1];
break;
case 3:
a = GRID[ai][aj + 1];
break;
case 4:
a = GRID[ai][aj]
}
t.push(e);
for (var r = !1; t.length > 0;) {
var s = 0;
for (i = 0; i < t.length; i++) t[i].f < t[s].f && (s = i);
var c = t[s];
if (c === a) {
console.log("Done"),
r = !0;
break
}
removeFromArray(t, c),
o.push(c);
var u = c.neighbors;
for (i = 0; i < u.length; i++) {
var d = u[i];
if (!o.includes(d) && !d.obstacle) {
var l = c.g + heuristic(d, c);
console.log("tempG" + l),
console.log("tempG" + l);
var g = !1;
t.includes(d) ? l < d.g && (d.g = l, g = !0) : (d.g = l, g = !0, t.push(d)),
g && (d.h = heuristic(d, a), d.f = d.g + d.h, console.log("FFFF:" + d.f), d.previous = c)
}
}
}
if (!1 === r) return console.log("fail"),
n;
console.log("time for find path: 0"),
console.log("enemy current: " + ei + "," + ej);
var p = c,
A = c;
for (n.push(p); p.previous;) n.push(p.previous),
p = p.previous,
A.previous = void 0,
A = p;
return n
}
function drawPath(e) {
pathline && ABWorld.scene.remove(pathline),
e.pop();
var a = [];
for (const i of e) {
var t = translate(i.i, i.j);
a.push(t)
}
var i = new THREE.LineBasicMaterial({
color: linecolor
}),
o = (new THREE.BufferGeometry).setFromPoints(a);
pathline = new THREE.Line(o, i),
ABWorld.scene.add(pathline)
}
function moveLogicalEnemy() {
var e, a, t = enemyPath();
if (! (t.length > 0)) return console.log("Fail!");
t.pop(),
e = t[t.length - 1].i,
a = t[t.length - 1].j,
drawPath(t),
occupied(e, a) || (ei = e, ej = a),
console.log("enemy moveto:" + ei + "," + ej)
}
function moveLogicalAgent(e) {
var a = ai,
t = aj;
e == ACTION_LEFT ? a--:e == ACTION_RIGHT ? a++:e == ACTION_UP ? t++:e == ACTION_DOWN && t--,
occupied(a, t) || (ai = a, aj = t)
}
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 a = AB.world.getState();
AB.msg(" Step: " + AB.step + " x = (" + a.toString() + ") a = (" + e + ") ")
}
function updateStatusAfter() {
var e = AB.world.getState(),
a = goodsteps / AB.step * 100;
AB.msg(" y = (" + e.toString() + ") <br> Bad steps: " + badsteps + " Good steps: " + goodsteps + " Score: " + a.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()
}