Code viewer for World: Cube Catcher
/*

ALi Raza
14447642
This is my World for the Assignment 

There was problems with uploading pictures,they had to be over certain resloution(over 800*420)

I also encountered problems with uploading models, the had to be under 2MB, the car 
model that i made was 5.4MB, was unable to upload this-had to change game plan

I couldn't upload .json files, only .Obj files were allowed to upload

*/

//game explation
/*
The game is set in a swimming pool and the cubes float.The red/white cubes displays the track.


The idea behind this game is to catch the cubes to increase score, IF AND ONLY IF the score is >= 10 at 10,00 steps then the player wins
Whats interesting in this game is that if the cube is not caught then the score is minisued by 1 every time,
and the game is finished if it reaches 10,000 steps or the score goes to -14 which ever occour first, then the game is ended and the
player is informed by displaying the end game string. What makes the problem hard is that the cube is moved
into a new random position if not not caught in certain milliseconds. In some places I made the track in diagonal
position which makes the packman harder to move fast around the track. The game gets quite addective after a few plays.
Once the coin is eaten then the cube reappers in a new position.
The game is set in a swimming pool stadium with people observing the game, just like in the Olympics.

*/


// World must define these:
 
const   CLOCKTICK   = 100;          // speed of run - move things every n milliseconds
const   MAXSTEPS  = 1000;         // length of a run before final score
 
 
const  SCREENSHOT_STEP = 50;    


//---- global constants: -------------------------------------------------------
const gridsize = 50;            // number of squares along side of world     

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

const squaresize = 200;         // size of square in pixels
const MAXPOS = gridsize * squaresize;   // length of one side in pixels 
  
const SKYCOLOR  = 0xddffdd;       // a number, not a string 
const BLANKCOLOR  = SKYCOLOR ;      // make objects this color until texture arrives (from asynchronous file read)




const show3d = false;            // Switch between 3d and 2d view (both using Three.js) 
 
const startRadiusConst    = MAXPOS * 0.8 ;    // distance from centre to start the camera at
const skyboxConst     = MAXPOS * 3 ;    // where to put skybox 
const maxRadiusConst    = MAXPOS * 20  ;    // maximum distance from camera we will render things  





//--- 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 GRID  = new Array(gridsize);      // can query GRID about whether squares are occupied, will in fact be initialised as a 2D array   
 
var score = 1;
var  step;



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

var timeout; 
 
// --- some useful random functions  ---------


function randomfloatAtoB ( A, B )      
{
 return ( A + ( Math.random() * (B-A) ) );
}

function randomintAtoB ( A, B )      
{
 return  ( Math.round ( randomfloatAtoB ( A, B ) ) );
}
  
function randomBoolean()       
{
 if ( Math.random() < 0.5 ) { return false; }
 else { return true; }
}

function occupied ( i, j )    //check if the square is this square occupied
{
 if ( ( ei == i ) && ( ej == j ) ) return true;   // variable objects 
 if ( ( ai == i ) && ( aj == j ) ) return true;

 if ( GRID[i][j] == GRID_WALL ) return true;    // fixed objects   
 if ( GRID[i][j] == GRID_MAZE ) return true;     
   
 return false;
}


//---- start of World class -------------------------------------------------------
 
function World() { 


// most of World can be private 
// regular "var" syntax means private variables:


var BOXHEIGHT;    // 3d or 2d box height 


var WALLS   = new Array ( 4 * gridsize );   // need to keep handles to wall and maze objects so can find them later to paint them 
var MAZE  = new Array ( NOBOXES );
var theagent, theenemy;
  


//var badsteps;
var goodsteps;

  var self = this;            // needed for private fn to call public fn - see below  

 


// regular "function" syntax means private functions:


function initGrid()
{
 for (var i = 0; i < gridsize ; i++) 
 {
  GRID[i] = new Array(gridsize);    // each element is an array 

  for (var j = 0; j < gridsize ; j++) 
  {
   GRID[i][j] = GRID_BLANK ;
  }
 }
}

 
// logically, coordinates are: y=0, x and z all positive (no negative)    
// logically my dimensions are all positive 0 to MAXPOS
// to centre everything on origin, subtract (MAXPOS/2) from all dimensions 

function translate ( x ) 
{
 return ( x - ( MAXPOS/2 ) );
}


//--- skybox ------------
function initSkybox() 
{   
    //setting the background as a stadium
    //uploaded images used here
    var materialArray = [
  ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/ali/background.jpg" ), side: THREE.BackSide } ) ),
  ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/ali/background.jpg" ), side: THREE.BackSide } ) ),
  ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/ali/background.jpg" ), side: THREE.BackSide } ) ),
  ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/ali/water.jpg" ), side: THREE.BackSide } ) ),
  ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/ali/background.jpg" ), side: THREE.BackSide } ) ),
  ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/ali/background.jpg" ), side: THREE.BackSide } ) ),
  ];

  var skyGeometry = new THREE.CubeGeometry ( skyboxConst, skyboxConst, skyboxConst ); 
  var skyMaterial = new THREE.MeshFaceMaterial ( materialArray );
  var theskybox = new THREE.Mesh ( skyGeometry, skyMaterial );
  threeworld.scene.add( theskybox );            // We are inside a giant cube
}


// This does the file read the old way using loadTexture.
// (todo) Change to asynchronous TextureLoader. A bit complex:
// Make blank skybox. Start 6 asynch file loads to call 6 return functions.
// Each return function checks if all 6 loaded yet. Once all 6 loaded, paint the skybox.     


// --- asynchronous load textures from file ----------------------------------------
// credits:
// http://commons.wikimedia.org/wiki/File:Old_door_handles.jpg?uselang=en-gb
// 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
  
// loader return can call private function


function loadTextures()
{

 var loader1 = new THREE.TextureLoader();
 loader1.load ( '/uploads/ali/barrier.jpg',   function ( thetexture ) {      
    thetexture.minFilter = THREE.LinearFilter;
    paintWalls ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
  } ); 

 var loader2 = new THREE.TextureLoader();
 loader2.load ( '/uploads/ali/barrier.jpg',   function ( thetexture ) {      
    thetexture.minFilter = THREE.LinearFilter;
    paintMaze ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
  } ); 

 var loader3 = new THREE.TextureLoader();
 loader3.load ( '/uploads/starter/pacman.jpg', function ( thetexture ) {      
    thetexture.minFilter = THREE.LinearFilter;
    theagent.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
  } ); 

 var loader4 = new THREE.TextureLoader();
 loader4.load ( '/uploads/ali/coin.jpg',  function ( thetexture ) {      
    thetexture.minFilter = THREE.LinearFilter;
    theenemy.material =  new THREE.MeshBasicMaterial( { map: thetexture } );
  } ); 

}


// --- add fixed objects ----------------------------- 
   
 
function initLogicalWalls()   // set up logical walls in data structure, whether doing graphical run or not 
{
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( ( i==0 ) || ( i==gridsize-1 ) || ( j==0 ) || ( j==gridsize-1 ) )
   {
      GRID[i][j] = GRID_WALL ;     
   }
}

function floorCreate()    
{
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
      GRID[i][j][2] = GRID_WALL ;   
}


function initThreeWalls()   // graphical run only, set up blank boxes, painted later  
{
 var t = 0;
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( GRID[i][j] == GRID_WALL )
   {
   var shape    = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );      
   var thecube  = new THREE.Mesh( shape );
   thecube.material.color.setHex( BLANKCOLOR  );        
 
       thecube.position.x = translate ( i * squaresize );       // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
       thecube.position.z = translate ( j * squaresize );     
       thecube.position.y =  0; 
 
   threeworld.scene.add(thecube);
   WALLS[t] = thecube;        // save it for later
   t++; 
   }
}

//printing walls
function paintWalls ( material )     
{
 for ( var i = 0; i < WALLS.length; i++ )
 { 
   if ( WALLS[i] )  WALLS[i].material = material;
 }
}

//function for a maze, indes/positions given here to place cubes in desired places
function initLogicalMaze()     
{
     // building the track with blocks
      var i = 42;
      var j = 10;
      
      for(var a = 2; a < 35; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          j++;
      }
      
      j = 10;
      
      for(var a = 0; a < 33; a++)
      {
          GRID[i][j] = GRID_MAZE;  //placing cubes to make shape of track
          i--;
      }
      
        for(var a = 0; a < 10; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j++;
      }
      
      i = 12;
      j = 30;
      for(var a =0; a < 12; a++)    //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
          i--;
      }
      
      i = 12;
      j = 30;
        for(var a = 0; a < 19; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j++;
      }
      
      i = 18;
      j = 35;
        
       for(var a = 0; a < 10; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          j++;
      }
      
      i = 10;
      j = 20;
        for(var a = 0; a < 8; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
          i++;
      }
      
      
      i = 19;   //placing cubes to make shape of track
      j = 17;
        for(var a = 0; a < 6; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i--;
          j++;
      }
      
      i = 30;
      j = 17;
        for(var a = 0; a < 11; a++) //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i--;
         
      }
      
      i = 36;
      j = 13;
        for(var a = 0; a < 20; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i--;                      //placing cubes to make shape of track
      }
      
      i = 31;
      j = 17;
        for(var a = 0; a < 12; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          
          j++;
      }
      
      i = 36;
      j = 13;
        for(var a = 0; a < 20; a++)
      {
          GRID[i][j] = GRID_MAZE;   //placing cubes to make shape of track
          j++;
      }
      
      i = 31;
      j = 29;
        for(var a = 0; a < 6; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i--;
          j++;
      }
      
      i = 15;
      j = 23;           //placing cubes to make shape of track
        for(var a = 0; a < 12; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
          j++;
      }
      
      i = 18;
      j = 40;
      for(var a =0; a < 15; a++)
      {
          GRID[i][j] = GRID_MAZE;
          i++;                      //placing cubes to make shape of track
      }
      i = 36;
      j = 33;
      for(var a =0; a <7; a++)
      {
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;
      }
      
      i = 19;
      j = 44;
      for(var a = 0; a < 18; a++)       //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
        
      }
      
      i = 32;
      j = 40;
      for(var a =0; a <4; a++)      //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;
      }
      //placing cubes to make shape of track
      i = 18;
      j = 34;
      for(var a =0; a <6; a++)
      {     
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;
      }
      
      //filling in space/gaps in the race course at bottom corner
      i = 18;
      j = 35;
      for(var a =0; a <5; a++)
      {
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;      //placing cubes to make shape of track
      }
      i = 18;
      j = 36;
      for(var a =0; a <5; a++)
      {
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;
      }
      
      i = 18;       //placing cubes to make shape of track
      j = 37;
      for(var a =0; a <4; a++)
      {
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;
      }
                    //placing cubes to make shape of track
      i = 18;
      j = 38;
      for(var a =0; a <2; a++)
      {
          GRID[i][j] = GRID_MAZE;
          i++;
          j++;
      }
      
      //filling in space/gaps in the race course at bottom-right box
      i = 18;
      j = 43;
        for(var a = 0; a < 18; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      
      i = 18;           //placing cubes to make shape of track
      j = 42;
        for(var a = 0; a < 16; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      //placing cubes to make shape of track
      i = 18;
      j = 41;
        for(var a = 0; a < 15; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      
      //filling in space/gaps in the left part of the race course 
      i = 1;
      j = 48;
        for(var a = 0; a < 30; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      
      i = 1;
      j = 48;
        for(var a = 0; a < 20; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      
      i = 2;        //placing cubes to make shape of track
      j = 48;
        for(var a = 0; a < 29; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      
      i = 3;
      j = 48;       //placing cubes to make shape of track
        for(var a = 0; a < 28; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      
      i = 4;
      j = 48;
        for(var a = 0; a < 26; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }         //placing cubes to make shape of track
      
      i = 5;
      j = 48;
      for(var a = 0; a < 25; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      } 
      i = 6;
      j = 48;
        //placing cubes to make shape of track
      for(var a = 0; a < 24; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      } 
      
      i = 7;
      j = 48;
      for(var a = 0; a < 23; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      //placing cubes to make shape of track
      i = 8;
      j = 48;
        for(var a = 0; a < 22; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      //placing cubes to make shape of track
      i = 9;
      j = 48;
      for(var a = 0; a < 21; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      //placing cubes to make shape of track
      i = 10;
      j = 48;
      for(var a = 0; a < 20; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      
      i = 11;
      j = 48;
      for(var a = 0; a < 19; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      
      //filling right hand side#
      i = 41;
      j = 37;
        for(var a = 0; a < 27; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      i = 40;
      j = 36;
        for(var a = 0; a < 26; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      } 
      i = 39;
      j = 35;
        for(var a = 0; a < 25; a++)
      {
          GRID[i][j] = GRID_MAZE;   //placing cubes to make shape of track
          j--;
      }
       i = 38;
      j = 34;
        for(var a = 0; a < 24; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          j--;
      }
       i = 37;
      j = 33;
        for(var a = 0; a < 23; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          j--;
      }
      //filling top black spaces with cubes
      i = 9;
      j = 12;
        for(var a = 0; a < 29; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          i++;
      }
      i = 9;
      j = 11;
        for(var a = 0; a < 29; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 9;
      j = 13;
        for(var a = 0; a < 10; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 9;
      j = 14;
        for(var a = 0; a < 8; a++)  //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 9;
      j = 15;
        for(var a = 0; a < 7; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
       i = 9;
      j = 16;
        for(var a = 0; a < 6; a++)  //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 9;
      j = 17;
        for(var a = 0; a < 5; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          i++;
      }
      i = 9;
      j = 18;
        for(var a = 0; a < 4; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      //making shape/corners
      GRID[9][18] = GRID_MAZE;
      GRID[10][19] = GRID_MAZE;
      
      //filling the house in the middle
      i = 18;
      j = 18;
        for(var a = 0; a < 14; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 17;
      j = 19;
        for(var a = 0; a < 14; a++) //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
       i = 16;
      j = 20;
        for(var a = 0; a < 15; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          i++;
      }
       i = 15;
      j = 21;
        for(var a = 0; a < 16; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
       i = 14;              //placing cubes to make shape of track
      j = 22;
        for(var a = 0; a < 17; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 15;
      j = 23;
        for(var a = 0; a < 16; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }                             //placing cubes to make shape of track
      i = 16;
      j = 24;
        for(var a = 0; a < 15; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 17;
      j = 25;
        for(var a = 0; a < 14; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          i++;
      }
      i = 18;
      j = 26;
        for(var a = 0; a < 13; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 19;
      j = 27;
        for(var a = 0; a < 12; a++) //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 20;
      j = 28;
        for(var a = 0; a < 11; a++)
      {
          GRID[i][j] = GRID_MAZE; //placing cubes to make shape of track
          i++;
      }
      i = 21;
      j = 29;
        for(var a = 0; a < 10; a++)
      {
          GRID[i][j] = GRID_MAZE;       //placing cubes to make shape of track
          i++;
      }
      i = 22;
      j = 30;
        for(var a = 0; a < 8; a++)
      {
          GRID[i][j] = GRID_MAZE;   //placing cubes to make shape of track
          i++;
      }
      i = 23;
      j = 31;
        for(var a = 0; a < 6; a++)
      {
          GRID[i][j] = GRID_MAZE;   //placing cubes to make shape of track
          i++;
      }
      i = 24;
      j = 32;
        for(var a = 0; a < 4; a++)
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
      i = 25;
      j = 33;
        for(var a = 0; a < 2; a++)      //placing cubes to make shape of track
      {
          GRID[i][j] = GRID_MAZE; 
          i++;
      }
}


function initThreeMaze()        
{
 var t = 0;
 for (var i = 0; i < gridsize ; i++) 
  for (var j = 0; j < gridsize ; j++) 
   if ( GRID[i][j] == GRID_MAZE )
   {
    var shape    = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );       
    var thecube  = new THREE.Mesh( shape );
  thecube.material.color.setHex( BLANKCOLOR  );       

    thecube.position.x = translate ( i * squaresize );    
    thecube.position.z = translate ( j * squaresize );    
    thecube.position.y =  0;  
 
  threeworld.scene.add(thecube);
  MAZE[t] = thecube;    // save it for later
  t++; 
   }
}


function paintMaze ( material )    
{
 for ( var i = 0; i < MAZE.length; i++ )
 { 
   if ( MAZE[i] )  MAZE[i].material = material;
 }
}


// --- enemy functions -----------------------------------


function drawEnemy()  // given ei, ej, draw it 
{
  var x = translate ( ei * squaresize );    
  var z = translate ( ej * squaresize );    
  var y =  0; 

 theenemy.position.x = x;
 theenemy.position.y = y;
 theenemy.position.z = z;
  theenemy.transparent = true

 threeworld.scene.add(theenemy);
threeworld.follow.copy ( theenemy.position );
 //threeworld.lookat.copy ( theenemy.position );    // if camera moving, look back at where the enemy is  
}



function initThreeEnemy()
{
 var shape    = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );      
 theenemy = new THREE.Mesh( shape );
 theenemy.material.color.setHex( BLANKCOLOR  );
 drawEnemy();     
}


// --- agent functions -----------------------------------


function drawAgent()  // given ai, aj, draw it 
{
  var x = translate ( ai * squaresize );    
  var z = translate ( aj * squaresize );    
  var y =  0; 

 theagent.position.x = x;
 theagent.position.y = y;
 theagent.position.z = z;
 threeworld.scene.add(theagent);

threeworld.lookat.copy ( theagent.position );
 //threeworld.follow.copy ( theagent.position );    // follow vector = agent position (for camera following agent)
}


function initLogicalAgent()
{
// start in random location:
 var i, j;
 do
 {
  i = randomintAtoB(1,gridsize-2);
  j = randomintAtoB(1,gridsize-2);

 }
 while ( occupied(i,j) );     // search for empty square 

 ai = i;
 aj = j;
 
}

function initThreeAgent()
{
 var shape    = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );      
 theagent = new THREE.Mesh( shape );
 theagent.material.color.setHex( BLANKCOLOR );  
 drawAgent();       
}

this.takeAction = function ( a )
{
	if ( true  )
	{
		updateStatusAfter();
	}
	
	if(step == MAXSTEPS)
	{
	    this.endCondition = true;
	}
}


function moveLogicalAgent( a )      // this is called by the infrastructure that gets action a from the Mind 
{ 
 var i = ai;
 var j = aj;     

      if ( a == ACTION_LEFT )   i--;
 else if ( a == ACTION_RIGHT )  i++;
 else if ( a == ACTION_UP )     j++;
 else if ( a == ACTION_DOWN )   j--;

 if ( ! occupied(i,j) ) 
 {
  ai = i;
  aj = j;
 }
}



function keyHandler(e)    
// user control 
// Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
{
    if (e.keyCode == 37)  moveLogicalAgent ( ACTION_LEFT  );
    if (e.keyCode == 38)  moveLogicalAgent ( ACTION_DOWN    );
    if (e.keyCode == 39)  moveLogicalAgent ( ACTION_RIGHT   );
    if (e.keyCode == 40)  moveLogicalAgent ( ACTION_UP  );
}





// --- score: -----------------------------------

function updateStatusBefore(a)
// 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 x = self.getState();
 var status = " Step: <b> " + step + " </b> &nbsp; x = (" + x.toString() + ") &nbsp; a = (" + a + ") "; 

 $("#user_span3").html( status );
}

this.endCondition;      // If set to true, run will end. 


function   updateStatusAfter()    // agent and enemy have moved, can calculate score
{
 // new state after both have moved
 var y = self.getState();
 var status = " &nbsp; y = (" + y.toString() + ") <BR> "; 
 $("#user_span4").html( status );
 
 var status = "   Score: " + score;

 $("#user_span5").html( status );

}

//--- public functions / interface / API -----------




this.newRun = function() 
{

// (subtle bug) must reset variables like these inside newRun (in case do multiple runs)

  this.endCondition = false;
  //badsteps = 0; 
  goodsteps = 0;
  step = 0;


  // for all runs:
  initGrid();
  initLogicalWalls(); 
  initLogicalMaze();
  initLogicalAgent();
 // for graphical runs only:

  if ( true  )
  {
  if ( show3d )
  {
   BOXHEIGHT = squaresize;
   threeworld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR  );   
  }      
  else
  {
   BOXHEIGHT = 1;
   threeworld.init2d ( startRadiusConst, maxRadiusConst, SKYCOLOR  );          
  }

  initSkybox();
  initMusic();

  // Set up objects first:

  initThreeWalls(); 
  initThreeMaze();
  initThreeAgent();
  initThreeEnemy();
  // Then paint them with textures - asynchronous load of textures from files. 
  // The texture file loads return at some unknown future time in some unknown order.
  // It is safe to paint objects in random order, but might not be safe to create objects in random order. 

  loadTextures(); 
  
  timeout = setInterval(initLogicalEnemy, 18000);

  document.onkeydown = keyHandler;   
  }

};


this.endRun = function()
{
 if (true )
 {
  musicPause(); //pause music when game ends        //priting message when player wins/loses
  if ( this.endCondition )
    $("#user_span6").html( " &nbsp; <font color=red> <B> Game Over. Score Limit Reached. Final score " + score +" </B> </font>   "  );
  else if(score >= 5)
    $("#user_span6").html( " &nbsp; <font color=green> <B> Run over. </B> You scored " + score + " You won </font>   "  );
  else
    $("#user_span6").html( " &nbsp; <font color=red> <B> Run over. </B> You scored "+ score + " You lost. You need to get more than 5 to win</font>   "  );

    
 }
};

this.getState = function()
{
 var x = [ ai, aj, ei, ej ];
  return ( x );  
};


///chane so enemy can only see n squares away


this.takeAction = function(a)		 
{ 

  step++;

  if ( true  )
   updateStatusBefore(a);     // show status line before moves 

  moveLogicalAgent(a);

  if ( true  )
  {
   drawAgent();
   drawEnemy();
   updateStatusAfter();     // show status line after moves  
  }

  }

};


//---- end of World class -------------------------------------------------------


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



function initMusic()
{
  // put music element in one of the spans, background game music
    var x = "<audio  id=theaudio  src=/uploads/starter/Defense.Line.mp3   autoplay loop> </audio>" ;
    $("#user_span1").html( x );
} 
 

function musicPlay()  
{
  // jQuery does not seem to parse pause() etc. so find the element the old way:
  document.getElementById('theaudio').play();
}


function musicPause() 
{
  document.getElementById('theaudio').pause();
}


function soundAlarm()
{
  var x = "<audio    src=/uploads/starter/air.horn.mp3   autoplay  > </audio>";
    $("#user_span2").html( x );
}