Code viewer for World: Abdelshafa Abdala (clone b...
 



// ==== Starter World =================================================================================================
// This code is designed for use on the Ancient Brain site.
// This code may be freely copied and edited by anyone on the Ancient Brain site.
// To include a working run of this program on another site, see the "Embed code" links provided on Ancient Brain.
// ====================================================================================================================



// =============================================================================================
// More complex starter World 
// 3d-effect Maze World (really a 2-D problem)
// Movement is on a semi-visible grid of squares 
//
// This more complex World shows:
// - Skybox
// - Internal maze (randomly drawn each time)
// - Enemy actively chases agent
// - Music/audio
// - 2D world (clone this and set show3d = false)
// - User keyboard control (clone this and comment out Mind actions to see)
// =============================================================================================


// =============================================================================================
// Scoring:
// Bad steps = steps where enemy is within one step of agent.
// Good steps = steps where enemy is further away. 
// Score = good steps as percentage of all steps.
//
// There are situations where agent is trapped and cannot move.
// If this happens, you score zero.
// =============================================================================================


 





// ===================================================================================================================
// === Start of tweaker's box ======================================================================================== 
// ===================================================================================================================

// The easiest things to modify are in this box.
// You should be able to change things in this box without being a JavaScript programmer.
// Go ahead and change some of these. What's the worst that could happen?


AB.clockTick       = 100;    

	// Speed of run: Step every n milliseconds. Default 100.
	
AB.maxSteps        = 1000;    

	// 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  = true;


// Open and closed set
openSet                 =[];
closedSet               =[];
neighbors               =[];
path                    =[];



//---- global constants: -------------------------------------------------------

	const show3d = true;						// Switch between 3d and 2d view (both using Three.js) 


 const TEXTURE_WALL 	= '/uploads/shafi200/wall.png' ;
 const TEXTURE_MAZE 	= '/uploads/starter/latin.jpg' ;
 const TEXTURE_AGENT 	= '/uploads/starter/pacman.jpg' ;
 const TEXTURE_ENEMY 	= '/uploads/starter/ghost.3.png' ;

// credits:
// http://commons.wikimedia.org/wiki/File:Old_door_handles.jpg
// https://commons.wikimedia.org/wiki/Category:Pac-Man_icons
// https://commons.wikimedia.org/wiki/Category:Skull_and_crossbone_icons
// http://en.wikipedia.org/wiki/File:Inscription_displaying_apices_(from_the_shrine_of_the_Augustales_at_Herculaneum).jpg

 
	const MUSIC_BACK  = '/uploads/sinfulsalad/Forest.mp3';
	const SOUND_ALARM = '/uploads/inapo/bgmusic.mp3';

// credits:
// http://www.dl-sounds.com/royalty-free/defense-line/
// http://soundbible.com/1542-Air-Horn.html 

	
	
const gridsize = 50;						// number of squares along side of world	   

const NOBOXES =  Math.trunc ( (gridsize * gridsize) / 3);
		// density of maze - number of internal boxes
		// (bug) use trunc or can get a non-integer 

const squaresize = 100;					// size of square in pixels

const MAXPOS = gridsize * squaresize;		// length of one side in pixels 
	
const SKYCOLOR 	= 0xddffdd;				// 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  



//--- change ABWorld defaults: -------------------------------

ABHandler.MAXCAMERAPOS 	= maxRadiusConst ;

ABHandler.GROUNDZERO		= true;						// "ground" exists at altitude zero



//--- skybox: -------------------------------
// skybox is a collection of 6 files 
// x,y,z positive and negative faces have to be in certain order in the array 
// https://threejs.org/docs/#api/en/loaders/CubeTextureLoader 

// mountain skybox, credit:
// http://stemkoski.github.io/Three.js/Skybox.html


const SKYBOX_ARRAY = [
    "/uploads/shafi200/rainbow_bk.png",
    "/uploads/shafi200/rainbow_bk.png",
    "/uploads/shafi200/rainbow_bk.png",
    "/uploads/shafi200/rainbow_bk.png",
    "/uploads/shafi200/rainbow_bk.png",
    "/uploads/shafi200/rainbow_bk.png",

];



// ===================================================================================================================
// === 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;

// in initial view, (smaller-larger) on i axis is aligned with (left-right)
// in initial view, (smaller-larger) on j axis is aligned with (away from you - towards you)


// contents of a grid square

const GRID_BLANK 	= 0;
const GRID_WALL 	= 1;
const GRID_MAZE 	= 2;
 
 
 
 
var BOXHEIGHT;		// 3d or 2d box height 

var GRID 	= new Array(gridsize);			// can query GRID about whether squares are occupied, will in fact be initialised as a 2D array   

var theagent, theenemy;
  
var wall_texture, agent_texture, enemy_texture, maze_texture; 


// enemy and agent position on squares
var ei, ej, ai, aj;

var badsteps;
var goodsteps;


// asynchronous file loads - call initScene() when all finished 
	
function loadResources()
    
{
   var e = new THREE.TextureLoader();
   var t = new THREE.TextureLoader();
   var o = new THREE.TextureLoader();
   var a = new THREE.TextureLoader();
        
   e.load(TEXTURE_WALL,function(e)
   {
   e.minFilter = THREE.LinearFilter,
   wall_texture = e,asynchFinished()&&initScene();// if all file loads have returned 
            
   });
    
        
   t.load(TEXTURE_AGENT,function(e)
   {
   e.minFilter = THREE.LinearFilter,
   agent_texture = e,asynchFinished()&&initScene();
            
   });
   
      
   o.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();
            
  });
        
    }
    
// all file loads returned
function asynchFinished()

{
  return!!(wall_texture&&agent_texture&&enemy_texture&&maze_texture)}
  
 
    
function occupied(e,t)
{

 return ei==e&&ej==t||(ai==e&&aj==t||(e>=19||t>=19||(1==GRID[e][t].wall||1==GRID[e][t].wall)));
}
 function translate(e,t)
 {
   var o = new THREE.Vector3();
     
   return o.y = 0,
   o.x = e*squaresize - MAXPOS/2,
   o.z=t*squaresize-MAXPOS/2,
   o}
     
// all file loads have returned 
function initScene()
     
     {
 var e,t,o,a;
         
// set up GRID  array
  for (e = 0; e < gridsize ; e++)
    GRID[e] = new Array(gridsize);
    for(e = 0; e < gridsize;e++)
    

// set up walls
           
    for (t = 0; t < gridsize ; t++)
     0 == e || e == gridsize-1 || 0 == t || t == gridsize-1?(GRID[e][t] = GRID_WALL,
    o = new THREE.BoxGeometry (squaresize, BOXHEIGHT, squaresize),
    (
        
    a = new THREE.Mesh(o)).material = new THREE.MeshBasicMaterial({map:wall_texture}),
    a.position.copy(translate(e,t)),
    ABWorld.scene.add(a),GRID[e][t] = new Spot(e,t,!0)):
   (GRID[e][t] = GRID_BLANK,GRID[e][t] = new Spot(e,t,!1));
       
       
// set up maze 
  for ( var i = 1; 
  i <= NOBOXES;i++)e=AB.randomIntAtoB(1,gridsize-2),
  t = AB.randomIntAtoB(1,gridsize-2),
  
  GRID[e][t] = GRID_MAZE,
  
  o = new THREE.BoxGeometry(squaresize,BOXHEIGHT,squaresize),
  (
  a = new THREE.Mesh(o)).material = new THREE.MeshBasicMaterial({map:maze_texture}),
  a.position.copy(translate(e,t)),
  ABWorld.scene.add(a),GRID[e][t] =new Spot(e,t,!0);
  
  
// set up enemy 
// start in random location
  
  do 
  {
  e = AB.randomIntAtoB(1,gridsize-3);
  t = AB.randomIntAtoB(1,gridsize-3);
      
  }
  while(occupied(e,t)); // search for empty square 
  
  ei = e,
  ej = t,
  o = new THREE.BoxGeometry(squaresize,BOXHEIGHT,squaresize),
  (theenemy = new THREE.Mesh(o)).material = new THREE.MeshBasicMaterial
  ({   
  map:enemy_texture}),ABWorld.scene.add(theenemy),drawEnemy();
  
  
// set up agent 
// start in random location

  do
  {
   
  e = AB.randomIntAtoB(1,gridsize-2),
  t = AB.randomIntAtoB(1,gridsize-2
  )}  
  while(occupied(e,t));   // search for empty square 
  
  ai = e,
  aj = t,
  
  o = new THREE.BoxGeometry(squaresize,BOXHEIGHT,squaresize),
  (theagent = new THREE.Mesh(o)).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 = true;
     
 })}



// --- draw moving objects -----------------------------------
// given ei, ej, draw it 
function drawEnemy()
{
 theenemy.position.copy(translate(ei,ej));	// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates 
 ABWorld.lookat.copy (theenemy.position);    // if camera moving, look back at where the enemy is 
    
}

function drawAgent()  // given ai, aj, draw it 
{
 theagent.position.copy (translate(ai,aj)), 	// translate my (i,j) grid coordinates to three.js (x,y,z) coordinates 
    
 ABWorld.follow.copy (theagent.position); 	// follow vector = agent position (for camera following agent)
    
}

function heuristic(e,t)
{
    return diagonal?Math.hypot(e.i-t.i,e.j-t.j):Math.abs(e.i-t.i)+Math.abs(e.j-t.j);
    
}
function removeFromArray(e,t)
{
    for
    (
    var 
    o = e.length-1;
    o>=0;
    o--)e[o]==t&&e.splice(o,1);
    
}
function Spot(e,t,o)
{
    this.wall=o,
    this.i=e,
    this.j=t,
    this.f=0,
    this.g=0,
    this.h=0,
    this.neighbors=[],
    this.previous=void 0;
    
}
function moveLogicalEnemy() 	// this is called by the infrastructure that gets action a from the Mind 
{
    for
    (
   var
   e = 0;
   e < gridsize; e++)
    for
    (
    
    var
    t = 0;
    t < gridsize; t++)
    {
    var 
    o = GRID[e][t].wall;
     GRID[e][t] = new Spot(e,t,o);
        
    }
    for
    (
    e = 0;
    e < gridsize; e++)
    
    for 
    (
    t = 0;
    t < gridsize;
    t ++ )GRID.addNeighbors(e,t);
    
    for
    (
    openSet = [],
    closedSet = [],
    start = GRID[ei][ej],
    end = GRID[ai][aj],
    openSet.push(start);
    openSet.length > 0; 
    )
    {
        
 var a = 0;
   for (
   e = 0;
   e < openSet.length; e++)
   openSet[e].f<openSet[a].f&&(a = e);
 var i = openSet[a];
   if(i === end){path = [];
     for(var n = i;
     n.previous&&n.previous.previous;)path.push(n),
     n = n.previous;
     path.length>=1&&(ei == ai&&ej == aj||(ei = n.i,ej = n.j)),
        
console.log("success - found path")}removeFromArray(openSet,i),closedSet.push(i);
 var r = GRID[i.i][i.j].neighbors;
   for(e = 0; 
   e < r.length; e++)
   {
 var s=r[e];
   if(!closedSet.includes(s)&&!s.wall)
 {
 var d = i.g+heuristic(s,i),u = !1;
   openSet.includes(s)?d<s.g&&(s.g = d,u = !0):(s.g = d,u = !0,
   openSet.push(s)),u&&(s.h=heuristic(s,end),s.f = s.g+s.h,s.previous = i);
                    
}}}}

function moveLogicalAgent(e)
 {
 var t = ai,
     o = aj;
     e == ACTION_LEFT?t--:
 e == ACTION_RIGHT?t++: e == ACTION_UP?o++:
 e == ACTION_DOWN&&o--, occupied(t,o)||(ai = t,aj = o);
                    
}
 GRID.addNeighbors = function
 (e,t)
 {
  e < gridsize-1&&GRID[e][t].neighbors.push(GRID[e+1][t]),
  e > 0&&GRID[e][t].neighbors.push(GRID[e-1][t]),
  t < gridsize-1&&GRID[e][t].neighbors.push(GRID[e][t+1]),
  t > 0&&GRID[e][t].neighbors.push(GRID[e][t-1]),
 diagonal&&(e>0&&t>0&&GRID[e][t].neighbors.push(GRID[e-1][t-1]),
 e < gridsize-1&&t>0&&GRID[e][t].neighbors.push(GRID[e+1][t-1]),
 e > 0&&t<gridsize-1&&GRID[e][t].neighbors.push(GRID[e-1][t+1]),
 e < gridsize-1&&t<gridsize-1&&GRID[e][t].neighbors.push(GRID[e+1][t+1]))};
 
 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));
                        
}

// --- score: -----------------------------------
function badstep() // is the enemy within one square of the agent
   {
    return Math.abs(ei-ai)<2&&Math.abs(ej-aj);
                        
  }
function agentBlocked() // agent is blocked on all sides, run over
  {
  return occupied(ai-1,aj)&&occupied(ai+1,aj)&&occupied(ai,aj+1)&&occupied(ai,aj-1);
                        
  }
function updateStatusBefore(e)
// this is called before anyone has moved on this step, agent has just proposed an action
// update status to show old state and proposed move 
  {
   var  t = AB.world.getState();
   AB.msg(" Step: "+AB.step+"   x = ("+t.toString()+")   a = ("+e+") ");
                        
  }
  
function updateStatusAfter() // agent and enemy have moved, calculate score
{
// new state after both have moved

var e = AB.world.getState(),
    t = goodsteps / AB.step * 100;
AB.msg("   y = ("+e.toString()+") <br> Bad steps: "+badsteps+"   Good steps: "+goodsteps+"   Score: "+t.toFixed(2)+"% ",2);
                    
 }
 //--- public functions / interface / API ----------------------------------
 
  AB.world.newRun=function()
  {
  AB.loadingScreen(),
  AB.runReady = !1;
  badsteps = 0;
  goodsteps = 0 ;
  
  BOXHEIGHT=squaresize;
  ABWorld.init3d(startRadiusConst,maxRadiusConst,14548957);
  
  loadResources(),  // aynch file loads	
                   // calls initScene() when it returns 
                   
  document.onkeydown = keyHandler}, 
  AB.world.getState = function()
 {
     
 return[ai,aj,ei,ej]},
 
 AB.world.takeAction = function(e)
 {
  updateStatusBefore(e), // show status line before moves 
  
  moveLogicalAgent(e), 	
  
 AB.step%2==0&&moveLogicalEnemy(),  // slow the enemy down to every nth step
 
 badstep()?badsteps++:goodsteps++,
 drawAgent(),
 drawEnemy(),
 
 updateStatusAfter();	// show status line after moves  
 agentBlocked()        // if agent blocked in, run over 
 
 &&(AB.abortRun = !0,
 goodsteps = 0,        // you score zero as far as database is concerned
 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()
 {
     
// only called at end - do not use ABRun.step because it may have just 
 var e = goodsteps/AB.maxSteps * 100; // float like 93.4372778 
 return Math.round(100 * e) / 100};
 
 
 // --- music and sound effects --
 var backmusic=AB.backgroundMusic(MUSIC_BACK);
 
function musicPlay(){backmusic.play(); 
                                
 }                          
function musicPause(){backmusic.pause();
                                
}
  
function soundAlarm()
  
{
  
   new Audio(SOUND_ALARM).play();	// play once, no loop 
       
}

//--- end of while ------------------------------------------

if ( ! found ){
    console.log ("No path found");
} else {
    console.log ("found goal node");
    highlightPath (person);
}