maze-generator/src/main/java/ch/fritteli/maze/generator/model/Maze.java

132 lines
4.2 KiB
Java

package ch.fritteli.maze.generator.model;
import io.vavr.control.Option;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
@EqualsAndHashCode
@ToString
public class Maze {
private final Tile[][] field;
@Getter
private final int width;
@Getter
private final int height;
@Getter
private final long randomSeed;
@Getter
private final Position start;
@Getter
private final Position end;
public Maze(final int width, final int height) {
this(width, height, System.nanoTime());
}
public Maze(final int width, final int height, @NonNull final Position start, @NonNull final Position end) {
this(width, height, System.nanoTime(), start, end);
}
public Maze(final int width, final int height, final long randomSeed) {
this(width, height, randomSeed, new Position(0, 0), new Position(width - 1, height - 1));
}
public Maze(final int width, final int height, final long randomSeed, @NonNull final Position start, @NonNull final Position end) {
if (width <= 1 || height <= 1) {
throw new IllegalArgumentException("width and height must be >1");
}
if (start.equals(end)) {
throw new IllegalArgumentException("'start' must not be equal to 'end'");
}
if (start.getX() != 0 && start.getX() != width - 1 && start.getY() != 0 && start.getY() != height - 1) {
throw new IllegalArgumentException("'start' must be at the edge of the maze");
}
if (end.getX() != 0 && end.getX() != width - 1 && end.getY() != 0 && end.getY() != height - 1) {
throw new IllegalArgumentException("'end' must be at the edge of the maze");
}
this.width = width;
this.height = height;
this.randomSeed = randomSeed;
this.field = new Tile[width][height];
this.start = start;
this.end = end;
this.initField();
}
/**
* INTERNAL API. Exists only for deserialization. Not to be called from user code.
*/
private Maze(@NonNull final Tile[][] field, final int width, final int height, final long randomSeed) {
this.field = field;
this.width = width;
this.height = height;
this.randomSeed = randomSeed;
this.start = new Position(0, 0);
this.end = new Position(this.width - 1, this.height - 1);
}
/**
* INTERNAL API. Exists only for deserialization. Not to be called from user code.
*/
private Maze(@NonNull final Tile[][] field, final int width, final int height, @NonNull final Position start, @NonNull final Position end, final long randomSeed) {
this.field = field;
this.width = width;
this.height = height;
this.randomSeed = randomSeed;
this.start = start;
this.end = end;
}
@NonNull
public Option<Tile> getTileAt(@NonNull final Position position) {
return this.getTileAt(position.getX(), position.getY());
}
@NonNull
public Option<Tile> getTileAt(final int x, final int y) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
return Option.none();
}
return Option.of(this.field[x][y]);
}
@NonNull
public Tile getStartTile() {
return this.getTileAt(this.start).get();
}
@NonNull
public Tile getEndTile() {
return this.getTileAt(this.end).get();
}
private void initField() {
for (int x = 0; x < this.width; x++) {
this.field[x] = new Tile[this.height];
for (int y = 0; y < this.height; y++) {
final Tile tile = new Tile();
this.hardenWalls(tile, x, y);
this.field[x][y] = tile;
}
}
}
private void hardenWalls(@NonNull final Tile tile, final int x, final int y) {
if (x == 0) {
tile.preventDiggingToOrFrom(Direction.LEFT);
}
if (x == this.width - 1) {
tile.preventDiggingToOrFrom(Direction.RIGHT);
}
if (y == 0) {
tile.preventDiggingToOrFrom(Direction.TOP);
}
if (y == this.height - 1) {
tile.preventDiggingToOrFrom(Direction.BOTTOM);
}
}
}