Code viewer for Mind: A Star (clone by David Jusev)

// Cloned by David Jusev on 1 Dec 2022 from Mind "A Star " 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.tempShape=new THREE.BoxGeometry(30,30,30),this.tempCube=new THREE.Mesh(this.tempShape),this.tempCube.material=new THREE.MeshBasicMaterial,this.tempCube.position.copy(this.translate(this.idx,this.jdx)),this.tempCube.material.color.setColorName("blue"),this.tempCube.material.opacity=.25,ABWorld.scene.add(this.tempCube)}removeTemperoryPath(){ABWorld.scene.remove(this.tempCube),this.tempShape=null,this.tempCube=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}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="A Star 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.pathColor="darkred",this.openColor=new THREE.Color(0,1,0),this.closedColor=new THREE.Color(0,0,1),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())}isOccupied(t,e){return this.enemyIdx===t&&this.enemyJdx===e||(this.agentIdx===t&&this.agentJdx===e||!!this.GRID[t][e].isWall())}isBadStep(){return Math.abs(this.enemyIdx-this.agentIdx)<2&&Math.abs(this.enemyJdx-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)}ourKeys(t){return this.OURKEYS.includes(t.keyCode)}initScene(){this.initialized||(this.setupWalls(),this.setupMaze(),this.setupNeighbours(),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})}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.lookat.copy(this.theAgent.position)}addPath(t){this.path.push(t)}setPath(t){this.path=t}heuristic(t,e){return Math.abs(t.idx-e.idx)+Math.abs(t.jdx-e.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=[t],s=[],h=null,n=[],r=null,a=null;for(;i.length;){let t=0;for(let e=0;e<i.length;e++)i[e].calculatedTotal<i[t].calculatedTotal&&(t=e);if((h=i[t])===e)break;i=this.removeFromArray(i,h),s.push(h);for(let t=0;t<h.neighbours.length;t++){let n=h.neighbours[t];if(s.includes(n)||n.isWall())continue;let r=n.stepCost+this.heuristic(n,h),a=!1;i.includes(n)?r<n.stepCost&&(n.stepCost=r,a=!0):(n.stepCost=r,a=!0,i.push(n)),a&&(n.heuristicEstimate=this.heuristic(n,e),n.calculatedTotal=n.stepCost+n.heuristicEstimate,n.previous=h)}}for(n.push(h);h&&h.previous&&(n.push(h.previous),(h=h.previous)&&h.previous);)h.showTemperoryPath();let o=n[n.length-2];r=o.idx,a=o.jdx,this.isOccupied(r,a)||(this.enemyIdx=r,this.enemyJdx=a,this.addPath(this.GRID[this.enemyIdx][this.enemyJdx]))}_moveLogicalAgent(){let t=null,e=null;this.enemyIdx<this.agentIdx?t=AB.randomIntAtoB(this.enemyIdx,this.enemyIdx+1):this.enemyIdx===this.agentIdx?t=this.enemyIdx:this.enemyIdx>this.agentIdx&&(t=AB.randomIntAtoB(this.enemyIdx-1,this.enemyIdx)),this.enemyJdx<this.agentJdx?e=AB.randomIntAtoB(this.enemyJdx,this.enemyJdx+1):this.enemyJdx===this.agentJdx?e=this.enemyJdx:this.enemyJdx>this.agentJdx&&(e=AB.randomIntAtoB(this.enemyJdx-1,this.enemyJdx)),this.isOccupied(t,e)||(this.enemyIdx=t,this.enemyJdx=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)}renderTemperoryPath(t){for(let e of t)e.showTemperoryPath()}renderPath(){for(let t of this.path)t.showPermanentPath()}keyHandler(t){if(!AB.runReady)return!0;if(!this.ourKeys(t))return!0;let e={37:this.ACTION_LEFT,38:this.ACTION_DOWN,39:this.ACTION_RIGHT,40:this.ACTION_UP};return this.moveLogicalAgent(e[t.keyCode]),t.stopPropagation(),t.preventDefault(),!1}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+" &nbsp; x = ("+e.toString()+") &nbsp; a = ("+t+") ")}updateStatusAfter(){let t=this.getState(),e=this.goodSteps/AB.step*100;AB.msg(" &nbsp; y = ("+t.toString()+") <br> Bad steps: "+this.badSteps+" &nbsp; Good steps: "+this.goodSteps+" &nbsp; 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}}window.world=new complexWorld,AB.world={newRun:function(){window.world.newRun()},endRun:function(){window.world.endRun()},getScore:function(){return window.world.getScore()},getState:function(){return window.world.getState()},takeAction:function(t){window.world.takeAction(t)},customKeyHandler:function(t){if(!AB.runReady)return!0;if(!window.world.ourKeys(t))return!0;let e=window.world.getKeyMap();return window.world.moveLogicalAgent(e[t.keyCode]),t.stopPropagation(),t.preventDefault(),!1}},AB.mind={getAction:function(t){return window.world.getAction(t)}};