// Cloned by Chinmay on 13 Nov 2021 from Mind "CA686~2" by Himanshu Warekar
// Please leave this clone trail here.
class Node{constructor(t,e,i){this.world=t,this.GRID=t.GRID,this.idx=e,this.jdx=i,this.columns=t.gridSize,this.rows=t.gridSize,this.squareSize=t.squareSize,this.calculatedTotal=0,this.stepCost=0,this.heuristicEstimate=0,this.neighbours=[],this.previous=null,this.gridWall=!1,this.mazeWall=!1,this.isEmpty=!1,this.tempCube=null,this.Cube=null}addNeighbours(){this.idx<this.columns-1&&this.neighbours.push(this.GRID[this.idx+1][this.jdx]),this.idx>0&&this.neighbours.push(this.GRID[this.idx-1][this.jdx]),this.jdx<this.rows-1&&this.neighbours.push(this.GRID[this.idx][this.jdx+1]),this.jdx>0&&this.neighbours.push(this.GRID[this.idx][this.jdx-1])}setAsGridWall(){this.gridWall=!0}setAsMazeWall(){this.mazeWall=!0}setAsEmpty(){this.isEmpty=!0}isWall(){return this.gridWall||this.mazeWall}showTemperoryPath(){this.Shape=new THREE.BoxGeometry(30,30,30),this.Cube=new THREE.Mesh(this.Shape),this.Cube.material=new THREE.MeshBasicMaterial,this.Cube.position.copy(this.translate(this.idx,this.jdx)),this.Cube.material.color.setColorName("blue"),this.Cube.material.opacity=.25,ABWorld.scene.add(this.Cube)}removeTemperoryPath(){ABWorld.scene.remove(this.Cube),this.Shape=null,this.Cube=null}showPermanentPath(){this.Shape=new THREE.BoxGeometry(30,30,30),this.Cube=new THREE.Mesh(this.Shape),this.Cube.material=new THREE.MeshBasicMaterial,this.Cube.position.copy(this.translate(this.idx,this.jdx)),this.Cube.material.color.setColorName("green"),this.Cube.material.opacity=.25,ABWorld.scene.add(this.Cube)}removePermanentPath(){ABWorld.scene.remove(this.Cube),this.Shape=null,this.Cube=null}showCornerIndicator(){this.Shape=new THREE.BoxGeometry(30,30,30),this.Cube=new THREE.Mesh(this.Shape),this.Cube.material=new THREE.MeshBasicMaterial,this.Cube.position.copy(this.translate(this.idx,this.jdx)),this.Cube.material.color.setColorName("orange"),this.Cube.material.opacity=.25,ABWorld.scene.add(this.Cube)}removeCornerIndicator(){ABWorld.scene.remove(this.Cube),this.Shape=null,this.Cube=null}translate(t,e){let i=new THREE.Vector3;return i.y=0,i.x=t*this.world.squareSize-this.world.MAXPOS/2,i.z=e*this.world.squareSize-this.world.MAXPOS/2,i}}class Analytics{constructor(){this.API_URL="https://api.airtable.com/v0/appaNU1MlDvrEYsnk/Table%201",this.API_KEY="a2V5T1BOeXRjUElpV3pCU0c="}sendAnalytics(t,e,i,s,h,n){let r={records:[{fields:{world:t,totalSteps:e,goodSteps:i,badSteps:s,score:h,agentBlocked:n}}]};$.ajax({type:"POST",url:this.API_URL,contentType:"application/json",data:JSON.stringify(r),headers:{Authorization:"Bearer "+atob(this.API_KEY)},success:function(){}})}}class complexWorld{constructor(){AB.clockTick=100,AB.maxSteps=1e3,AB.screenshotStep=50,this.WORLD="Herding World",this.show3d=!0,this.TEXTURE_WALL="/uploads/starter/door.jpg",this.TEXTURE_MAZE="/uploads/starter/latin.jpg",this.TEXTURE_AGENT="/uploads/starter/pacman.jpg",this.TEXTURE_ENEMY="/uploads/starter/ghost.3.png",this.MUSIC_BACK="/uploads/starter/Defense.Line.mp3",this.SOUND_ALARM="/uploads/starter/air.horn.mp3",this.gridSize=50,this.NOBOXES=Math.trunc(this.gridSize*this.gridSize/3),this.squareSize=100,this.MAXPOS=this.gridSize*this.squareSize,this.SKYCOLOR=14548957,this.startRadiusConst=.8*this.MAXPOS,this.maxRadiusConst=10*this.MAXPOS,ABHandler.MAXCAMERAPOS=this.maxRadiusConst,ABHandler.GROUNDZERO=!0,this.SKYBOX_ARRAY=["/uploads/hrwx/black.jpg","/uploads/hrwx/black.jpg","/uploads/hrwx/black.jpg","/uploads/hrwx/black.jpg","/uploads/hrwx/black.jpg","/uploads/hrwx/black.jpg"],this.ACTION_LEFT=0,this.ACTION_RIGHT=1,this.ACTION_UP=2,this.ACTION_DOWN=3,this.ACTION_STAYSTILL=4,this.GRID_BLANK=0,this.GRID_WALL=1,this.GRID_MAZE=2,this.BOXHEIGHT,this.GRID=new Array(this.gridSize),this.theAgent=null,this.theEnemy=null,this.wall_texture=null,this.agent_texture=null,this.enemy_texture=null,this.maze_texture=null,this.enemyIdx=null,this.enemyJdx=null,this.agentIdx=null,this.agentJdx=null,this.badSteps=null,this.goodSteps=null,this._goodSteps=null,this.OURKEYS=[37,38,39,40],this.initialized=!1,this.path=[],this.pathHistory=[],this.trapLocations=[],this.stopCounter=0,this.loadResources(),this.initMusic(),this.initAnalytics()}loadResources(){this.initWallTexture(),this.initAgentTexture(),this.initEnemyTexture(),this.initMazeTexture()}initAnalytics(){this.analytics=new Analytics}initWallTexture(){let t=this;(new THREE.TextureLoader).load(this.TEXTURE_WALL,function(e){e.minFilter=THREE.LinearFilter,t.wall_texture=e,t.resourcesLoaded()&&t.initScene()})}initAgentTexture(){let t=this;(new THREE.TextureLoader).load(this.TEXTURE_AGENT,function(e){e.minFilter=THREE.LinearFilter,t.agent_texture=e,t.resourcesLoaded()&&t.initScene()})}initEnemyTexture(){let t=this;(new THREE.TextureLoader).load(this.TEXTURE_ENEMY,function(e){e.minFilter=THREE.LinearFilter,t.enemy_texture=e,t.resourcesLoaded()&&t.initScene()})}initMazeTexture(){let t=this;(new THREE.TextureLoader).load(this.TEXTURE_MAZE,function(e){e.minFilter=THREE.LinearFilter,t.maze_texture=e,t.resourcesLoaded()&&t.initScene()})}initMusic(){this.music=AB.backgroundMusic(this.MUSIC_BACK)}playMusic(){this.music.play()}soundAlarm(){new Audio(this.SOUND_ALARM).play()}pauseMusic(){this.music.pause()}resourcesLoaded(){return this.wall_texture&&this.agent_texture&&this.enemy_texture&&this.maze_texture}newRun(){AB.loadingScreen(),AB.runReady=!1,this.badSteps=0,this.goodSteps=0,this.show3d?(this.BOXHEIGHT=this.squareSize,ABWorld.init3d(this.startRadiusConst,this.maxRadiusConst,this.SKYCOLOR)):(this.BOXHEIGHT=1,ABWorld.init2d(this.startRadiusConst,this.maxRadiusConst,this.SKYCOLOR)),this.loadResources(),document.onkeydown=AB.world.customKeyHandler}endRun(){this.pauseMusic(),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);let t=this._goodSteps/(AB.step-1)*100;this.analytics.sendAnalytics(this.WORLD,AB.step-1,this._goodSteps,this.badSteps,parseFloat(t.toFixed(2)),this.isAgentBlocked()),setTimeout(()=>{window.location.reload()},5e3)}isOccupied(t,e){return this.enemyIdx===t&&this.enemyJdx===e||(this.agentIdx===t&&this.agentJdx===e||!!this.GRID[t][e].isWall())}isBadStep(t,e){return t=t||this.enemyIdx,e=e||this.enemyJdx,Math.abs(t-this.agentIdx)<2&&Math.abs(e-this.agentJdx)<2}isAgentBlocked(){return this.isOccupied(this.agentIdx-1,this.agentJdx)&&this.isOccupied(this.agentIdx+1,this.agentJdx)&&this.isOccupied(this.agentIdx,this.agentJdx-1)&&this.isOccupied(this.agentIdx,this.agentJdx+1)}isAgentKindaBlocked(){return 3===[this.isOccupied(this.agentIdx-1,this.agentJdx),this.isOccupied(this.agentIdx+1,this.agentJdx),this.isOccupied(this.agentIdx,this.agentJdx-1),this.isOccupied(this.agentIdx,this.agentJdx+1)].filter(t=>!0===t).length}ourKeys(t){return this.OURKEYS.includes(t.keyCode)}initScene(){this.initialized||(this.setupWalls(),this.setupMaze(),this.setupNeighbours(),this.setupTrapLocations(),this.setupEnemy(),this.setupAgent(),this.initialized=!0)}setupWalls(){let t=null,e=null;for(let i=0;i<this.gridSize;i++){this.GRID[i]=new Array(this.gridSize);for(let s=0;s<this.gridSize;s++)if(i&&i!==this.gridSize-1&&s&&s!==this.gridSize-1){let t=new Node(this,i,s);t.setAsEmpty(),this.GRID[i][s]=t}else{let h=new Node(this,i,s);h.setAsGridWall(),this.GRID[i][s]=h,t=new THREE.BoxGeometry(this.squareSize,this.BOXHEIGHT,this.squareSize),(e=new THREE.Mesh(t)).material=new THREE.MeshBasicMaterial({map:this.wall_texture}),e.position.copy(this.translate(i,s)),ABWorld.scene.add(e)}}}setupMaze(){let t=null,e=null,i=null,s=null;for(let h=1;h<=this.NOBOXES;h++){t=AB.randomIntAtoB(1,this.gridSize-2),e=AB.randomIntAtoB(1,this.gridSize-2);let h=new Node(this,t,e);h.setAsMazeWall(),this.GRID[t][e]=h,i=new THREE.BoxGeometry(this.squareSize,this.BOXHEIGHT,this.squareSize),(s=new THREE.Mesh(i)).material=new THREE.MeshBasicMaterial({map:this.maze_texture}),s.position.copy(this.translate(t,e)),ABWorld.scene.add(s)}}setupNeighbours(){for(let t=0;t<this.gridSize;t++)for(let e=0;e<this.gridSize;e++)this.GRID[t][e].addNeighbours(this.GRID)}setupEnemy(){let t=null,e=null,i=null;do{t=AB.randomIntAtoB(1,this.gridSize-2),e=AB.randomIntAtoB(1,this.gridSize-2)}while(this.isOccupied(t,e));this.enemyIdx=t,this.enemyJdx=e,i=new THREE.BoxGeometry(this.squareSize,this.BOXHEIGHT,this.squareSize),this.theEnemy=new THREE.Mesh(i),this.theEnemy.material=new THREE.MeshBasicMaterial({map:this.enemy_texture}),ABWorld.scene.add(this.theEnemy),this.drawEnemy()}setupAgent(){let t=null,e=null,i=null;do{t=AB.randomIntAtoB(1,this.gridSize-2),e=AB.randomIntAtoB(1,this.gridSize-2)}while(this.isOccupied(t,e));this.agentIdx=t,this.agentJdx=e,i=new THREE.BoxGeometry(this.squareSize,this.BOXHEIGHT,this.squareSize),this.theAgent=new THREE.Mesh(i),this.theAgent.material=new THREE.MeshBasicMaterial({map:this.agent_texture}),ABWorld.scene.add(this.theAgent),this.drawAgent(),ABWorld.scene.background=(new THREE.CubeTextureLoader).load(this.SKYBOX_ARRAY,function(){ABWorld.render(),AB.removeLoading(),AB.runReady=!0})}setupTrapLocations(){let t=null,e=null;do{t=AB.randomIntAtoB(1,this.gridSize-2),e=AB.randomIntAtoB(1,this.gridSize-2)}while(this.isOccupied(t,e));for(let i=0;i<this.gridSize;i++)for(let s=0;s<this.gridSize;s++){let h=this.GRID[i][s];h.isWall()||1===h.neighbours.filter(t=>!t.isWall()).length&&(this.resetNodeParameters(),this.getPath({startNode:this.GRID[t][e],endNode:this.GRID[i][s],fn:()=>{this.trapLocations.push(this.GRID[i][s])}}))}}translate(t,e){let i=new THREE.Vector3;return i.y=0,i.x=t*this.squareSize-this.MAXPOS/2,i.z=e*this.squareSize-this.MAXPOS/2,i}drawEnemy(){this.theEnemy.position.copy(this.translate(this.enemyIdx,this.enemyJdx)),ABWorld.lookat.copy(this.theEnemy.position)}drawAgent(){this.theAgent.position.copy(this.translate(this.agentIdx,this.agentJdx)),ABWorld.follow.copy(this.theAgent.position)}addPath(t){this.path.push(t),this.addPathHistory(t)}addPathHistory(t){this.pathHistory.length>10&&this.pathHistory.splice(0,1),this.pathHistory.push(t)}checkPathHistory(t,e){return this.pathHistory.filter(i=>i.idx===t&&i.jdx===e).length>3}heuristic(t){let e=null,i=null,s=null;return 2===t.length?(e=t[0],s=t[1],Math.abs(e.idx-s.idx)+Math.abs(e.jdx-s.jdx)):(e=t[0],i=t[1],s=t[2],Math.min(Math.abs(e.idx-i.idx)+Math.abs(e.jdx-i.jdx),Math.abs(i.idx-s.idx)+Math.abs(i.jdx-s.jdx)))}resetNodeParameters(){for(let t=0;t<this.gridSize;t++)for(let e=0;e<this.gridSize;e++){let i=this.GRID[t][e];i&&!i.isWall()&&(i.removeTemperoryPath(),i.calculatedTotal=null,i.stepCost=null,i.heuristicEstimate=null,i.previous=null)}}moveLogicalEnemy(){this.resetNodeParameters();let t=this.GRID[this.enemyIdx][this.enemyJdx],e=this.GRID[this.agentIdx][this.agentJdx],i=this.getLocationForHerdingAgent(),s=this.getPath({startNode:t,intermediateNode:e,endNode:i}),h=[],n=null,r=null;for(h.push(s);s&&s.previous&&(h.push(s.previous),(s=s.previous)&&s.previous);)s.showTemperoryPath();if(h.length<2)return;console.log(h);let a=h[h.length-2];if(n=a.idx,r=a.jdx,!this.isOccupied(n,r)&&!this.checkPathHistory(n,r))if(!this.isBadStep(n,r)||this.isAgentKindaBlocked()||this.stopCounter>5)this.enemyIdx=n,this.enemyJdx=r,this.stopCounter=0,this.addPath(this.GRID[this.enemyIdx][this.enemyJdx]);else{this.stopCounter+=1;let t=null;try{this.path.pop(),t=this.path[this.path.length-2],this.enemyIdx=t.idx,this.enemyJdx=t.jdx}catch(t){return}}}getPath(t){console.log(t);let e=t.startNode,i=t.intermediateNode,s=t.endNode,h=t.fn,n=[e],r=[],a=null,o=0,d=t.returnTotalCost||!1,l=!0;if(i&&i!==s){let t=[[i.idx,i.jdx],[s.idx,s.jdx]].sort();this.GRID[t[1][0]][t[1][1]]===i?(s=this.GRID[t[0][0]][t[0][1]],i=this.GRID[t[1][0]][t[1][1]]):(i=this.GRID[t[0][0]][t[0][1]],s=this.GRID[t[1][0]][t[1][1]])}else i=null;let u=i||s;for(;n.length;){let t=0;for(let e=0;e<n.length;e++)n[e].calculatedTotal<n[t].calculatedTotal&&(t=e);if(a=n[t],i&&a===i&&(u=s),a===u){l=!1,h&&h();break}n=this.removeFromArray(n,a),r.push(a);for(let t=0;t<a.neighbours.length;t++){let e=a.neighbours[t];if(r.includes(e)||e.isWall())continue;let h=e.stepCost+this.heuristic(i?[e,u,a]:[e,a]),d=!1;n.includes(e)?h<e.stepCost&&(e.stepCost=h,d=!0):(e.stepCost=h,d=!0,n.push(e)),d&&(e.heuristicEstimate=this.heuristic(i?[e,u,a]:[e,s]),e.calculatedTotal=e.stepCost+e.heuristicEstimate,o+=e.stepCost+e.heuristicEstimate,e.previous=a)}}return l?e:d?o:a}getLocationForHerdingAgent(){let t=this.GRID[this.enemyIdx][this.enemyJdx],e=this.GRID[this.agentIdx][this.agentJdx],i={node:null,cost:0},s=null,h=this.getCoordinates(e);return this.trapLocations.includes(e)?(i.node=e,i.cost=0):this.trapLocations.forEach(n=>{this.liesWithin(n,h)&&(s=this.heuristic([t,n,e]),(!i.cost||i.cost>s)&&(i.node=n,i.cost=s))}),i.node&&i.node.showCornerIndicator(),i.node&&setTimeout(()=>{i.node.removeCornerIndicator()},100),i.node||e}moveLogicalAgent(t){let e=this.agentIdx,i=this.agentJdx;t===this.ACTION_LEFT?e--:t===this.ACTION_RIGHT?e++:t===this.ACTION_UP?i++:t===this.ACTION_DOWN&&i--,this.isOccupied(e,i)||(this.agentIdx=e,this.agentJdx=i)}renderPath(){for(let t of this.path)t.showPermanentPath()}getScore(){let t=this.goodSteps/AB.maxSteps*100;return Math.round(100*t)/100}getState(){return[this.agentIdx,this.agentJdx,this.enemyIdx,this.enemyJdx]}updateStatusBefore(t){let e=this.getState();AB.msg(" Step: "+AB.step+" x = ("+e.toString()+") a = ("+t+") ")}updateStatusAfter(){let t=this.getState(),e=this.goodSteps/AB.step*100;AB.msg(" y = ("+t.toString()+") <br> Bad steps: "+this.badSteps+" Good steps: "+this.goodSteps+" Score: "+e.toFixed(2)+"% ",2)}takeAction(t){this.updateStatusBefore(t),this.moveLogicalAgent(t),AB.step%2==0&&this.moveLogicalEnemy(),this.isBadStep()?this.badSteps++:this.goodSteps++,this.drawAgent(),this.drawEnemy(),this.updateStatusAfter(),this._goodSteps=this.goodSteps,this.isAgentBlocked()&&(AB.abortRun=!0,this.goodSteps=0,this.pauseMusic(),this.soundAlarm(),this.renderPath())}getAction(t){let e=t[0],i=t[1],s=t[2],h=t[3];return h<i?AB.randomPick(this.ACTION_UP,AB.randomPick(this.ACTION_RIGHT,this.ACTION_LEFT)):h>i?AB.randomPick(this.ACTION_DOWN,AB.randomPick(this.ACTION_RIGHT,this.ACTION_LEFT)):s<e?AB.randomPick(this.ACTION_RIGHT,AB.randomPick(this.ACTION_UP,this.ACTION_DOWN)):s>e?AB.randomPick(this.ACTION_LEFT,AB.randomPick(this.ACTION_UP,this.ACTION_DOWN)):AB.randomIntAtoB(0,3)}getKeyMap(){return{37:this.ACTION_LEFT,38:this.ACTION_DOWN,39:this.ACTION_RIGHT,40:this.ACTION_UP}}removeFromArray(t,e){let i=t.indexOf(e);return-1!==i&&t.splice(i,1),t}liesWithin(t,e){let i=e.topLeft,s=e.topRight,h=e.bottomLeft,n=e.bottomRight;return t.idx<s.idx&&t.jdx<s.jdx&&t.idx>i.idx&&t.jdx<i.jdx&&t.idx>h.idx&&t.jdx>h.jdx&&t.idx<n.idx&&t.jdx>n.jdx}getCoordinates(t){let e={idx:t.idx+5,jdx:t.jdx+5};e.idx>this.gridSize-2?e.idx=this.gridSize-2:e.idx<1&&(e.idx=1),e.jdx>this.gridSize-2?e.jdx=this.gridSize-2:e.jdx<1&&(e.jdx=1);let i={idx:t.idx-5,jdx:t.jdx+5};i.idx>this.gridSize-2?i.idx=this.gridSize-2:i.idx<1&&(i.idx=1),i.jdx>this.gridSize-2?i.jdx=this.gridSize-2:i.jdx<1&&(i.jdx=1);let s={idx:t.idx-5,jdx:t.jdx-5};s.idx>this.gridSize-2?s.idx=this.gridSize-2:s.idx<1&&(s.idx=1),s.jdx>this.gridSize-2?s.jdx=this.gridSize-2:s.jdx<1&&(s.jdx=1);let h={idx:t.idx+5,jdx:t.jdx-5};return h.idx>this.gridSize-2?h.idx=this.gridSize-2:h.idx<1&&(h.idx=1),h.jdx>this.gridSize-2?h.jdx=this.gridSize-2:h.jdx<1&&(h.jdx=1),{topLeft:i,topRight:e,bottomLeft:s,bottomRight:h}}}window.world=new complexWorld,AB.world={newRun:function(){world.newRun()},endRun:function(){world.endRun()},getScore:function(){return world.getScore()},getState:function(){return world.getState()},takeAction:function(t){world.takeAction(t)},customKeyHandler:function(t){if(!AB.runReady)return!0;if(!world.ourKeys(t))return!0;let e=world.getKeyMap();return world.moveLogicalAgent(e[t.keyCode]),t.stopPropagation(),t.preventDefault(),!1}},AB.mind={getAction:function(t){return world.getAction(t)}};