// Abdelshafa Abdala
//Student ID number: 21269020
// A* practical (2)
const WALLMOVENO=20;
WALLMOVETICK= 5e3;
AB.clockTick = 200;
// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps = 1e3;
// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep = 50;
// Take screenshot on this step. (All resources should have finished loading.) Default 50.
var start,end,diagonal=!0,
openSet=[],
closedSet=[],
neighbors=[],
path=[];
//---- global constants: -------------------------------------------------------
const show3d = !0; // Switch between 3d and 2d view (both using Three.js)
const TEXTURE_WALL = '/uploads/rania/door6.jpg' ;
const TEXTURE_MAZE = '/uploads/rania/latin9.gif' ;
const TEXTURE_AGENT = '/uploads/starter/pacman.jpg';
const TEXTURE_ENEMY = '/uploads/rania/ghost1.jpg';
const MUSIC_BACK = '/uploads/rania/Ultimate.mp3' ;
const SOUND_ALARM = '/uploads/rania/mixkit-classic-winner-alarm-1997.wav' ;
gridsize= 150,
NOBOXES=Math.trunc(gridsize*gridsize/7),
squaresize = 100;
// size of square in pixels
const MAXPOS = gridsize * squaresize; // length of one side in pixels
const SKYCOLOR = 14548957; // a number, not a string
const startRadiusConst = MAXPOS * 0.8 ; // distance from centre to start the camera at
const maxRadiusConst = MAXPOS * 10 ; // maximum distance from camera we will render things
wallCutOff=AB.randomFloatAtoB(0,.6)
ABHandler.MAXCAMERAPOS=maxRadiusConst,ABHandler.GROUNDZERO=!0;
//--- change ABWorld defaults: -------------------------------
const SKYBOX_ARRAY = [
"/uploads/rania/dawnmountain-xpos2.jpg",
"/uploads/rania/dawnmountain-xpos2.jpg",
"/uploads/rania/dawnmountain-xpos2.jpg",
"/uploads/rania/dawnmountain-xpos2.jpg",
"/uploads/rania/dawnmountain-xpos2.jpg",
"/uploads/rania/dawnmountain-xpos2.jpg"
];
// ===================================================================================================================
// === End of tweaker's box ==========================================================================================
// ===================================================================================================================
// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.
//--- Mind can pick one of these actions -----------------
const ACTION_LEFT = 0;
const ACTION_RIGHT = 1;
const ACTION_UP = 2;
const ACTION_DOWN = 3;
const ACTION_STAYSTILL = 4;
// contents of a grid square
const GRID_BLANK = 0;
const GRID_WALL = 1;
const GRID_MAZE = 2;
const VERBOSE_LOG =!1;
var BOXHEIGHT,theagent,theenemy,wall_texture,agent_texture,enemy_texture,maze_texture,ei,ej,ai,aj,badsteps,goodsteps,GRID=new Array(gridsize),shownPath=[],path=[];
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||(GRID[e][a]==GRID_WALL||GRID[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++)
for(a=0;a<gridsize;a++)0==e||e==gridsize-1||0==a||a==gridsize-1?(GRID[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)):GRID[e][a]=GRID_BLANK;
for
(
var r=1;r<=NOBOXES;r++)e=AB.randomIntAtoB(1,gridsize-2),
a=AB.randomIntAtoB(1,gridsize-2),GRID[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);
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)}
function removeFromArray(e,a)
{
for
(
var t=e.length-1;t>=0;t--)e[t]==a&&e.splice(t,1)}
function MakeSpot(e,a){this.i=e,this.j=a,this.f=0,this.g=0,this.h=0,this.neighbors=[],
this.previous=void 0,this.wall=GRID[e][a]!==GRID_BLANK,this.addNeighbors=function(e)
{
var a=this.i,
t=this.j;
a<gridsize-1&&this.neighbors.push(e[a+1][t]),
t<gridsize-1&&this.neighbors.push(e[a][t+1]),
a>0&&this.neighbors.push(e[a-1][t]),t>0&&this.neighbors.push(e[a][t-1])}}
function heuristic(e,a)
{
return Math.abs(e.i-a.i)+Math.abs(e.j-a.j)}
function euc_heuristic(e,a)
{
return Math.sqrt(Math.pow(e.i-a.i,2)+Math.pow(e.j-a.j,2))}
function oct_heuristic(e,a)
{
return Math.max(Math.abs(e.i-a.i),Math.abs(e.j-a.j))+(Math.sqrt(2)-1)*Math.min(Math.abs(e.i-a.i),Math.abs(e.j-a.j))}
function chebyshev_heuristic(e,a)
{
return Math.max((Math.abs(e.i-a.i),Math.abs(e.j-a.j)))}
function highlightPath(e,a)
{
for(
var t=0;t<e.length-1;t++)shape=new THREE.BoxGeometry(squaresize,.1,squaresize),
ShownPath=new THREE.Mesh(shape),
ShownPath.material=new THREE.MeshBasicMaterial({color:a}),
ShownPath.position.copy(translate(e[t].i,e[t].j)),
ABWorld.scene.add(ShownPath),
shownPath.push(ShownPath)}
function moveLogicalEnemy()
{
for
(
var e=new Array(gridsize),a=[],t=[],i=0;i<shownPath.length;i++)ABWorld.scene.remove(shownPath[i]);
for(i=0;i<gridsize;i++)e[i]=new Array(gridsize);
for(i=0;i<gridsize;i++)
for
(
var r=0;r<gridsize;r++)e[i][r]=new MakeSpot(i,r);
for(i=0;i<gridsize;i++)for(r=0;r<gridsize;r++)e[i][r].addNeighbors(e);
for(a.push(e[ei][ej]);a.length>0;){var o=0;for(i=0;i<a.length;i++)a[i].f<a[o].f&&(o=i);
var n=a[o];
if(n===e[ai][aj])
{
var s=[],u=n;
for(s.push(u);u.previous;)s.push(u.previous),u=u.previous;highlightPath(s,255);
var d=s.length-2;occupied(s[d].i,s[d].j)||(ei=s[d].i,ej=s[d].j);
break}removeFromArray(a,n),t.push(n);
var h=n.neighbors;
for(i=0;i<h.length;i++){var c=h[i];if(c[i]===e[ai][aj]){c.previous=n;
break}if(!t.includes(c)&&!c.wall){var l=n.g+heuristic(c,n),p=!1;
a.includes(c)?l<c.g&&(c.g=l,p=!0):(c.g=l,p=!0,
a.push(c)),p&&(c.h=heuristic(c,e[ai][aj]),c.f=c.g+c.h,c.previous=n)}}}}
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=yellow> <B> Agent trapped. Final score zero. </B> </font> ",3):AB.msg(" <br> <font color=coral> <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("/uploads/rania/Ultimate.mp3");
function musicPlay(){backmusic.play()}function musicPause(){backmusic.pause()}
function soundAlarm(){new Audio("/uploads/rania/mixkit-classic-winner-alarm-1997.wav").play()}