Hi leetcode community, I am new to machine coding and system design world. Please review the below code for 2048 game. Feedback is welcome. Thanks.
State.java
package com.game.g2048;
public enum State {
VICTORY, OVER, ONGOING
}Direction.java
package com.game.g2048;
public enum Direction {
UP, RIGHT, BOTTOM, LEFT
}Board.java
package com.game.g2048;
import java.util.ArrayList;
import java.util.List;
public class Board {
public static class Cell {
private final int row;
private final int column;
public Cell(int row, int column) {
this.row = row;
this.column = column;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
}
public int getSize() {
return size;
}
private final int size;
private List<List<Integer>> grid;
public Board(int size) {
this.size = size;
grid = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
grid.add(new ArrayList<>(size));
for (int j = 0; j < size; j++) {
grid.get(i).add(0);
}
}
}
public void setCell(Cell cell, int num) {
int row = cell.getRow();
int column = cell.getColumn();
if (row < 0 || column < 0 || row >= size || column >= size) {
throw new RuntimeException("Invalid cell passed");
}
this.grid.get(cell.getRow()).set(cell.getColumn(), num);
}
public boolean isCellVacant(Cell cell) {
return grid.get(cell.row).get(cell.column) == 0;
}
public boolean contains(int num) {
for (List<Integer> row : grid) {
for (Integer cellValue : row) {
if (cellValue == num) {
return true;
}
}
}
return false;
}
public boolean isFull() {
for (List<Integer> row : grid) {
for (Integer cellValue : row) {
if (cellValue == 0) {
return false;
}
}
}
return true;
}
public void slideUp() {
transpose();
slideLeft();
transpose();
}
public void slideDown() {
transpose();
slideRight();
transpose();
}
public void slideRight() {
reverse();
slideLeft();
reverse();
}
public void slideLeft() {
for (int i = 0; i < size; i++) {
grid.set(i, slideRowLeft(grid.get(i)));
}
}
private List<Integer> slideRowLeft(List<Integer> row) {
List<Integer> updatedRow = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
updatedRow.add(0);
}
int i = 0;
int j = 0;
while (i < size) {
if (row.get(i) == 0){
i++;
} else if (row.get(i) != 0 && updatedRow.get(j) == 0) {
updatedRow.set(j, row.get(i));
i++;
} else if (row.get(i) == updatedRow.get(j)) {
updatedRow.set(j, updatedRow.get(j) + row.get(i));
i++;
j++;
} else {
j++;
}
}
return updatedRow;
}
private void transpose() {
List<List<Integer>> transpose = new ArrayList<>();
for (int i = 0; i < size; i++) {
List<Integer> col = new ArrayList<>();
for (List<Integer> row : grid) {
col.add(row.get(i));
}
transpose.add(col);
}
grid = transpose;
}
private void reverse() {
for (int i = 0; i < size; i++) {
reverseRow(grid.get(i));
}
}
private void reverseRow(List<Integer> row) {
int i = 0, j = size - 1;
while (i < j) {
int temp = row.get(i);
row.set(i, row.get(j));
row.set(j, temp);
i++;
j--;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (List<Integer> row : grid) {
for (Integer cellValue : row) {
sb.append(cellValue == 0 ? "-" : cellValue.toString());
sb.append(" ");
}
sb.append("\n");
}
return sb.toString();
}
}GameService.java
package com.game.g2048.service;
import com.game.g2048.Board;
import com.game.g2048.Direction;
import com.game.g2048.State;
import java.util.Random;
public class GameService {
private final Board board;
private static final int DEFAULT_GRID_SIZE = 4;
public GameService(int gridSize) {
this.board = new Board(gridSize);
}
public GameService() {
this(GameService.DEFAULT_GRID_SIZE);
}
public void initialise() {
Board.Cell randomCell1 = getRandomCell();
Board.Cell randomCell2 = getRandomCell();
while (randomCell2.getRow() == randomCell1.getRow() && randomCell2.getColumn() == randomCell1.getColumn()) {
randomCell2 = getRandomCell();
}
board.setCell(randomCell1, 2);
board.setCell(randomCell2, 2);
System.out.println(board);
}
public State getCurrentState() {
if (board.contains(2048)) {
return State.VICTORY;
} else if (board.isFull()) {
return State.OVER;
} else {
return State.ONGOING;
}
}
public void move(Direction directionToMove) {
switch (directionToMove) {
case UP:
board.slideUp();
break;
case LEFT:
board.slideLeft();
break;
case RIGHT:
board.slideRight();
break;
case BOTTOM:
board.slideDown();
break;
}
Board.Cell randomCell = getRandomCell();
while (!board.isCellVacant(randomCell)) {
randomCell = getRandomCell();
}
board.setCell(randomCell, 2);
System.out.println(board);
}
private Board.Cell getRandomCell() {
Random random = new Random();
return new Board.Cell(random.nextInt(board.getSize()), random.nextInt(board.getSize()));
}
}Main.java
package com.game;
import com.game.g2048.Direction;
import com.game.g2048.State;
import com.game.g2048.service.GameService;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
GameService gameService = new GameService();
gameService.initialise();
Scanner sc = new Scanner(System.in);
System.out.println("\n0 - UP");
System.out.println("1 - RIGHT");
System.out.println("2 - BOTTOM");
System.out.println("3 - LEFT");
while (gameService.getCurrentState() == State.ONGOING) {
int move = sc.nextInt();
if (move < 0 || move > 3) {
System.out.println("Please enter a valid move");
continue;
}
Direction directionToMove = Direction.values()[move];
gameService.move(directionToMove);
}
System.out.println(gameService.getCurrentState());
}
}