Code viewer for World: Tetris World

// 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 width = 32;                       //size of grid in 
const height = 25;

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

const centreIndexHeight = height/2;     
const centreIndexWidth = width/2;       

    
const SKYCOLOR  = 0xddffdd;             // a number, not a string 
const BLANKCOLOR    = SKYCOLOR ;        // make objects this color until texture arrives (from asynchronous file read)
 
const startRadiusConst      = ((centreIndexHeight + centreIndexWidth) * 20) * 3 ;           // distance from centre to start the camera at
const skyboxConst           = ((centreIndexHeight + centreIndexWidth) * 20) * 10 ;          // where to put skybox 
const maxRadiusConst        = ((centreIndexHeight + centreIndexWidth) * 20) * 100  ;        // maximum distance from camera we will render things  
// contents of a grid square

const GRID_BLANK = 0;
const GRID_WALL = 1;
const GRID_PIECE = 2;
const GRID_TETRIS = 3;



//---- set of action controls
const ACTION_ROTATE_R    = 0;    // up arrow key   
const ACTION_ROTATE_L    = 1;    // down arrow key  
const ACTION_MOVE_R      = 2;    // right arrow key
const ACTION_MOVE_L      = 3;    // left arrow key
const ACTION_SPEED       = 4;    // space bar

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


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

  // width = x axis
  // height = y axis


  var BOXHEIGHT = 1;       // 3d or 2d box height 
 
  var GRID  = new Array(width);          // can query GRID about whether squares are occupied, will in fact be initialised as a 2D array   
  var WALLS = new Array(height * width);
  var PIECES = new Array(10);
  var GRIDS = new Array(height * width);
  var TETRIS = new Array(height * width);

  var rotationsCount = 0;
  var ord_x = 5;
  var ord_y = 4;

  var userXinit = 5;
  var userYinit = 1;

  var currentPieceType;
  var nextPieceType;
  var currentPiece;
  var nextPiece;

  var gravity = true;

  // --- userGrid and enemyGrid are both initialised, redrawn each time
  // --- both are grids 10 x 20 in size.
  var userGrid = new Array(20)

  for(var i = 0; i < userGrid.length; i++)
  {
    userGrid[i] = new Array(10);
  }

  var enemyGrid = userGrid;


  var self = this;

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

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

  function translateHeight ( x ) 
  {
   return ( x - ( (height * squaresize)/2 ) );
  }
  
  function translateWidth ( x ) 
  {
   return ( x - ( (width * squaresize)/2 ) );
  }
  
 

  //--- skybox ----------------------------------------------------------------------------------------------
  function initSkybox() 
  {

  // x,y,z positive and negative faces have to be in certain order in the array 
   
  // mountain skybox, credit:
  // http://stemkoski.github.io/Three.js/Skybox.html

    var materialArray = [
      ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/sky_pos_z.jpg" ), side: THREE.BackSide } ) ),
      ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/sky_neg_z.jpg" ), side: THREE.BackSide } ) ),
      ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/sky_pos_y.jpg" ), side: THREE.BackSide } ) ),
      ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/sky_neg_y.jpg" ), side: THREE.BackSide } ) ),
      ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/sky_pos_x.jpg" ), side: THREE.BackSide } ) ),
      ( new THREE.MeshBasicMaterial ( { map: THREE.ImageUtils.loadTexture( "/uploads/starter/sky_neg_x.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
  }

  function loadWallTexture()
  {
    var loader = new THREE.TextureLoader();
    loader.load ( '/uploads/phm/squareborder.png',       function ( thetexture ) 
    {            
      thetexture.minFilter = THREE.LinearFilter;
      paintWalls ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
    } );
  }

  function loadPieceTexture()
  {
    var loader = new THREE.TextureLoader();
    loader.load ( '/uploads/phm/square.jpg',      function ( thetexture ) 
    {            
      thetexture.minFilter = THREE.LinearFilter;
      paintPiece ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
    } );
  }

  function loadGridTexture()
  {
    var loader = new THREE.TextureLoader();
    loader.load ( '/uploads/phm/blue.png',      function ( thetexture ) 
    {            
      thetexture.minFilter = THREE.LinearFilter;
      paintGrid ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
    } );
  }

  function loadTetrisTexture()
  {
    var loader = new THREE.TextureLoader();
    loader.load ( '/uploads/phm/red.png',      function ( thetexture ) 
    {            
      thetexture.minFilter = THREE.LinearFilter;
      paintTetris ( new THREE.MeshBasicMaterial( { map: thetexture } ) );
    } );
  }

  function createCube()
  {
    var shape = new THREE.BoxGeometry( squaresize, BOXHEIGHT, squaresize );          
    var thecube = new THREE.Mesh( shape );
    thecube.material.color.setHex( BLANKCOLOR  );

    return thecube;
  }

  // --- add piece objects ----------------------------------------

  function getPiece(number, rotations)
  {
    var opiece0 = [
                  [1,1],
                  [1,1]
                  ];
    // -- o piece is square in every direction
    var jpiece1 = [
                  [0,1,0],
                  [0,1,0],
                  [1,1,0]
                  ];
                    
    var jpiece2 = [
                  [1,0,0],
                  [1,1,1],
                  [0,0,0]
                  ];

    var jpiece3 = [
                  [1,1,0],
                  [1,0,0],
                  [1,0,0]
                  ]; 

    var jpiece4 = [
                  [1,1,1],
                  [0,0,1],
                  [0,0,0]
                  ];

    // -- j piece 4 rotations

    var lpiece1 = [
                  [1,0,0],
                  [1,0,0],
                  [1,1,0]
                  ];

    var lpiece2 = [
                  [1,1,1],
                  [1,0,0],
                  [0,0,0]
                  ]; 

    var lpiece3 = [
                  [1,1,0],
                  [0,1,0],
                  [0,1,0]
                  ];

    var lpiece4 = [
                  [0,0,1],
                  [1,1,1],
                  [0,0,0]
                  ];   

    // -- l piece 4 rotations

    var zpiece1 = [
                  [0,1,0],
                  [1,1,0],
                  [1,0,0]
                  ];

    var zpiece2 = [
                  [1,1,0],
                  [0,1,1],
                  [0,0,0]
                  ];

    var zpiece3 = [
                  [0,0,1],
                  [0,1,1],
                  [0,1,0]
                  ];

    var zpiece4 = [
                  [0,0,0],
                  [1,1,0],
                  [0,1,1]
                  ];

    // -- z piece 4 rotations

    var spiece1 = [
                  [1,0,0],
                  [1,1,0],
                  [0,1,0]
                  ];

    var spiece2 = [
                  [0,1,1],
                  [1,1,0],
                  [0,0,0]
                  ];

    var spiece3 = [
                  [0,1,0],
                  [0,1,1],
                  [0,0,1]
                  ];

    var spiece4 = [
                  [0,0,0],
                  [0,1,1],
                  [1,1,0]
                  ];

    

    // -- s piece 2 rotations

    var tpiece1 = [
                  [1,0,0],
                  [1,1,0],
                  [1,0,0]
                  ];

    var tpiece2 = [
                  [1,1,1],
                  [0,1,0],
                  [0,0,0]
                  ];

    var tpiece3 = [
                  [0,0,1],
                  [0,1,1],
                  [0,0,1]
                  ];

    var tpiece4 = [
                  [0,1,0],
                  [1,1,1],
                  [0,0,0]
                  ];

    // -- t piece 4 rotations

    var ipiece1 = [
                  [1,0,0,0],
                  [1,0,0,0],    
                  [1,0,0,0],    
                  [1,0,0,0]     
                  ];

    var ipiece2 = [
                  [0,0,0,0],
                  [1,1,1,1],
                  [0,0,0,0],
                  [0,0,0,0]
                  ];

    var ipiece3 = [
                  [0,0,0,1],
                  [0,0,0,1],
                  [0,0,0,1],
                  [0,0,0,1]
                  ];

    var ipiece4 = [
                  [0,0,0,0],
                  [0,0,0,0],
                  [1,1,1,1],
                  [0,0,0,0]
                  ];


    //                   ^
    //                   |
    //                   x
    //            o      |
    //            <--y---|              

    // o is rotation point

    // -- i piece 2 rotations

    var bag = [
              [opiece0],
              [jpiece1, jpiece2, jpiece3, jpiece4],
              [lpiece1, lpiece2, lpiece3, lpiece4],
              [zpiece1, zpiece2, zpiece3, zpiece4],
              [spiece1, spiece2, spiece3, spiece4],
              [tpiece1, tpiece2, tpiece3, tpiece4],
              [ipiece1, ipiece2, ipiece3, ipiece4]
              ]

    var j;

    if(number === 0)
    {
      return bag[number][0]
    }

    else
    {
      j = rotations % 4;
      return bag[number][j];
    }
  }

  function getRandomPiece()
  {
    return Math.floor(Math.random() * 7);   
  }

  function rotatePieceRight()
  {
    rotationsCount++;
    return getPiece(currentPieceType, rotationsCount);
  }

  function rotatePieceLeft()
  {
    rotationsCount--;
    return getPiece(currentPieceType, rotationsCount);
  }

  function start()
  {
    drawStartUserGrid();
  }

  function drawStartUserGrid()
  {
    currentPieceType = getRandomPiece();
    currentPiece = getPiece(currentPieceType, 0);
    console.log("currentPiece = " + currentPiece);

    nextPieceType = getRandomPiece();
    nextPiece = getPiece(nextPieceType, 0);
    console.log("nextPiece = " + nextPiece);

    drawPiece(0, 0, currentPiece);
    drawPiece(0, -3, nextPiece);
    reset_ord();

  }

  function drawNextUserGrid()
  {
    currentPiece = nextPiece;
    currentPieceType = nextPieceType
    drawPiece(0, 0, currentPiece);

    drawClearNextPiece(nextPiece);
    nextPieceType = getRandomPiece();
    nextPiece = getPiece(nextPieceType, 0);
    drawPiece(0, -3, nextPiece);

    reset_ord();

  }

  function reset_ord()
  {
    ord_x = 5;
    ord_y = 4;
    rotationsCount = 0;
  }

  function drawPiece(x, y, piece)
  {
    ord_x += x;
    ord_y += y;

    flushPieces();
    var t = 0;
    for(var i = 0; i < piece.length; i++)
    {
      for(var j = 0; j < piece.length; j++)
      {
        if(piece[i][j] == 1)
        {
          GRID[ord_x + i][ord_y + j] = GRID_PIECE;

          var cube = createCube();            
          cube.position.x = translateWidth ( (i + ord_x) * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( (j + ord_y) * squaresize );     
          cube.position.y =  0;   
     
          threeworld.scene.add(cube)   ;
          PIECES[t] = cube;                // save it for later
          t++; 
        }

      }
    }
    loadPieceTexture();
  }

  function drawClearPiece(piece)
  {
    flushGrid();
    flushPieces();
    var t = 0;
    for(var i = 0; i < piece.length; i++)
    {
      for(var j = 0; j < piece.length; j++)
      {
        if(piece[i][j] == 1)
        {
          GRID[ord_x + i][ord_y + j] = GRID_BLANK;

          var cube = createCube();            
          cube.position.x = translateWidth ( (i + ord_x) * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( (j + ord_y) * squaresize );     
          cube.position.y =  0;   
     
          threeworld.scene.add(cube)   ;
          GRIDS[t] = cube;                // save it for later
          t++; 
        }
      }
    }

    loadGridTexture();
  }

  function drawClearNextPiece(piece)
  {
    flushGrid();
    flushPieces();
    var t = 0;
    for(var i = 0; i < piece.length; i++)
    {
      for(var j = 0; j < piece.length; j++)
      {
        if(piece[i][j] == 1)
        {
          GRID[ord_x + 0 + i][ord_y -3 + j] = GRID_BLANK;

          var cube = createCube();            
          cube.position.x = translateWidth ( (i + ord_x + 0) * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( (j + ord_y - 3) * squaresize );     
          cube.position.y =  0;   
     
          threeworld.scene.add(cube)   ;
          GRIDS[t] = cube;                // save it for later
          t++; 
        }
      }
    }

    loadGridTexture();
  }


  function isHittingBottom(piece)
  { 
    for(var i = 0; i < piece.length; i++)
    {
      for(var j = 0; j < piece.length; j++)
      {
        if((piece[i][j] == 1) && (GRID[ord_x + i][ord_y + j + 1]) == GRID_WALL)
        {
          return true;
        }
      }
    }

    return false;
  }

  function isHittingTetris(piece)
  { 
    for(var i = 0; i < piece.length; i++)
    {
      for(var j = 0; j < piece.length; j++)
      {
        if((piece[i][j] == 1) && (GRID[ord_x + i][ord_y + j + 1]) == GRID_TETRIS)
        {
          return true;
        }
      }
    }

    return false;
  }

  function isHittingSidesRight(piece)
  {
    for(var j = 0; j < piece.length; j++)
    {
      if((piece[piece.length - 1][j] == 1) && (GRID[ord_x + piece.length][ord_y + j]) == GRID_WALL)
      {
        return true;
      }

      if((piece[piece.length - 1][j] == 1) && (GRID[ord_x + piece.length][ord_y + j]) == GRID_TETRIS)
      {
        return true;
      }
    }

    return false;
  }

  function isHittingSidesLeft(piece)
  {
    for(var j = 0; j < piece.length; j++)
    {
      if((piece[0][j] == 1) && (GRID[ord_x + 0 - 1][ord_y + j]) == GRID_WALL)
      {
        return true;
      }

      if((piece[0][j] == 1) && (GRID[ord_x + 0 - 1][ord_y + j]) == GRID_TETRIS)
      {
        return true;
      }
    }

    return false;
  }

  
  // --- add fixed objects ---------------------------------------- 

  function initWalls()
  {
    for(var i = 0; i < width; i++)
    {
      for(var j = 0; j < height; j++)
      {

        if(
          i === 0 ||
          i == 11 ||
          i == 20 ||
          i == width - 1 ||
          j === 0 ||
          j == 3 && i < 11 ||
          j == 3 && i > 20 ||
          j == height - 1
          )
        {
          GRID[i][j] = GRID_WALL;
        }
      }
    }
  }

  function flushTetris()
  {
    TETRIS = new Array(height * width);
  }

  function flushPieces()
  {
    PIECES = new Array(10);
  }

  function flushGrid()
  {
    GRIDS = new Array(height * width);
  }


  function drawThreeScene()       // graphical run only, set up blank boxes, painted later    
  {
    var t = 0;
    var p = 0;
    var q = 0;
    var s = 0;
    for (var i = 0; i < width; i++)
    {
      for (var j = 0; j < height ; j++)
      { 
        if ( GRID[i][j] == GRID_WALL )
        {
          var cube = createCube();            
          cube.position.x = translateWidth ( i * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( j * squaresize );     
          cube.position.y =  0;   
     
          threeworld.scene.add(cube)   ;
          WALLS[t] = cube;                // save it for later
          t++; 
        }

        if ( GRID[i][j] == GRID_BLANK )
        {
          var cube = createCube();            
          cube.position.x = translateWidth ( i * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( j * squaresize );     
          cube.position.y =  0;  

     
          threeworld.scene.add(cube)   ;
          GRIDS[p] = cube;                // save it for later
          p++; 
        }

        if ( GRID[i][j] == GRID_PIECE )
        {
          var cube = createCube();            
          cube.position.x = translateWidth ( i * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( j * squaresize );     
          cube.position.y =  0;   

          threeworld.scene.add(cube);
          PIECES[q] = cube;                // save it for later
          q++; 
        }

        if ( GRID[i][j] == GRID_TETRIS )
        {
          var cube = createCube();            
          cube.position.x = translateWidth ( i * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( j * squaresize );     
          cube.position.y =  0;   

          threeworld.scene.add(cube);
          TETRIS[s] = cube;                // save it for later
          s++; 
        }

      }
    }

    loadWallTexture();
    loadPieceTexture();
    loadTetrisTexture();
    loadGridTexture();
  }


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

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

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

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

  function drawTetris(piece)
  {
    var q = 0;
    for (var i = 0; i < width ; i++)
    {
      for (var j = 6; j < height; j++)
      { 
        if(GRID[i][j] == GRID_PIECE)
        {
          GRID[i][j] = GRID_TETRIS;
        }
      }
    }
  }

  function drawThreeGrids(base)
  {
    
    var q = 0;
    var p = 0;
    for (var i = 0; i < width - 21 ; i++)
    {
      
      for (var j = height - 1; j > base - 1; j--)
      { 
        
        if(GRID[i][j] == GRID_BLANK)
        {
          var cube = createCube();            
          cube.position.x = translateWidth ( i * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( j * squaresize );     
          cube.position.y =  0;   

          threeworld.scene.add(cube);
          GRIDS[q] = cube;                // save it for later
          q++; 
        }

        if(GRID[i][j] == GRID_TETRIS)
        {

          var cube = createCube();            
          cube.position.x = translateWidth ( i * squaresize );         // translate my simple (i,j) block-numbering coordinates to three.js (x,y,z) coordinates 
          cube.position.z = translateHeight ( j * squaresize );     
          cube.position.y =  0;   

          threeworld.scene.add(cube);
          TETRIS[p] = cube;                // save it for later
          p++; 
        }

        
        loadTetrisTexture();
        loadGridTexture();

      }
    }

   

  }

  function keyHandler(e)    
  // user control 
  // Note that this.takeAction(a) is constantly running at same time, redrawing the screen.
  {
      if (e.keyCode == 32)  
      {
        movePiece ( ACTION_SPEED      ); 
        console.log("space hit");
      }   //spacebar
      if (e.keyCode == 37)  
      {
        movePiece ( ACTION_MOVE_L     ); 
        console.log("left move"); 
      }  //left
      if (e.keyCode == 38)  
      {
        movePiece ( ACTION_ROTATE_R   );
        console.log("right rotate"); 

      }    //up
      if (e.keyCode == 39)  
      {
        movePiece ( ACTION_MOVE_R     );
        console.log("move right");

      }    //right
      if (e.keyCode == 40)  
      {
        movePiece ( ACTION_ROTATE_L   );
        console.log("left rotate")
      }    //down
  }

  function movePiece(action)
  {
    switch(action){
      case ACTION_MOVE_L:
        if(!isHittingSidesLeft(currentPiece) && !isHittingBottom(currentPiece))
        {
          drawClearPiece(currentPiece);
          drawPiece(-1, 0, currentPiece);
          break;
        }
        else
        {
          break;
        }
        
      case ACTION_MOVE_R:
        if(!isHittingSidesRight(currentPiece) && !isHittingBottom(currentPiece))
        {
          drawClearPiece(currentPiece);
          drawPiece(1, 0, currentPiece);
          break;
        }
        else
        {
          break;
        }

      case ACTION_SPEED:
        if(!isHittingTetris(currentPiece) && !isHittingBottom(currentPiece))
        {
          drawClearPiece(currentPiece);
          drawPiece(0, 1, currentPiece);
          break;
        }
        else
        {
          break;
        }

      case ACTION_ROTATE_R:
        var tmp = rotatePieceRight();
        if(
          !isHittingTetris(tmp) && 
          !isHittingTetris(tmp) &&
          !isHittingSidesRight(tmp) &&
          !isHittingSidesLeft(tmp) 
          )
        {
          drawClearPiece(currentPiece);
          console.log("rotationsCount: " + rotationsCount);
          currentPiece = tmp;
          drawPiece(0, 0, currentPiece);
          break;
        }
        else
        {
          break;
        }

      case ACTION_ROTATE_L:
        var tmp = rotatePieceLeft();
        if(
          !isHittingTetris(tmp) && 
          !isHittingTetris(tmp) &&
          !isHittingSidesRight(tmp) &&
          !isHittingSidesLeft(tmp)
          )
        {
          drawClearPiece(currentPiece);
          console.log("rotationsCount: " + rotationsCount);
          currentPiece = tmp;
          drawPiece(0, 0, currentPiece);
          break;
        }
        else
        {
          break;
        }

        
      default:
        break;
      
    }
  }

  function printConsoleGrid()
  {
    var st = "";
    for(var i = 0; i < width; i++)
    {
      st = "";
      for(var j = 0; j  < height; j++)
      {
        st += " " + GRID[i][j];
      }

      console.log(st);
    }
  }
  
  function drawGravityPiece(piece)
  {
    if(!isHittingBottom(piece) && !isHittingTetris(piece))
    {
      drawClearPiece(piece);
      drawPiece(0, 1, piece);
    }

    else
    {

      drawTetris(piece);

      var d = getGridHeight();
      d = height - d - 2;
      drawThreeGrids(d);

      reset_ord();
      clearLines();

      
         
      printConsoleGrid();
      drawNextUserGrid();
      
      //printConsoleGrid();
    }
  }

  function start_Gravity()
  {
    if(step % 15 == 0)
    {
      drawGravityPiece(currentPiece);
    }
    
  }

  // ------------------------------------------------------------------------------------------------

  var userLinesCleared = 0;

  function clearLines()
  {
    var l = 10;

    for(var j = height - 1; j > 0; j--)
    {
      if(lineIsEmpty(j))
      {
        break;
      }

      for(var i = 1; i < width - 21; i++)
      {
        if(GRID[i][j] == GRID_TETRIS)
        {
          l--;
        }
      }

      if(l == 0)
      {
        userLinesCleared += 1;
        for(var x = j; x > 6; x--)
        {
          if(lineIsEmpty(x))
          { 
            adjustLine(x + 1);
            break;
          }
          adjustLine(x);
        }        
      }

      l = 10;
    }
  }


  function adjustLine(h)
  {
    var x = copyLine(h - 1);
    console.log(x);
    pasteLine(h, x);
  }

  function copyLine(h)
  {
    var t = new Array(10);
    for(var i = 1; i < 11; i++)
    {
      t[i] = GRID[i][h];
    }
    return t;
  }

  function pasteLine(h, arr)
  {
    drawThreeGrids(h);
    for(var i = 1; i < 11; i++)
    {
      GRID[i][h] = arr[i];
    }
  }

  function lineIsEmpty(h)
  {
    for(var i = 1; i < 11; i++)
    {
      if(GRID[i][h] != GRID_BLANK)
      {
        return false;
      }
    }

    return true;
  }

  function getGridHeight()
  {
    var gridHeight = 0;
    var l = 10;
    for(var j = height - 1; j > 5; j--)
    {
      for(var i = 1; i < width - 19; i++)
      {
        if(GRID[i][j] == GRID_TETRIS)
        {
          gridHeight += 1;
          l--;

          break;
        }        
      }

      if(l == 0)
      {
        break;
      }

      else
      {
        l = 10;
      }

    }

    return gridHeight;
  }

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

  

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

  this.newRun = function() 
  {
    
    this.endCondition = false;
    step = 0;
    
    

    // for all runs:
    initGrid();
    initWalls();

  
    if (true)
    {
        threeworld.init2d ( startRadiusConst, maxRadiusConst, SKYCOLOR  );

         // Set up objects first:
        start();
        drawThreeScene();
        document.onkeydown = keyHandler; 
    }
    
  };
  
  this.getState = function()
  {

  };


 
this.nextStep = function()		 
{
 var a = 4;

      step++;   

      if(true)
      {
        start_Gravity();

        if(step % 50 == 0)
        {
          if(getGridHeight() > 17)
          {
           this.endCondition = true;
          }
        }
      }


  };
  
  this.endRun = function()
  {
      console.log("Game over");
  };

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

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