Skip to content

Instantly share code, notes, and snippets.

@jabrena
Forked from ayyytam/TwentyFourtyEight
Created April 30, 2017 22:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jabrena/057b6e3b666d3e66a9aa1ea5fa14b8e1 to your computer and use it in GitHub Desktop.
Save jabrena/057b6e3b666d3e66a9aa1ea5fa14b8e1 to your computer and use it in GitHub Desktop.
2048 terminal game
// Terminal 2048
// By: Andrew Tam
// There is currently no GUI for this game and is played completely on the Terminal.
// Type in the instructions such as "up", "down", "left", "right" to move the tiles
// Type in "reset" to reset the game
import java.util.Scanner;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Random;
import java.util.HashMap;
import java.util.Map;
public class TwentyFourtyEight {
private static final int UP = 1;
private static final int DOWN = 2;
private static final int LEFT = 3;
private static final int RIGHT = 4;
private int[][] board;
private Map<Integer, int[]> OFFSETS = new HashMap<Integer, int[]>();
private ArrayList<int[]> upTileIndices = new ArrayList<int[]>();
private ArrayList<int[]> downTileIndices = new ArrayList<int[]>();
private ArrayList<int[]> leftTileIndices = new ArrayList<int[]>();
private ArrayList<int[]> rightTileIndices = new ArrayList<int[]>();
private Map<Integer, ArrayList<int[]>> edgeTileIndices = new HashMap<Integer, ArrayList<int[]>>();
public static void main(String[] args) {
String input;
TwentyFourtyEight game = new TwentyFourtyEight();
game.newTile();
game.displayBoard();
do {
System.out.println("Please enter a direction: up, down, left, right");
Scanner in = new Scanner(System.in);
input = in.nextLine();
if ("up".equalsIgnoreCase(input)) {
game.move(UP);
game.displayBoard();
} else if ("down".equalsIgnoreCase(input)) {
game.move(DOWN);
game.displayBoard();
} else if ("right".equalsIgnoreCase(input)) {
game.move(RIGHT);
game.displayBoard();
} else if ("left".equalsIgnoreCase(input)) {
game.move(LEFT);
game.displayBoard();
} else if ("reset".equalsIgnoreCase(input)) {
System.out.println("Game reset!");
game.reset();
game.displayBoard();
} else {
System.out.println("Input not recognized");
}
} while (!game.gameFinished());
}
public TwentyFourtyEight(int boardHeight, int boardWidth) {
// Populate board with zeros
board = new int[boardHeight][boardWidth];
// Populate OFFSET map
OFFSETS.put(UP, new int[]{1, 0});
OFFSETS.put(DOWN, new int[]{-1, 0});
OFFSETS.put(LEFT, new int[]{0, 1});
OFFSETS.put(RIGHT, new int[]{0, -1});
// Populate edge tile indices
for (int i = 0; i < boardHeight; i++) {
leftTileIndices.add(new int[]{i, 0});
rightTileIndices.add(new int[]{i, getBoardWidth() - 1});
}
for (int i = 0; i < boardWidth; i++) {
upTileIndices.add(new int[]{0, i});
downTileIndices.add(new int[]{getBoardHeight() - 1, i});
}
// Edge Tiles and direction map
edgeTileIndices.put(UP, upTileIndices);
edgeTileIndices.put(DOWN, downTileIndices);
edgeTileIndices.put(LEFT, leftTileIndices);
edgeTileIndices.put(RIGHT, rightTileIndices);
}
// Default to 4 by 4 game
public TwentyFourtyEight() {
this(4, 4);
}
//Reset board to zero
public void reset() {
for (int i = 0; i < getBoardHeight(); i++) {
for (int j = 0; j < getBoardWidth(); j++) {
setTile(i, j, 0);
}
}
}
// Move all tiles in the give direction and add a new tile if any tiles moved.
public void move(int direction) {
boolean tilesChanged = false;
int lineLength = 0;
int[] offset = OFFSETS.get(direction);
ArrayList<int[]> edgeTileIndicesDirection = edgeTileIndices.get(direction);
if (direction == UP || direction == DOWN) {
lineLength = getBoardHeight();
} else {
lineLength = getBoardWidth();
}
// Based on direction, we go down each line element of edge of the respective direction.
for (int i = 0; i < edgeTileIndicesDirection.size(); i++) {
int[] tempList = new int[lineLength];
int[] currEdgeTileIndices = edgeTileIndicesDirection.get(i);
for (int j = 0; j < lineLength; j++) {
tempList[j] = getTile(currEdgeTileIndices[0] + j * offset[0],
currEdgeTileIndices[1] + j * offset[1]);
}
// Create new merged list
int[] mergedList = merge(tempList);
// Check to see if list changed
if (Arrays.equals(tempList, mergedList)) {
tilesChanged = true;
}
// Modify board line to show new values
for (int j = 0; j < lineLength; j++) {
setTile(currEdgeTileIndices[0] + j * offset[0],
currEdgeTileIndices[1] + j * offset[1],
mergedList[j]);
}
}
if (tilesChanged) {
newTile();
}
}
// This method merges a single row or column
private int[] merge(int[] line) {
int[] resultLine = new int[line.length];
int resultIndex = 0;
boolean lastTileMerged = false;
int lastTileAdded = 0;
// Shift blocks over. If 2 tiles are equal in value, then merge them. But only merge the first pair.
// When it is merged, you multiply it by 2
for (int i = 0; i < line.length; i++) {
int currTile = line[i];
if (currTile > 0) {
// Merge
if ((currTile == lastTileAdded) && !lastTileMerged) {
resultLine[resultIndex - 1] = currTile * 2;
lastTileAdded = currTile * 2;
lastTileMerged = true;
} else {
// Don't merge
resultLine[resultIndex] = currTile;
lastTileAdded = currTile;
lastTileMerged = false;
resultIndex += 1;
}
}
}
return resultLine;
}
// Create a new tile in a randomly selected empty square
public void newTile() {
ArrayList<int[]> emptyTileList = new ArrayList<int[]>();
// Get the index of empty tiles
for (int i = 0; i < getBoardHeight(); i++) {
for (int j = 0; j < getBoardWidth(); j++) {
if (getTile(i, j) == 0) {
int[] emptyIndex = {i, j};
emptyTileList.add(emptyIndex);
}
}
}
// Set one tile from empty list and set to a value. Tile is 2 90% of the time and 4 10% of the time
if (emptyTileList.size() > 0) {
Random rand = new Random();
int randomIndex = rand.nextInt(emptyTileList.size());
int[] emptyTileIndex = emptyTileList.get(randomIndex);
int[] possibleValues = {2, 2, 2, 2, 2, 2, 2, 2, 2, 4};
setTile(emptyTileIndex[0], emptyTileIndex[1], possibleValues[rand.nextInt(possibleValues.length)]);
}
}
// Display board on terminal
public void displayBoard() {
for (int i = 0; i < getBoardHeight(); i++) {
for (int j = 0; j < getBoardWidth(); j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
//Determine whether game is finished or not
public boolean gameFinished() {
// If 2048 achieved
for (int i = 0; i < getBoardHeight(); i++) {
for (int j = 0; j < getBoardWidth(); j++) {
if (board[i][j] == 2048) {
System.out.println("You win!!");
return true;
}
}
}
// If no more moves left. For each row and colsee if there are repeated values
// Go through each row
for (int i = 0; i < getBoardHeight(); i++) {
int prevTile = board[i][0];
for (int j = 0; j < getBoardWidth(); j++) {
if (j > 0) {
if (board[i][j] == prevTile) {
return false;
}
prevTile = board[i][j];
}
}
}
// Go through each col
for (int i = 0; i < getBoardWidth(); i++) {
int prevTile = board[0][i];
for (int j = 0; j < getBoardHeight(); j++) {
if (j > 0) {
if (board[j][i] == prevTile) {
return false;
}
prevTile = board[j][i];
}
}
}
System.out.println("game over!!");
return true;
}
// Setters and Getters
private void setTile(int row, int col, int value) {
board[row][col] = value;
}
private int getTile(int row, int col) {
return board[row][col];
}
private int getBoardHeight() {
return board.length;
}
private int getBoardWidth() {
return board[0].length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment