Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Game of Threes in java. Already completed the GameUtil() class. Need help with the Game() class. The game consists of a grid of moveable tiles.

Game of Threes in java. Already completed the GameUtil() class. Need help with the Game() class.

The game consists of a grid of moveable tiles. Each tile contains a number 1, 2, 3, or a value that results from starting with a 3 and doubling a bunch of times. We will think of the grid as a 2D array of integer values, where the value 0 means there is no tile in that cell. There are only four possible operations: to "shift" the grid up, down, left, or right. What this means is that the tiles are shifted in the indicated direction, and certain combinations of tiles may be merged if "pushed" together against one of the boundaries. The exact rules for merging are discussed in a later section. The screenshot on the right shows the result of shifting in the "up" direction. The two 12's are "pushed" against the top and merge to make 24. In addition, the 1 and 2 in the second column are merged to make a 3. All other tiles that can move (the two 2's in this case) are shifted up as well. Whenever the grid is shifted in some direction, a new tile appears on the opposite side. The game ends when the grid can't be shifted in any direction because there are no empty cells and no merges are possible. The object of the game is to get the highest possible score. The score is the sum, for all tiles on the grid, of a predetermined number associated with each individual tile value.

Methods to be used in GameUtil:

int mergeValues(int a, int b) Determines whether the two tile values can be merged and returns the merged value, returning zero if no merge is possible. The basic rules are that 1 can be merged with 2, and values larger than 2 can be merged if they are equal. In either case the merged value is the sum. This method is already implemented.

int getScoreForValue(int value) Returns the score for a tile with the given value.

int calculateTotalScore(int[][] grid) Returns the total score for the given grid. This method is already implemented.

int[][] initializeNewGrid(int size, Random rand) Initializes a new grid, using the given Random object to position two initial tiles. This method is already implemented.

int[][] copyGrid(int[] grid) Makes a copy of the given 2D array. This method is already implemented.

int generateRandomTileValue(Random rand) Returns a randomly generated tile value according to a predefined set of probabilities, using the given Random object.

TilePosition generateRandomTilePosition(int[] grid, Random rand, Direction lastMove) Returns a randomly selected tile position on the side of the grid that is opposite the direction of the most recent shift.

ArrayList shiftArray(int[] arr) Shifts the array elements to the left according to the rules of the game, possibly merging two of the cells.

See below for details.

The shiftArray() method The basic rules for shifting are as follows. Remember that we interpret an array cell containing zero to be "empty". If there is an adjacent pair that can be merged, and has no empty cell to its left, then the leftmost such pair is merged (the merged value goes into the left one of the two cells) and all elements to the right are shifted one cell to the left. Otherwise, if there is an empty cell in the array, then all elements to the right of the leftmost empty cell are shifted one cell to the left. Otherwise, the method does nothing.

The method mergeValues() (see overview above) determines which pairs of values can be merged, and if so what the resulting value is. Note that at most one pair in in the array is merged.

Here are some examples:

For arr = [3, 1, 2, 1], after shiftArray(arr), the array is [3, 3, 1, 0] For arr = [1, 2, 1, 2], after shiftArray(arr), the array is [3, 1, 2, 0] For arr = [6, 3, 3, 3, 3], after shiftArray(arr), the array is [6, 6, 3, 3, 0] For arr = [3, 6, 6, 0], after shiftArray(arr), the array is [3, 12, 0, 0] For arr = [3, 0, 1, 2], after shiftArray(arr), the array is [3, 1, 2, 0] The return value of shiftArray() is a list of Move objects. A Move object is a simple data container that encapsulates the information about a move of one cell or a merge of a pair of cells. The Move objects do not directly affect the game state, but can be used by a client (such as a GUI) to animate the motion of tiles. The Move class is in the api package; see the source code to see what it does.

Methods to be used in Game.Java:

Game(int givenSize, GameUtil givenConfig, java.util.Random givenRandom).Constructs a game with a grid of the given size, using the given instance of Random for the random number generator.

copyRowOrColumn(int rowOrColumn, Direction dir) Copy a row or column from the grid into a new one-dimensional array.

getCell(int row, int col) Returns the value in the cell at the given row and column

getNextTileValue() Returns the value that will appear on the next tile generated in a call to newTile.

getScore() Returns the current score.

getSize() Returns the size of this game's grid.

newTile() Generates a new tile and places its value in the grid, provided that there was a previous call to shiftGrid without a corresponding call to undo or newTile.

setCell(int row, int col, int value) Sets the value of the cell at the given row and column.

shiftGrid(Direction dir) Plays one step of the game by shifting the grid in the given direction.

undo() Revernts the shift performed in a previous call to shiftGrid(), provided that neither newTile() nor undo() has been called.
updateRowOrColumn(int[] arr, int rowOrColumn, Direction dir) Updates the grid by copying the given one-dimensional array into a row or column of the grid.

Methods implemented for Game.Java:

package hw3;

import java.util.ArrayList;

import java.util.Random;

import api.Direction;

import api.Move;

import api.TilePosition;

/**

* The Game class contains the state and logic for an implementation of a video

* game such as "Threes". The basic underlying state is an n by n grid of tiles,

* represented by integer values. A zero in a cell is considered to be *

* "empty". To play the game, a client calls the method

* shiftGrid(), selecting one of the four directions (LEFT, RIGHT,

* UP, DOWN). Each row or column is then shifted according to the rules

* encapsulated in the associated GameUtil object. The move is

* completed by calling newTile, which makes a new tile appear in

* the grid in preparation for the next move.

*

* In between the call to shiftGrid() and the call to

* newTile, the client may also call undo(), which

* reverts the grid to its state before the shift.

*

* The game uses an instance of java.util.Random to generate new tile values and

* to select the location for a new tile to appear. The new values are generated

* by the associated GameUtil's

* generateRandomTileValue method, and the new positions are

* generated by the GameUtil's

* generateRandomTilePosition method. The values are always

* generated one move ahead and stored, in order to support the ability for a UI

* to provide a preview of the next tile value.

*

* The score is the sum over all cells of the individual scores returned by the

* GameUtil's getScoreForValue() method.

*/

public class Game {

/**

* Constructs a game with a grid of the given size, using a default random

* number generator. The initial grid is produced by the

* initializeNewGrid method of the given GameUtil

* object.

*

* @param givenSize

* size of the grid for this game

* @param givenConfig

* given instance of GameUtil

*/

public Game(int givenSize, GameUtil givenConfig) {

// just call the other constructor

this(givenSize, givenConfig, new Random());

}

/**

* Constructs a game with a grid of the given size, using the given instance of

* Random for the random number generator. The initial grid is

* produced by the initializeNewGrid method of the given

* GameUtil object.

*

* @param givenSize

* size of the grid for this game

* @param givenConfig

* given instance of GameUtil

* @param givenRandom

* given instance of Random

*/

public Game(int givenSize, GameUtil givenConfig, Random givenRandom) {

// TODO

}

/**

* Returns the value in the cell at the given row and column.

*

* @param row

* given row

* @param col

* given column

* @return value in the cell at the given row and column

*/

public int getCell(int row, int col) {

// TODO

return 0;

}

/**

* Sets the value of the cell at the given row and column. NOTE: This method

* should not be used by clients outside of a testing environment.

*

* @param row

* given row

* @param col

* given col

* @param value

* value to be set

*/

public void setCell(int row, int col, int value) {

// TODO

}

/**

* Returns the size of this game's grid.

*

* @return size of the grid

*/

public int getSize() {

// TODO

return 0;

}

/**

* Returns the current score.

*

* @return score for this game

*/

public int getScore() {

// TODO

return 0;

}

/**

* Copy a row or column from the grid into a new one-dimensional array. There

* are four possible actions depending on the given direction:

*

    *

  • LEFT - the row indicated by the index rowOrColumn is copied

    * into the new array from left to right

    *

  • RIGHT - the row indicated by the index rowOrColumn is copied

    * into the new array in reverse (from right to left)

    *

  • UP - the column indicated by the index rowOrColumn is copied

    * into the new array from top to bottom

    *

  • DOWN - the row indicated by the index rowOrColumn is copied

    * into the new array in reverse (from bottom to top)

    *

*

* @param rowOrColumn

* index of the row or column

* @param dir

* direction from which to begin copying

* @return array containing the row or column

*/

public int[] copyRowOrColumn(int rowOrColumn, Direction dir) {

// TODO

return null;

}

/**

* Updates the grid by copying the given one-dimensional array into a row or

* column of the grid. There are four possible actions depending on the given

* direction:

*

    *

  • LEFT - the given array is copied into the the row indicated by the index

    * rowOrColumn from left to right

    *

  • RIGHT - the given array is copied into the the row indicated by the index

    * rowOrColumn in reverse (from right to left)

    *

  • UP - the given array is copied into the column indicated by the index

    * rowOrColumn from top to bottom

    *

  • DOWN - the given array is copied into the column indicated by the index

    * rowOrColumn in reverse (from bottom to top)

    *

*

* @param arr

* the array from which to copy

* @param rowOrColumn

* index of the row or column

* @param dir

* direction from which to begin copying

*/

public void updateRowOrColumn(int[] arr, int rowOrColumn, Direction dir) {

// TODO

}

/**

* Plays one step of the game by shifting the grid in the given direction.

* Returns a list of Move objects describing all moves performed. All Move

* objects must include a valid value for getRowOrColumn() and

* getDirection(). If no cells are moved, the method returns an

* empty list.

*

* The shift of an individual row or column is performed by the method

* shiftArray of GameUtil.

*

* The score is not updated.

*

* @param dir

* direction in which to shift the grid

* @return list of moved or merged tiles

*/

public ArrayList shiftGrid(Direction dir) {

// TODO

return null;

}

/**

* Reverts the shift performed in a previous call to shiftGrid(),

* provided that neither newTile() nor undo() has been

* called. If there was no previous call to shiftGrid() without a

* newTile() or undo(), this method does nothing and

* returns false; otherwise returns true.

*

* @return true if the previous shift was undone, false otherwise

*/

public boolean undo() {

// TODO

return false;

}

/**

* Generates a new tile and places its value in the grid, provided that there

* was a previous call to shiftGrid without a corresponding call to

* undo or newTile. The tile's position is determined

* according to the generateRandomTilePosition of this game's

* associated GameUtil object. If there was no previous call to

* shiftGrid without an undo or newTile,

* this method does nothing and returns null; otherwise returns a

* TilePosition object with the new tiles's position and value.

* Note that the returned tile's value should match the current value

* returned by getNextTileValue, and if this method returns a

* non-null value the upcoming tile value should be updated according to

* generateRandomTileValue(). This method should update the total

* score and the score should include the newly generated tile.

*

* @return TilePosition containing the new tile's position and value, or null if

* no new tile is created

*/

public TilePosition newTile() {

// TODO

return null;

}

/**

* Returns the value that will appear on the next tile generated in a call to

* newTile. This is an accessor method that does not modify the

* game state.

*

* @return value to appear on the next generated tile

*/

public int getNextTileValue() {

// TODO

return 0;

}

}

THIS IS GAMEUTIL.JAVA:

package hw3;

import java.util.ArrayList;

import java.util.Random;

import api.Direction;

import api.Move;

import api.TilePosition;

/**

* Utility class containing some elements of the basic logic for performing

* moves in a game of "Threes".

*/

public class GameUtil {

/**

* Constructor does nothing, since this object is stateless.

*/

public GameUtil() {

// do nothing

}

/**

* Returns the result of merging the two given tile values, or zero if they

* can't be merged. The rules are: a 1 can be merged with a 2, and two values

* greater than 2 can be merged if they match. The result of a merge is always

* the sum of the tile values.

*

* @param a

* given tile value

* @param b

* given tile value

* @return result of merging the two values, or zero if no merge is possible

*/

public int mergeValues(int a, int b) {

if (a > 0 && b > 0 && (a + b == 3) || (a >= 3 && b == a)) {

return a + b;

} else {

return 0;

}

}

/**

* Returns the score for a single tile value. Tiles with value less than 3 have

* score zero. All other values result from starting with value 3 and doubling N

* times, for some N; the score is 3 to the power N + 1. For example: the value

* 48 is obtained from 3 by doubling N = 4 times (48 / 3 is 16, which is 2 to

* the 4th), so the score is 3 to the power 5, or 243.

*

* @param value

* tile value for which to compute the score

* @return score for the given gile value

*/

public int getScoreForValue(int value) {

int realValue=0;

int i=0;

int num=0;

int dos =2;

int tres =3;

if(value==3) {

return value;

}

else if(value<3){

return realValue;

}

else {

realValue=3;

num = value/realValue;

while(dos

dos = dos*2;

i++;

}

return (int)Math.pow(tres, i+1);

}

}

/**

* Returns a new size x size array with two nonzero cells. The nonzero cells

* consist of a 1 and a 2, placed randomly in the grid using the given Random

* instance.

*

* @param size

* width and height of the new array

* @param rand

* random number generator to use for positioning the nonzero cells

* @return new size x size array

*/

public int[][] initializeNewGrid(int size, Random rand) {

int[][] grid = new int[size][size];

int numCells = size * size;

// To select two distinct cells, think of the numCells cells as ordered

// left to right within rows, with the rows ordered top to bottom.

// First select two distinct integers between 0 and numCells

int first = rand.nextInt(numCells);

int second = rand.nextInt(numCells - 1);

if (second >= first) {

second += 1;

}

// Then, divide by size to get the row, mod by size to get column,

// put a 1 in the first and a 2 in the other

grid[first / size][first % size] = 1;

grid[second / size][second % size] = 2;

return grid;

}

/**

* Returns the total score for the given grid. The grid is not modified.

*

* @param grid

* given grid

* @return sum of scores for the values in the grid

*/

public int calculateTotalScore(int[][] grid) {

int total = 0;

for (int row = 0; row < grid.length; ++row) {

for (int col = 0; col < grid[0].length; ++col) {

total += getScoreForValue(grid[row][col]);

}

}

return total;

}

/**

* Makes a copy of the given 2D array. The array must be nonempty and

* rectangular.

*

* @param grid

* given 2D array to copy

* @return copy of the given array

*/

public int[][] copyGrid(int[][] grid) {

int[][] ret = new int[grid.length][grid[0].length];

for (int row = 0; row < grid.length; ++row) {

for (int col = 0; col < grid[0].length; ++col) {

ret[row][col] = grid[row][col];

}

}

return ret;

}

/**

* Generate a new tile value using the given instance of Random. Values are

* generated such that there are 40% 1's, 40% 2's, 10% 3's, and 10% 6's.

*

* @param rand

* random number generator to use

* @return the value 1, 2, 3, or 6 with the specified probability

*/

public int generateRandomTileValue(Random rand) {

int num = rand.nextInt(100)+1;

if (num<=10) {

return 6;

}

if (num>10 && num<=20) {

return 3;

}

if (num>20 && num<=60) {

return 2;

}

else {

return 1;

}

}

/**

* Generates a position for a new tile. The new position is on the side of the

* grid opposite that of the previous move and is randomly selected from

* available positions in the given grid. The value of the tile is zero

* (typically filled in later by an associated Game instance). The given grid is

* not modified. If lastMove is null, this method returns null.

*

* @param grid

* given square array

* @param rand

* random number generator to use

* @param down

* given direction

* @return new tile position

*/

public TilePosition generateRandomTilePosition(int[][] grid, Random rand, Direction down) {

int spot = rand.nextInt(grid.length);

if(down ==Direction.UP) {

ArrayList moveUp = new ArrayList();

for(int i =0; i<4; i++) {

moveUp.add(grid[i][grid[0].length-1]);

}

while(moveUp.get(spot)!=0) {

spot = rand.nextInt(grid.length-1);

}

TilePosition tile = new TilePosition(spot, grid[0].length-1, 0);

return tile;

}

else if (down == Direction.DOWN) {

ArrayList moveDown = new ArrayList();

for(int i=0; i<4; i++) {

moveDown.add(grid[i][0]);

}

while(moveDown.get(spot)!=0) {

spot = rand.nextInt(grid.length-1);

}

TilePosition tile = new TilePosition(spot, 0, 0);

return tile;

}

else if (down==Direction.LEFT) {

ArrayList moveLeft = new ArrayList();

for(int i=0;i<4;i++) {

moveLeft.add(grid[grid.length-1][i]);

}

while(moveLeft.get(spot)!=0) {

spot = rand.nextInt(grid[0].length-1);

}

TilePosition tile = new TilePosition(grid.length-1, spot, 0);

return tile;

}

else if(down==Direction.RIGHT) {

ArrayList moveRight= new ArrayList();

for(int i=0;i<4;i++) {

moveRight.add(grid[0][i]);

}

while(moveRight.get(spot)!=0) {

spot= rand.nextInt(grid[0].length-1);

}

TilePosition tile = new TilePosition(0, grid.length-1, 0);

return tile;

}

else {

return null;

}

}

/**

* Shifts the array elements to the left according to the rules of the Threes

* game. This method only operates on a one-dimensional array of integers

* representing the tile values in one row or column. The Game class can use

* this method to shift a row or column in any direction by copying that row or

* column, either forward or backward, into a temporary one-dimensional array to

* be passed to this method. The rules are that if there is a pair of adjacent

* cells that can be merged, and has no empty (zero) cells to its left, then the

* leftmost such pair of cells is merged and everything to its right is shifted

* left by one cell. Otherwise, if there is an empty cell, then everything to

* the right of the leftmost empty cell is shifted left by one cell. Otherwise,

* the array is unmodified and an empty list is returned.

*

* The new value for a pair of merged cells is determined by the method

* mergeValues. The method returns a list of Move objects

* representing the moved cells. All returned Move objects will have unspecified

* row/column and direction (typically filled in later by the associated Game

* instance). The list is in no particular order.

*

* @param arr

* array to be shifted

* @return list of all moves and/or merges performed in the shift

*/

public ArrayList shiftArray(int[] arr) {

ArrayList shiftedArray = new ArrayList();

boolean canMerge = false;

for(int i = 0; i

if (!canMerge) {

if(mergeValues(arr[i-1], arr[i]) !=0) {

shiftedArray.add(new Move(i-1, i-2, arr[i], arr[i-1], mergeValues(arr[i-1], arr[i])));

arr[i-1] = mergeValues(arr[i], arr[i-1]);

canMerge = true;

}

else if(arr[i-1] == 0) {

shiftedArray.add(new Move(i-1, i-2, arr[i]));

arr[i-1] = arr[i];

canMerge = true;

}

}

else {

shiftedArray.add(new Move(i-1, i-2, arr[i]));

arr[i-1] = arr[i];

}

}

if(canMerge) {

arr[arr.length-1] = 0;

}

return shiftedArray;

}

}

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

More Books

Students also viewed these Databases questions