CSE-8B / PA4 / starter / GameState.java
GameState.java
Raw
//File: GameState.java
//Name: Trai Pham
//Date: 02/06/2020
//Course: CSE 8B
/**This code would allow you to play the game 2048 on the command prompt.
This code is goes over all elements of the game 2048. This program would allow
user to move the values within the grid of the game 2048.
*/
//#file header: This file contains the GameState, Config, Direction, and
//Game2048 code.

//#class header: the GameState class is the core of movements and operation of
//the 2048 game. It creates the board and allows user to move

import java.util.Random;
import java.util.Random.*;
import java.util.*;

public class GameState{
//declaring the class's variable
  private Random rng;
  private int [][] board;
  private int score;
  private int numTiles;

//Constructor
  public GameState(int numRows, int numCols){
    this.score = 0;
    this.board = new int[numRows][numCols];
    this.rng = new Random(Config.RANDOM_SEED);
  }
//Each element of the 2d-array should either be the value
//of the tile or 0 if the tile does not exist
/*
Creates a deep copy of the Board
*/
  public int[][] getBoard(){
    int [][] newBoard = new int [this.board.length][this.board[0].length];
    for(int i = 0; i < this.board.length; i++){
      for(int j =0; j < this.board[0].length; j++){
        newBoard[i][j] = this.board[i][j];
      }
    }
    return newBoard;
  }
/*  @param 2d Array
Sets the new board to that of the game board
@return void, creates a new board
*/
  public void setBoard(int [][] newBoard){
    if( newBoard == null){
      return;
    }
    else{
      int [][] board2 = new int[newBoard.length][newBoard[0].length];
      for(int i = 0; i< newBoard.length; i++){
        for(int j =0; j < newBoard[0].length; j++){
          board2[i][j] = newBoard[i][j];
        }
      }
      this.board = board2;
    }
  }
/*@ param none
@return int
Gets the score of the game
*/
  public int getScore(){
    return this.score;
  }
/*@ param int of the updated Score
@return void
Gets the new score for the game

*/
  public void setScore (int newScore){
    this.score = newScore; // setting the input class variable score to called
  }
/*@param int, bound to roll a random number
@return int random number
gets a random number between 0 and a bound

*/
  protected int rollRNG(int bound){
    int newBound = this.rng.nextInt(bound);
    return newBound; //returns a random number between 0 and bound
  }
/*@param none
@return int, number 2 or 4
random tile 2 or 4 created
*/
  protected int randomTile (){
    int num2 = 2;
    int num4 = 4;
    int newInt = this.rng.nextInt(Config.RANDOM_SEED);
    if(newInt <= Config.TWO_PROB){
      return num2;
    }
    else{
      return num4;
    }

  }
/*@oaram none
@return int, number of empty tiles
gives you a number of how much empty squares there are
*/
  protected int countEmptyTiles (){
    int counter = 0;
    for(int i = 0; i < this.board.length; i++){
      for(int j = 0; j < this.board[0].length; j++){
        if(this.board[i][j] == 0){
          counter ++;
        }
      }
    }
    return counter;
  }
/*@param none
@return int, randomly added tile, it'll be 2 or 4
adds a tile at a random empty tile on the board

*/
  protected int addTile(){
    int a = 0;
    int b = 0;

    if(this.countEmptyTiles() == 0){
      return 0;
    }
    else{
      boolean flag = true;
      while(flag){
         a = rollRNG(this.board.length);
         b = rollRNG(this.board[0].length);
         if(this.board[a][b] == 0){ // empty space checks
           flag = false;
        }
      }
      this.board[a][b] = randomTile();
      return(this.board[a][b]);
    }
  }

//MOVEMENT METHODS
//Remember to call addTiles and countEmptyTiles() after every movement
/*@param none
@return void
rotates the board counter clockwise
*/
  protected void rotateCounterClockwise (){ //optional
//creating a deep copy of the board

    for(int i = 0; i < this.board.length; i++){
      for(int j =0; j < this.board[0].length; j++){
        int a = this.board[j][this.board[0].length-i-1];
        this.board[i][j] = a;
      }
    }
  }
/*@param none
@return boolean, true if you cna slide down, false if you can't
checks if the tiles can slide down
*/
  protected boolean canSlideDown (){
    //this checks if the tiles are equal to one another
    if(this.countEmptyTiles() > 0){
      for(int i = 0; i < this.board.length; i++){
//When tile is on the last row/edge
        if(i == this.board.length -1){
          return false;
        }
        for( int j =0 ; j < this.board[0].length; j++){
          if(i +1 >= this.board.length){
            return false;
          }
//When two tiles next to each other are equal
          if(this.board[i][j] != 0 && this.board[i][j] == this.board[i+1][j]){
            return true;
          }
//When there is an empty space below a tile
          if(this.board[i][j] !=0 && this.board[i+1][j] == 0){
            return true;
          }
        }
      }
    }
      return false;
  }

/*@param none
@return boolean, true if game is over, false if you can still move
checks if the game is over or not based on restriction of movements
*/
  public boolean isGameOver (){

    int i =0;
    while(i != 4){
      if(this.canSlideDown() == false){
        this.rotateCounterClockwise();
        i++;
      }
      if(this.canSlideDown() == true){
        return false;
      }
    }
    return true;
  }
/* @param void
@return boolean true if slide is successful, false if not
*/
  protected boolean slideDown(){
    while(this.canSlideDown()==true){
    for(int col = 0 ; col <this.board.length; col++){
      for( int row = this.board[0].length-1; row > 0; row--){

//variable represent col before
//checks that there is empty spaces below tile
//moving tile down
          if(this.board[row][col] == 0){
            this.board[row][col] = this.board[row-1][col];
            this.board[row -1][col] = 0;
            continue;
          }
          else if(this.board[row -1][col] == this.board[row][col]){
            this.board[row][col] = this.board[row -1][col]*2;
            this.board[row-1][col] = 0;
            this.score += this.board[row][col];
            continue;
          }
          else{
            continue;
          }


    }
  }
  }
  return this.countEmptyTiles() >1;
}
/*@param Direction object
@return boolean, true if you can move in a certain direction, false if you
can't
This allows the user to move within the game
*/
  public boolean move(Direction dir){
    if(dir == null){
      return false;
    }
    if(dir == Direction.DOWN &&  this.slideDown() == true){
      this.addTile();
      return true;
    }
    if(dir == Direction.LEFT){
      this.rotateCounterClockwise();
      this.slideDown();
      return true;
    }
    if(dir == Direction.UP){
      int i = 0;
      while( i != dir.getRotationCount()){
        this.rotateCounterClockwise();
        i++;
      }
      this.slideDown();
      return true;
    }
    if(dir == Direction.RIGHT){
      int b = 0;
      while( b != dir.getRotationCount()){
        this.rotateCounterClockwise();
        b++;
      }
      this.slideDown();
      return true;
    }
    return false;
  }


/*@param none
@return String
this converts the 2d array to that of strings so that it'll be printed
instead of printing the reference/address number

*/
  public String toString () {
    StringBuilder outputString = new StringBuilder();
    outputString.append(String.format("Score: %d\n", getScore()));
    for (int row = 0; row < getBoard().length; row++) {
        for (int column = 0; column < getBoard()[0].length; column++) {
          //Something wrong with bottom code
            outputString.append(getBoard()[row][column] == 0 ? "    -" :
                String.format("%5d", getBoard()[row][column]));
        }
        outputString.append("\n");
    }
    return outputString.toString();
  }


}