195 lines
7.0 KiB
Java
195 lines
7.0 KiB
Java
package labyrinth;
|
|
|
|
import io.vavr.control.Option;
|
|
import lombok.NonNull;
|
|
|
|
import java.util.Deque;
|
|
import java.util.LinkedList;
|
|
|
|
public class Labyrinth {
|
|
private final Tile[][] field;
|
|
private final int width;
|
|
private final int height;
|
|
|
|
public Labyrinth(final int width, final int height) {
|
|
this.width = width;
|
|
this.height = height;
|
|
this.field = new Tile[width][height];
|
|
this.initField();
|
|
System.out.println(this);
|
|
this.generate();
|
|
}
|
|
private static final char TOP_LEFT = '\u250c';
|
|
private static final char TOP_RIGHT = '\u2510';
|
|
private static final char MIDDLE_LEFT = '\u251c';
|
|
private static final char MIDDLE_RIGHT = '\u2524';
|
|
private static final char BOTTOM_LEFT = '\u2514';
|
|
private static final char BOTTOM_RIGHT = '\u2518';
|
|
private static final char HORIZONTAL = '\u2500';
|
|
private static final char VERTICAL = '\u2502';
|
|
|
|
@Override
|
|
public String toString() {
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int y = 0; y < this.height; y++) {
|
|
// TOP WALL
|
|
for (int x = 0; x < this.width; x++) {
|
|
final Tile tile = this.getTileAt(new Position(x, y));
|
|
final boolean top = tile.getWalls().isSet(Direction.TOP);
|
|
final boolean topHard = tile.getWalls().getHardened().contains(Direction.TOP);
|
|
sb.append(TOP_LEFT);
|
|
if (topHard) {
|
|
if (top) {
|
|
sb.append(HORIZONTAL);
|
|
} else {
|
|
sb.append("?");
|
|
}
|
|
} else {
|
|
if (top) {
|
|
sb.append("-");
|
|
} else {
|
|
sb.append(" ");
|
|
}
|
|
}
|
|
sb.append(TOP_RIGHT);
|
|
}
|
|
sb.append("\n");
|
|
// LEFT WALL, CENTER, RIGHT WALL
|
|
for (int x = 0; x < this.width; x++) {
|
|
final Tile tile = this.getTileAt(new Position(x, y));
|
|
// left
|
|
final boolean left = tile.getWalls().isSet(Direction.LEFT);
|
|
final boolean leftHard = tile.getWalls().getHardened().contains(Direction.LEFT);
|
|
if (leftHard) {
|
|
if (left) {
|
|
sb.append(VERTICAL);
|
|
} else {
|
|
sb.append("?");
|
|
}
|
|
} else {
|
|
if (left) {
|
|
sb.append(":");
|
|
} else {
|
|
sb.append(" ");
|
|
}
|
|
}
|
|
// center
|
|
sb.append(" ");
|
|
// right
|
|
final boolean right = tile.getWalls().isSet(Direction.RIGHT);
|
|
final boolean rightHard = tile.getWalls().getHardened().contains(Direction.RIGHT);
|
|
if (rightHard) {
|
|
if (right) {
|
|
sb.append(VERTICAL);
|
|
} else {
|
|
sb.append("?");
|
|
}
|
|
} else {
|
|
if (right) {
|
|
sb.append(":");
|
|
} else {
|
|
sb.append(" ");
|
|
}
|
|
}
|
|
}
|
|
sb.append("\n");
|
|
// BOTTOM WALL
|
|
for (int x = 0; x < this.width; x++) {
|
|
final Tile tile = this.getTileAt(new Position(x, y));
|
|
final boolean bottom = tile.getWalls().isSet(Direction.BOTTOM);
|
|
final boolean bottomHard = tile.getWalls().getHardened().contains(Direction.BOTTOM);
|
|
sb.append(BOTTOM_LEFT);
|
|
if (bottomHard) {
|
|
if (bottom) {
|
|
sb.append(HORIZONTAL);
|
|
} else {
|
|
sb.append("?");
|
|
}
|
|
} else {
|
|
if (bottom) {
|
|
sb.append("-");
|
|
} else {
|
|
sb.append(" ");
|
|
}
|
|
}
|
|
sb.append(BOTTOM_RIGHT);
|
|
}
|
|
sb.append("\n");
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
private Tile getTileAt(@NonNull final Position position) {
|
|
return this.field[position.getX()][position.getY()];
|
|
}
|
|
|
|
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);
|
|
} else if (x == width - 1) {
|
|
tile.preventDiggingToOrFrom(Direction.RIGHT);
|
|
}
|
|
if (y == 0) {
|
|
if (x != 0) {
|
|
tile.preventDiggingToOrFrom(Direction.TOP);
|
|
}
|
|
} else if (y == height - 1) {
|
|
tile.preventDiggingToOrFrom(Direction.BOTTOM);
|
|
}
|
|
}
|
|
|
|
private void generate() {
|
|
new Generator();
|
|
}
|
|
|
|
public class Generator {
|
|
private final Deque<Position> positions = new LinkedList<>();
|
|
|
|
Generator() {
|
|
final Position topLeft = new Position(0, 0);
|
|
Labyrinth.this.getTileAt(topLeft).digFrom(Direction.TOP);
|
|
this.positions.push(topLeft);
|
|
this.dig();
|
|
final Position bottomRight = new Position(Labyrinth.this.width - 1, Labyrinth.this.height - 1);
|
|
final Tile bottomRightTile = Labyrinth.this.getTileAt(bottomRight);
|
|
bottomRightTile.enableDiggingToOrFrom(Direction.BOTTOM);
|
|
bottomRightTile.digTo(Direction.BOTTOM);
|
|
}
|
|
|
|
private void dig() {
|
|
while (!this.positions.isEmpty()) {
|
|
final Position currentPosition = this.positions.peek();
|
|
final Tile currentTile = Labyrinth.this.getTileAt(currentPosition);
|
|
final Option<Direction> directionToDigTo = currentTile.getRandomAvailableDirection();
|
|
if (directionToDigTo.isDefined()) {
|
|
final Direction digTo = directionToDigTo.get();
|
|
final Direction digFrom = digTo.getOpposite();
|
|
final Position neighborPosition = digTo.translate(currentPosition);
|
|
final Tile neighborTile = Labyrinth.this.getTileAt(neighborPosition);
|
|
if (currentTile.digTo(digTo) && neighborTile.digFrom(digFrom)) {
|
|
// all ok!
|
|
this.positions.push(neighborPosition);
|
|
} else {
|
|
// Hm, didn't work.
|
|
currentTile.undigTo(digTo);
|
|
currentTile.preventDiggingToOrFrom(digTo);
|
|
}
|
|
} else {
|
|
this.positions.pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|