package generator;
import java.util.PriorityQueue;
import engine.Board;
/**
* BoardManager provides static methods to modify board.
*/
public final class BoardManager {
// *************************************************************************
// Content
/**
* Removes all elements from the board
* and makes all fields empty.
*
* @param board - the given board
*/
public static void removeElements(Board board) {
for (int y=0;y<board.height;y++)
for (int x=0;x<board.width;x++)
board.setElement(x,y,Board.EMPTY);
}
/**
* Removes all blocks from the board.
*
* @param board - the given board
*/
public static void removeBlocks(Board board) {
for (int y=0;y<board.height;y++)
for (int x=0;x<board.width;x++)
if (board.isBlock(x,y))
board.setElement(x,y,Board.EMPTY);
board.doFramesToStability();
}
/**
* Removes all surrounded solids and makes empty areas there.
*
* @param board - the given board
*/
public static void removeSurroundedSolids(Board board) {
boolean[][] surrounded = new boolean[board.width][board.height];
for (int y=1;y<board.height-1;y++)
for (int x=1;x<board.width-1;x++)
if (board.isSurroundedSolid(x,y))
surrounded[x][y] = true;
for (int y=1;y<board.height-1;y++)
for (int x=1;x<board.width-1;x++)
if (surrounded[x][y])
board.setElement(x,y,Board.EMPTY);
}
/**
* Converts concrete from the board to solid.
*
* @param board - the given board
*/
public static void convertConcrete(Board board) {
for (int y=0;y<board.height;y++)
for (int x=0;x<board.width;x++)
if (board.getType(x,y) == Board.CONCRETE)
board.setElement(x,y,Board.SOLID);
}
// *************************************************************************
// Resize
/**
* Gets the resized board. The original content (without border)
* is copied to new board starting from given shift x and shift y.
* Content outside the board is not copied.
*
* @param board - board to be resized
* @param width - new width
* @param height - new height
* @param shiftx - shift x of original content
* @param shifty - shift y of original content
*/
public static Board getResized(Board board,int width,int height,int shiftx,int shifty) {
Board newBoard = new Board(width,height);
int x1 = 0,x2 = width,y1 = 0,y2 = height;
if (x1 < shiftx) x1 = shiftx;
if (x2 > board.width+shiftx) x2 = board.width+shiftx;
if (y1 < shifty) y1 = shifty;
if (y2 > board.height+shifty) y2 = board.height+shifty;
for (int y=y1;y<y2;y++)
for (int x=x1;x<x2;x++) {
newBoard.setElement(x,y,
board.getType(x-shiftx,y-shifty),
board.getColor(x-shiftx,y-shifty),
board.getAction(x-shiftx,y-shifty));
}
return newBoard;
}
// *************************************************************************
// Make connected
/**
* Makes a connectivity between empty or containing block fields.
*
* @param board - the board to be connected
*/
public static void makeConnected(Board board) {
final byte END= 0;
final byte UP = 1;
final byte RIGHT = UP+1;
final byte DOWN = UP+2;
final byte LEFT = UP+3;
final int WEIGHT_SOLID = 1;
final int WEIGHT_SOLID_CONCRETE = 1;
final int WEIGHT_ELEVATOR = 50;
final int WEIGHT_UNDER_ELEVATOR = 50;
final int WEIGHT_NEAR_ELEVATOR = 10;
final int WEIGHT_PAINTER = 50;
final int WEIGHT_UNDER_PAINTER = 50;
final int WEIGHT_NEAR_LAVA = 50;
final int WEIGHT_LAVA = 100;
int x=-1, y=-1;
for(int i=0; i < board.width; i++)
for(int j=0; j < board.height; j++)
if (board.isEmpty(i,j)) {
x = i; y = j; i = board.width; break;
}
if (x == -1 || y == -1) return;
int [][][] tab = new int[board.width][board.height][2];
for(int i=0; i < board.width; i++)
for(int j=0; j < board.height; j++)
tab[i][j][0] = Byte.MAX_VALUE;
tab[x][y][0] = 0;
tab[x][y][1] = END;
PriorityQueue<Field> queue = new PriorityQueue<Field>();
queue.add(new Field(x,y,0));
while(queue.size() > 0) {
Field f = queue.remove();
int posX, posY, direction;
for (int i=0;i<4;i++) {
switch (i) {
case 0: posX = f.x-1; posY=f.y; direction = LEFT; break;
case 1: posX = f.x; posY=f.y-1; direction = UP; break;
case 2: posX = f.x; posY=f.y+1; direction = DOWN; break;
case 3: posX = f.x+1; posY=f.y; direction = RIGHT; break;
default: assert false; posX=posY=direction=0; break;
}
if (board.isInside(posX, posY) && tab[posX][posY][0] > f.distance) {
int type = board.getType(posX,posY);
if (f.distance == 0 && isAsEmpty(posX, posY, board)) {
tab[posX][posY][0] = 0; tab[posX][posY][1]=END;
queue.remove(new Field(posX,posY,0));
queue.add(new Field(posX,posY,0));
}
if (type != Board.EMPTY && !board.isBlock(posX, posY) &&
tab[posX][posY][0] > f.distance+1) {
if (board.getType(posX-1,posY) != Board.LAVA &&
board.getType(posX+1,posY) != Board.LAVA &&
board.getType(posX,posY-1) != Board.LAVA &&
board.getType(posX,posY-1) != Board.ELEVATOR &&
board.getType(posX,posY-1) != Board.PAINTER) {
if (board.getType(posX-1,posY+1) == Board.ELEVATOR
|| board.getType(posX+1,posY+1) == Board.ELEVATOR)
tab[posX][posY][0] = f.distance+WEIGHT_NEAR_ELEVATOR;
else if (type == Board.CONCRETE)
tab[posX][posY][0] = f.distance+WEIGHT_SOLID_CONCRETE;
else if (type == Board.ELEVATOR || type == Board.ELEVATOR_ROOT)
tab[posX][posY][0] = f.distance+WEIGHT_ELEVATOR;
else if (type == Board.PAINTER)
tab[posX][posY][0] = f.distance+WEIGHT_PAINTER;
else if (type == Board.LAVA)
tab[posX][posY][0] = f.distance+WEIGHT_LAVA;
else
tab[posX][posY][0] = f.distance+WEIGHT_SOLID;
} else if (board.getType(posX,posY-1) == Board.ELEVATOR
&& direction == DOWN) {
tab[posX][posY][0] = f.distance+WEIGHT_UNDER_ELEVATOR;
} else if (board.getType(posX,posY-1) == Board.PAINTER
&& direction == DOWN) {
tab[posX][posY][0] = f.distance+WEIGHT_UNDER_PAINTER;
} else if ((board.getType(posX-1, posY) == Board.LAVA
|| board.getType(posX+1, posY) == Board.LAVA)
&& (direction == DOWN || direction == UP)){
tab[posX][posY][0] = WEIGHT_NEAR_LAVA;
} else if ((board.getType(posX, posY-1) == Board.LAVA)
&& (direction == DOWN)){
tab[posX][posY][0] = WEIGHT_NEAR_LAVA;
}
tab[posX][posY][1] = direction;
queue.remove(new Field(posX,posY,0));
queue.add(new Field(posX,posY,tab[posX][posY][0]));
}
if ((type == Board.EMPTY || board.isBlock(posX, posY) ||
(type == Board.ELEVATOR || type == Board.ELEVATOR_ROOT)
&& board.getType(posX, posY+1)!= Board.SOLID)
&& f.distance > 0 && tab[posX][posY][0] > f.distance+1) {
tab[posX][posY][0] = 0; tab[posX][posY][1]=END;
queue.remove(new Field(posX,posY,0));
queue.add(new Field(posX,posY,0));
while( direction != END) {
if (direction == UP) posY++; else if (direction == LEFT) posX++;
else if (direction == DOWN) posY--; else posX--;
direction = tab[posX][posY][1];
tab[posX][posY][0] = 0; tab[posX][posY][1] = END;
if (direction != END) {
if (board.getType(posX-1, posY) == Board.LAVA)
board.setElement(posX-1, posY, Board.SOLID);
if (board.getType(posX+1, posY) == Board.LAVA)
board.setElement(posX+1, posY, Board.SOLID);
queue.remove(new Field(posX,posY,0));
queue.add(new Field(posX,posY,0));
if (board.getType(posX, posY) == Board.ELEVATOR
|| board.getType(posX, posY) == Board.ELEVATOR_ROOT) {
int k = posY;
while (k>0 && (board.getType(posX, k) == Board.ELEVATOR ||
board.getType(posX, k) == Board.ELEVATOR_ROOT)) {
board.setElement(posX, k, Board.EMPTY); k--;
}
k = posY+1;
while (k<board.height && (board.getType(posX, k) == Board.ELEVATOR ||
board.getType(posX, k) == Board.ELEVATOR_ROOT)) {
board.setElement(posX, k, Board.EMPTY); k++;
}
}
board.setElement(posX,posY, Board.EMPTY);
}
}
}
}
}
}
}
/*
* Checks if the field should be treated like a empty during making
* connectivity.
*
* @param x - field's x
* @param y - field's y
* @param board
* @return true - if the field should be treated like empty
*/
private static boolean isAsEmpty(int x, int y, Board board ) {
int type = board.getType(x,y);
if (type == Board.EMPTY || board.isBlock(x,y) ||
(type == Board.ELEVATOR || type == Board.ELEVATOR_ROOT)
&& board.getType(x, y+1) != Board.SOLID)
return true;
if (type == Board.ICE) {
while (board.getType(x, y-1) == Board.ICE) y--;
if (!board.isSolid(x, y-1)) return true;
}
return false;
}
/*
* Class used in method makeConnected(board). Contains the field coordinates
* and its distance from connected part of the board.
*/
private static class Field implements Comparable<Field>{
public int x, y, distance;
public Field(int x, int y, int distance) {
this.x = x;
this.y = y;
this.distance = distance;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Field) {
if (((Field) obj).x == x && ((Field) obj).y ==y) return true;
else return false;
}
return false;
}
@Override
public int compareTo(Field f) {
if (distance > f.distance) return 1;
else if (distance < f.distance) return -1;
return 0;
}
}
}