Code viewer for World: Lights OFF
// Look only this world, there is nothing worth looking in others. Thank you!

const   CLOCKTICK 	= 100;				// speed of run - move things every n milliseconds
const   MAXSTEPS 	= 1000;				// length of a run before final score
 
const   objectsize  = 300 ;
var     elem        = null;
const   MAXPOS              = 2000 ;                                 
const   startRadiusConst	= MAXPOS * 0.75 ;		// distance from centre to start the camera at
const   maxRadiusConst 		= MAXPOS * 5 ;		        // maximum distance from camera we will render things  


const   SKYCOLOR 	= 0xffffff;				            // a number, not a string 

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

// music on turning OFF and ON the light
// sound effect credit:
// http://soundbible.com/1705-Click2.html
const audio = new Audio('/uploads/kelletelle/click2.mp3');

// Text displayed on top of the browser
var     textString = "<center> <h2>TURN OFF ALL THE LIGHTBULBS!</h2> </center> <center> <h2> Use arrow keys and PgUp, PgDn to select the lightbulb. </h2> </center><center> <h2> Use mouse click to turn ON or OFF lightbulb and bulbs connected to it. </h2> </center>";


// These are some of my attempts to get the better camera angle
// I manly wanted to change camera centre coordinates to something else than 0, 0, 0.
function putCamera()
{
    // threeworld.follow.x = 0;
    // threeworld.follow.y = 0;
    // threeworld.follow.z = 0;
    // threeworld.camera.filmOffset = 0;
    // threeworld.camera.filmOffset = 0;
    // threeworld.camera.rotation._x = 0;
    // threeworld.camera.rotation._z = 0;
    // threeworld.scene.position.x = 0;
    // threeworld.scene.position.y = 0;
    // threeworld.scene.position.z = 0;
    // threeworld.lookat.x = 0;
    // threeworld.lookat.y = 0;
    // threeworld.lookat.z = 0;
    // threeworld.radius = 0;
}

const coordinate_change = 600;

// As I didn't get the desired outcome and I already had code 
// it resulted in those methods to get the coordinates or to set the coordinate values
function getX(object)
{
    return object.position.x + coordinate_change;
}

function getZ(object)
{
    return object.position.z + coordinate_change;
}

function putX(value)
{
    return value - coordinate_change;
}

function putZ(value)
{
    return value - coordinate_change;
}

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

function randomintAtoB ( A, B )			 
{
 return  ( Math.round ( randomfloatAtoB ( A, B ) ) );
}
  
function World() { 

var x, y, z;        // current location 

var textureArray;

// variable for objects
var theobject;

// only box shape is used in this world
const shape = new THREE.BoxGeometry( objectsize, objectsize, objectsize );

// return an initialised object
function createObject(x_coordinate, z_coordinate)
{
    var object  = new THREE.Mesh( shape );
    
    object.position.x = putX(x_coordinate);     	
  	object.position.z = putZ(z_coordinate);
    
    return object;
}

// create a game board with all the lights turned off
function initGameBoard()
{
    for ( i = 0; i < gridsize ; i++) 
    {
        GRID[i]	= new Array(gridsize);	
        for (var j = 0; j < gridsize ; j++) 
        {
            GRID[i][j] = 0;
            theobject  = createObject(i*objectsize, j*objectsize);
            x = getX(theobject);
            z = getZ(theobject);
            threeworld.scene.add(theobject);
            paintThis ( theobject );
        }
    }
}

// turn randomly ON few lights
function turnOnRandomLights()
{
    for (j = 0; j < gridsize ; j++) 
    {  
        tmp_x = randomintAtoB (0, 4);
        tmp_z = randomintAtoB (0, 4);
        if(GRID[tmp_x][tmp_z] === 0) //always generate 5
        {
          	theobject  = createObject(tmp_x*objectsize, tmp_z*objectsize);
            setGridAt(theobject);
            paintThis ( theobject );
            threeworld.scene.add(theobject);
        }
        else
            j--
    }
}

// create walls to make it bit nicer :)
function createBorder()
{
    for (i = 0; i < gridsize+2 ; i++) 
    {    
        for (j = 0; j < gridsize+2 ; j++) 
        {    
            if(i === 0 || j === 0 || i == gridsize+1 || j == gridsize+1)
            {
          	    theobject  = createObject(i*objectsize -300, j*objectsize -300);
                threeworld.scene.add(theobject);
                theobject.material =  new THREE.MeshBasicMaterial ( { map: textureArray[4] } );
            }
        } 
    }
}

function init()		 
{
   textureArray = [
    // light off
 	( new THREE.ImageUtils.loadTexture( "/uploads/kelletelle/turned-off.jpg" ) ),
 	// light on
 	( new THREE.ImageUtils.loadTexture( "/uploads/kelletelle/lightbulbs.png" ) ),
 	// light off selected
 	( new THREE.ImageUtils.loadTexture( "/uploads/kelletelle/turned-off-selected.jpg" ) ),
 	// light on selected
 	( new THREE.ImageUtils.loadTexture( "/uploads/kelletelle/lightbulb-selected.png" ) ),
 	// border texture
 	( new THREE.ImageUtils.loadTexture("/uploads/kelletelle/black_texture.jpg") )
 	];
 	
    for ( var i = 0; i < textureArray.length; i++ )    // for all textures 
    { 
        textureArray[i].minFilter = THREE.LinearFilter;
    }
 
    initGameBoard();
    createBorder();
    turnOnRandomLights();
}

function handleKeyDown (event)
{
    if(x >= 0 && x <= borderline && z >= 0 && z <= borderline)
    {
        // paint the previous box without selected picture
        unselect();
        
        theobject  = createObject(x, z);
 
        var code = event.keyCode;
        
        // can't select if over border
        if (code == 37 && x !== 0)  theobject.position.x = putX(x - objectsize);            // left
        if (code == 39 && x != borderline)  theobject.position.x = putX(x + objectsize);    // right
 
        if (code == 38 && z !== 0) theobject.position.z = putZ(z - objectsize);             // forward
        if (code == 40 && z != borderline) theobject.position.z = putZ(z + objectsize);     // back 
  
        x = getX(theobject);
        z = getZ(theobject);
 
        // paint the selected object again, as selected
 	    threeworld.scene.add(theobject);
        paintSelected ( theobject );
    }
 }
 
// method to paint over previous selected tile back to normal
function unselect ()
{
    theobject  = createObject(x, z);
 	threeworld.scene.add(theobject);
    paintThis ( theobject );
}
 
 function handleclick (event)
 {
    console.log("ss", threeworld.camera);
    if(doubleArraySum(GRID) !== 0)
    {
        audio.play();
        
      	//create & paint side objects
      	if (x != borderline)
      	{   
      	    theobject  = createObject(x + objectsize, z);
            threeworld.scene.add(theobject);
            setGridAt(theobject);
            paintThis ( theobject );
      	}
      	if (x !== 0)
      	{   
      	    theobject  = createObject(x - objectsize, z);
            threeworld.scene.add(theobject);
            setGridAt(theobject);
            paintThis ( theobject );
      	}
      	if (z != borderline)
      	{   
      	    theobject  = createObject(x, z + objectsize);
            threeworld.scene.add(theobject);
            setGridAt(theobject);
            paintThis ( theobject );
      	}
      	if (z !== 0)
      	{   
      	    theobject  = createObject(x, z - objectsize);
            threeworld.scene.add(theobject);
            setGridAt(theobject);
            paintThis ( theobject );
      	}
          
        theobject  = createObject(x, z);
        setGridAt(theobject);
        paintSelected ( theobject );
        threeworld.scene.add(theobject);
        
        // display how many lightbulbs are still on
        var s = textString + "<center> <h2> You have " + doubleArraySum(GRID) + " lightbulbs to turn OFF!</h2> </center>"
        $("#user_span2").html( s );
        
        // if all lights are closed let player know that they won
        if(doubleArraySum(GRID) == 0)
        {
            s = "<center> <h2> U DID IT!!! You turned off all the lightbulbs, you can leave the house now.</h2> </center>";
            $("#user_span2").html( s );
        }
    }
 }


function paintSelected( object)         // paint objects with selected picture
{
    var value = getGridAt(object)+2;
    object.material =  new THREE.MeshBasicMaterial ( { map: textureArray[value] } );   
}

function paintThis( object )            // paint objects with normal picture, no selection box
{
    var value = getGridAt(object);
    object.material =  new THREE.MeshBasicMaterial ( { map: textureArray[value] } );   
}

// set the grid to 0 or 1, representing respectively light off and on
function setGridAt(object)
{
    var x = getX(object);
    var z = getZ(object);
    var lightState = getGridAt(object);
    if(lightState == 1)
    {
        lightState = 0;
    }
    else
    {
        lightState = 1;
    }
    GRID[((x+objectsize)/objectsize -1)][(z+objectsize)/objectsize -1] = lightState;
}

// return object state value held in GRID array
function getGridAt(object)
{
    var lightState;
    var x = getX(object);
    var z = getZ(object);
    return lightState = GRID[((x+objectsize)/objectsize -1)][(z+objectsize)/objectsize -1];
}

	this.endCondition;			 

// run the code
this.newRun = function() 
{
    this.endCondition = false;

    threeworld.init2d ( startRadiusConst, maxRadiusConst, SKYCOLOR  ); 

    $("#user_span2").html( textString + "<center> <h2> You have 5 lightbulbs to turn OFF!</h2> </center>" );
    
    init();

    putCamera();
    document.addEventListener( 'keydown', handleKeyDown   );
    document.addEventListener( 'click', handleclick   );
};

// return sum of elements in array
function doubleArraySum(array)
{
    var sum = 0;
    for(var j = 0; j < gridsize ; j++)
    {
        sum = sum + GRID[j].reduce(add, 0); ;
    }
    return sum;
}

function add(a, b) {
    return a + b;
}


this.getState = function()
{
  return ( null );  
};


this.takeAction = function ( a )
{
};


this.endRun = function()
{
};


this.getScore = function()
{
 return 0;
};

}