package com.javarush.task.task35.task3513;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Model {
private static final int FIELD_WIDTH = 4;
private Tile[][] gameTiles;
int score;
int maxTile;
private Stack<Tile[][]> previousStates = new Stack<>();
private Stack<Integer> previousScores = new Stack<>();
private boolean isSaveNeeded = true;
public Model() {
score = 0;
maxTile = 0;
resetGameTiles();
}
public Tile[][] getGameTiles() {
return gameTiles;
}
private List<Tile> getEmptyTiles() {
List<Tile> emptyTiles = new ArrayList<>();
for (int y = 0; y < FIELD_WIDTH; y++) {
for (int x = 0; x < FIELD_WIDTH; x++) {
if (gameTiles[y][x].value == 0) {
emptyTiles.add(gameTiles[y][x]);
}
}
}
return emptyTiles;
}
private void addTile() {
List<Tile> emptyTiles = getEmptyTiles();
if (!emptyTiles.isEmpty()) {
Tile tile = emptyTiles.get((int) (emptyTiles.size() * Math.random()));
tile.value = (Math.random() < 0.9 ? 2:4);
}
}
public void resetGameTiles() {
gameTiles = new Tile[FIELD_WIDTH][FIELD_WIDTH];
for (int y = 0; y < FIELD_WIDTH; y++) {
for (int x = 0; x < FIELD_WIDTH; x++) {
gameTiles[y][x] = new Tile();
}
}
addTile();
addTile();
}
private boolean compressTiles(Tile[] tiles) {
boolean changes = false;
for (int x = 0; x < FIELD_WIDTH -1; x++) {
if (tiles[x].value == 0) {
for (int y = x + 1; y < FIELD_WIDTH; y++) {
if (tiles[y].value != 0){
tiles[x].value = tiles[y].value;
tiles[y].value = 0;
changes = true;
break;
}
}
}
}
return changes;
}
private boolean mergeTiles(Tile[] tiles) {
boolean changes = false;
for (int x = 0; x < FIELD_WIDTH - 1; x++) {
if (tiles[x].value > 0 & tiles[x].value == tiles[x + 1].value) {
tiles[x].value = tiles[x].value * 2;
tiles[x + 1].value = 0;
if (maxTile < tiles[x].value) {
maxTile = tiles[x].value;
}
score += tiles[x].value;
changes = true;
}
}
compressTiles(tiles);
return changes;
}
public void left() {
if (isSaveNeeded) {
saveState(gameTiles);
}
boolean isChanged = false;
for (int i = 0; i < FIELD_WIDTH; i++) {
if (compressTiles(gameTiles[i]) | mergeTiles(gameTiles[i])) {
isChanged = true;
}
}
if (isChanged) {
addTile();
}
isSaveNeeded = true;
}
private void rotateArray() {
Tile[][] tmp = new Tile[FIELD_WIDTH][FIELD_WIDTH];
for (int i = 0; i < FIELD_WIDTH; i++) {
for (int j = 0; j < FIELD_WIDTH; j++) {
tmp[i][j] = gameTiles[FIELD_WIDTH - 1 - j][i];
}
}
for (int i = 0; i < FIELD_WIDTH; i++) {
for (int j = 0; j < FIELD_WIDTH; j++) {
gameTiles[i][j] = tmp[i][j];
}
}
}
public void up() {
saveState(gameTiles);
rotateArray();
rotateArray();
rotateArray();
left();
rotateArray();
}
public void down() {
saveState(gameTiles);
rotateArray();
left();
rotateArray();
rotateArray();
rotateArray();
}
public void right() {
saveState(gameTiles);
rotateArray();
rotateArray();
left();
rotateArray();
rotateArray();
}
public boolean canMove() {
boolean can = false;
Tile[]tiles = new Tile[gameTiles.length];
for (int i = 0; i < FIELD_WIDTH; i++) {
for (int j = 0; j < FIELD_WIDTH; j++) {
tiles[i] = gameTiles[i][j];
}
}
for (int i = 0; i < FIELD_WIDTH; i++) {
for (int j = 0; j < FIELD_WIDTH; j++) {
if (gameTiles[i][j].value == 0) {
can = true;
}
else {
if (compressTiles(tiles) | mergeTiles(tiles)){
can = true;
}
}
}
}
return can;
}
private void saveState(Tile[][] tiles) {
Tile[][] tmp = new Tile[FIELD_WIDTH][FIELD_WIDTH];
for (int y = 0; y < FIELD_WIDTH; y++) {
for (int x = 0; x < FIELD_WIDTH; x++) {
tmp[y][x] = tiles[y][x];
}
}
previousStates.push(tmp);
previousScores.push(score);
isSaveNeeded = false;
}
public void rollback() {
if (!previousStates.empty() & !previousScores.empty()) {
gameTiles = previousStates.pop();
score = previousScores.pop();
}
}
}
package com.javarush.task.task35.task3513;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
Model model = new Model();
Controller controller = new Controller(model);
JFrame game = new JFrame();
game.setTitle("2048");
game.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
game.setSize(450, 500);
game.setResizable(false);
game.add(controller.getView());
game.setLocationRelativeTo(null);
game.setVisible(true);
}
}