/**
* Точка входа. Содержит все необходимые действия для одного игрового цикла.
*/
public static void main(String[] args) {
initFields();
createInitialCells();
while(!endOfGame){
input();
logic();
graphicsModule.draw(gameField);
}
graphicsModule.destroy();
}
public class GameField {
/**
* Состояние всех ячеек поля.
*/
private int[][] theField;
/**
* Инициализирует поле и заполняет его нулями
*/
public GameField(){
theField = new int[COUNT_CELLS_X][Constants.COUNT_CELLS_Y];
for(int i=0; i
for(int j=0; jtheField[i][j]=0;
}
}
}
/**
* Возвращает состояние ячейки поля по координатам
*
* @param x Координата ячейки X
* @param y Координата ячейки Y
* @return Состояние выбранной ячейки
*/
public int getState(int x, int y){
return theField[x][y];
}
/**
* Изменяет состояние ячейки поля по координатам
*
* @param x Координата ячейки X
* @param y Координата ячейки Y
* @param state Новое состояние для этой ячейки
*/
public void setState(int x, int y, int state){
//TODO check input maybe?
theField[x][y] = state;
}
/**
* Изменяет столбец под номером i
*
* @param i Номер изменяемого столбца
* @param newColumn Массив новых состояний ячеек столбца
*/
public void setColumn(int i, int[] newColumn) {
theField[i] = newColumn;
}
/**
* Возвращает массив состояний ячеек столбца под номером i
*
* @param i Номер запрашиваемого столбца
* @return Массив состояний ячеек столбца
*/
public int[] getColumn(int i) {
return theField[i];
}
/**
* Изменяет строку под номером i
*
* @param i Номер изменяемой строки
* @param newLine Массив новых состояний ячеек строки
*/
public void setLine(int i, int[] newLine) {
for(int j = 0; j< COUNT_CELLS_X; j++){
theField[j][i] = newLine[j];
}
}
/**
* Возвращает массив состояний ячеек строки под номером i
*
* @param i Номер запрашиваемой строки
* @return Массив состояний ячеек строки
*/
public int[] getLine(int i) {
int[] ret = new int[COUNT_CELLS_X];
for(int j = 0; j< COUNT_CELLS_X; j++){
ret[j] = theField[j][i];
}
return ret;
}
}
/**
* Создаёт на поле начальные ячейки
*/
private static void createInitialCells() {
for(int i = 0; i < COUNT_INITITAL_CELLS; i++){
generateNewCell();
}
}
private static void generateNewCell() {
int state = (new Random().nextInt(100) <= Constants.CHANCE_OF_LUCKY_SPAWN)
? LUCKY_INITIAL_CELL_STATE
: INITIAL_CELL_STATE;
int randomX, randomY;
randomX = new Random().nextInt(Constants.COUNT_CELLS_X);
int currentX = randomX;
randomY = new Random().nextInt(Constants.COUNT_CELLS_Y);
int currentY = randomY;
boolean placed = false;
while(!placed){
if(gameField.getState(currentX, currentY) == 0) {
gameField.setState(currentX, currentY, state);
placed = true;
}else{
if(currentX+1 < Constants.COUNT_CELLS_X) {
currentX++;
}else{
currentX = 0;
if(currentY+1 < Constants.COUNT_CELLS_Y) {
currentY++;
}else{
currentY = 0;
}
}
if ((currentX == randomX) && (currentY==randomY) ) { //No place -> Something went wrong
ErrorCatcher.cellCreationFailure();
}
}
}
score += state;
}
private static void input() {
keyboardModule.update();
/* Определяем направление, в котором нужно будет произвести сдвиг */
direction = keyboardModule.lastDirectionKeyPressed();
endOfGame = endOfGame || graphicsModule.isCloseRequested() || keyboardModule.wasEscPressed();
}
public interface GraphicsModule {
/**
* Отрисовывает переданное игровое поле
*
* @param field Игровое поле, которое необходимо отрисовать
*/
void draw(GameField field);
/**
* @return Возвращает true, если в окне нажат "крестик"
*/
boolean isCloseRequested();
/**
* Заключительные действия, на случай, если модулю нужно подчистить за собой.
*/
void destroy();
}
public interface KeyboardHandleModule {
/**
* Считывание последних данных из стека событий, если можулю это необходимо
*/
void update();
/**
* @return Возвращает направление последней нажатой "стрелочки",
* либо AWAITING, если не было нажато ни одной
*/
ru.tproger.main.Direction lastDirectionKeyPressed();
/**
* @return Возвращает информацию о том, был ли нажат ESCAPE за последнюю итерацию
*/
boolean wasEscPressed();
}
private static void logic() {
if(direction!=Direction.AWAITING){
if(shift(direction)) generateNewCell();
direction=Direction.AWAITING;
}
}
public enum Direction {
AWAITING, UP, DOWN, LEFT, RIGHT
}
/**
* Изменяет gameField, сдвигая все ячейки в указанном направлении,
* вызывая shiftRow() для каждой строки/столбца (в зависимости от направления)
*
* @param direction Направление, в котором необходимо совершить сдвиг
* @return Возвращает true, если сдвиг прошёл успешно (поле изменилось)
*/
private static boolean shift(Direction direction) {
boolean ret = false;
switch(direction) {
case UP:
case DOWN:
/*По очереди сдвигаем числа всех столбцов в нужном направлении*/
for(int i = 0; i< Constants.COUNT_CELLS_X; i++){
/*Запрашиваем очередной столбец*/
int[] arg = gameField.getColumn(i);
/*В зависимости от направления сдвига, меняем или не меняем порядок чисел на противоположный*/
if(direction==Direction.UP){
int[] tmp = new int[arg.length];
for(int e = 0; e < tmp.length; e++){
tmp[e] = arg[tmp.length-e-1];
}
arg = tmp;
}
/*Пытаемся сдвинуть числа в этом столбце*/
ShiftRowResult result = shiftRow (arg);
/*Возвращаем линию в исходный порядок*/
if(direction==Direction.UP){
int[] tmp = new int[result.shiftedRow.length];
for(int e = 0; e < tmp.length; e++){
tmp[e] = result.shiftedRow[tmp.length-e-1];
}
result.shiftedRow = tmp;
}
/*Записываем изменённый столбец*/
gameField.setColumn(i, result.shiftedRow);
/*Если хоть одна линия была изменена, значит было изменено всё поле*/
ret = ret || result.didAnythingMove;
}
break;
case LEFT:
case RIGHT:
/*По очереди сдвигаем числа всех строк в нужном направлении*/
for(int i = 0; i< Constants.COUNT_CELLS_Y; i++){
/*Запрашиваем очередную строку*/
int[] arg = gameField.getLine(i);
/*В зависимости от направления сдвига, меняем или не меняем порядок чисел на противоположный*/
if(direction==Direction.RIGHT){
int[] tmp = new int[arg.length];
for(int e = 0; e < tmp.length; e++){
tmp[e] = arg[tmp.length-e-1];
}
arg = tmp;
}
/*Пытаемся сдвинуть числа в этом столбце*/
ShiftRowResult result = shiftRow (arg);
/*Возвращаем линию в исходный порядок*/
if(direction==Direction.RIGHT){
int[] tmp = new int[result.shiftedRow.length];
for(int e = 0; e < tmp.length; e++){
tmp[e] = result.shiftedRow[tmp.length-e-1];
}
result.shiftedRow = tmp;
}
/*Записываем изменённую строку*/
gameField.setLine(i, result.shiftedRow);
/*Если хоть одна линия была изменена, значит было изменено всё поле*/
ret = ret || result.didAnythingMove;
}
break;
default:
ErrorCatcher.shiftFailureWrongParam();
break;
}
return ret;
}
/**
* Результат работы метода сдвига shiftRow().
* Содержит изменённую строку и информацию о том, эквивалентна ли она начальной.
*/
private static class ShiftRowResult{
boolean didAnythingMove;
int[] shiftedRow;
}
private static ShiftRowResult shiftRow (int[] oldRow) {
ShiftRowResult ret = new ShiftRowResult();
int[] oldRowWithoutZeroes = new int[oldRow.length];
{
int q = 0;
for (int i = 0; i < oldRow.length; i++) {
if(oldRow[i] != 0){
if(q != i){
/*
* Это значит, что мы передвинули ячейку
* на место какого-то нуля (пустой плитки)
*/
ret.didAnythingMove = true;
}
oldRowWithoutZeroes[q] = oldRow[i];
q++;
}
}
}
ret.shiftedRow = new int[oldRowWithoutZeroes.length];
{
int q = 0;
{
int i = 0;
while (i < oldRowWithoutZeroes.length) {
if((i+1 < oldRowWithoutZeroes.length) && (oldRowWithoutZeroes[i] == oldRowWithoutZeroes[i + 1])
&& oldRowWithoutZeroes[i]!=0) { {
ret.didAnythingMove = true;
ret.shiftedRow[q] = oldRowWithoutZeroes[i] * 2;
i++;
} else {
ret.shiftedRow[q] = oldRowWithoutZeroes[i];
}
q++;
i++;
}
}
}
Достарыңызбен бөлісу: |