diff --git a/pom.xml b/pom.xml
index 8afd225..d825c3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,5 +25,10 @@
io.vavr
vavr
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
diff --git a/src/main/java/labyrinth/Labyrinth.java b/src/main/java/labyrinth/Labyrinth.java
index c2599e5..5480fcb 100644
--- a/src/main/java/labyrinth/Labyrinth.java
+++ b/src/main/java/labyrinth/Labyrinth.java
@@ -20,7 +20,11 @@ public class Labyrinth {
}
Tile getTileAt(@NonNull final Position position) {
- return this.field[position.getX()][position.getY()];
+ return this.getTileAt(position.getX(), position.getY());
+ }
+
+ Tile getTileAt(final int x, final int y) {
+ return this.field[x][y];
}
private void initField() {
@@ -41,9 +45,7 @@ public class Labyrinth {
tile.preventDiggingToOrFrom(Direction.RIGHT);
}
if (y == 0) {
- if (x != 0) {
- tile.preventDiggingToOrFrom(Direction.TOP);
- }
+ tile.preventDiggingToOrFrom(Direction.TOP);
} else if (y == height - 1) {
tile.preventDiggingToOrFrom(Direction.BOTTOM);
}
@@ -57,14 +59,16 @@ public class Labyrinth {
private final Deque 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);
+ bottomRightTile.digFrom(Direction.BOTTOM);
+ this.positions.push(bottomRight);
+ this.dig();
+ final Position topLeft = new Position(0, 0);
+ final Tile topLeftTile = Labyrinth.this.getTileAt(topLeft);
+ topLeftTile.enableDiggingToOrFrom(Direction.TOP);
+ topLeftTile.digTo(Direction.TOP);
}
private void dig() {
diff --git a/src/main/java/labyrinth/Main.java b/src/main/java/labyrinth/Main.java
index 26f0971..2dfaada 100644
--- a/src/main/java/labyrinth/Main.java
+++ b/src/main/java/labyrinth/Main.java
@@ -4,9 +4,9 @@ import lombok.NonNull;
public class Main {
public static void main(@NonNull final String[] args) {
- int width = 5;
- int height = 8;
+ int width = 110;
+ int height = 15;
final Labyrinth labyrinth = new Labyrinth(width, height);
- System.out.println(SimpleTextRenderer.render(labyrinth));
+ System.out.println(TextRenderer.render(labyrinth));
}
}
diff --git a/src/main/java/labyrinth/SimpleTextRenderer.java b/src/main/java/labyrinth/SimpleTextRenderer.java
deleted file mode 100644
index e80bc69..0000000
--- a/src/main/java/labyrinth/SimpleTextRenderer.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package labyrinth;
-
-import lombok.NonNull;
-import lombok.experimental.UtilityClass;
-
-@UtilityClass
-public class SimpleTextRenderer {
- 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';
-
- public String render(@NonNull final Labyrinth labyrinth) {
- final int width;
- final int height;
- width = labyrinth.field.length;
- if (width == 0) {
- return "";
- }
- height = labyrinth.field[0].length;
- StringBuilder sb = new StringBuilder();
- for (int y = 0; y < height; y++) {
- // TOP WALL
- for (int x = 0; x < width; x++) {
- final Tile tile = labyrinth.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 < width; x++) {
- final Tile tile = labyrinth.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 < width; x++) {
- final Tile tile = labyrinth.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();
- }
-}
diff --git a/src/main/java/labyrinth/TextRenderer.java b/src/main/java/labyrinth/TextRenderer.java
new file mode 100644
index 0000000..d04ae0c
--- /dev/null
+++ b/src/main/java/labyrinth/TextRenderer.java
@@ -0,0 +1,250 @@
+package labyrinth;
+
+import lombok.Builder;
+import lombok.NonNull;
+import lombok.Value;
+import lombok.With;
+import org.jetbrains.annotations.Nullable;
+
+public class TextRenderer {
+ static final String HORIZONTAL = "\u2500";
+ static final String VERTICAL = "\u2502";
+ static final String LEFT = "\u2574";
+ static final String UP = "\u2575";
+ static final String RIGHT = "\u2576";
+ static final String DOWN = "\u2577";
+ static final String DOWN_RIGHT = "\u250c";
+ static final String DOWN_LEFT = "\u2510";
+ static final String UP_RIGHT = "\u2514";
+ static final String UP_LEFT = "\u2518";
+ static final String VERTICAL_RIGHT = "\u251c";
+ static final String VERTICAL_LEFT = "\u2524";
+ static final String HORIZONTAL_DOWN = "\u252c";
+ static final String HORIZONTAL_UP = "\u2534";
+ static final String CROSS = "\u253c";
+ private final Labyrinth labyrinth;
+ private final int width;
+ private final int height;
+ private int x = 0;
+ private int y = 0;
+ private int border = 0;
+
+ private TextRenderer(@NonNull final Labyrinth labyrinth, final int width, final int height) {
+ this.labyrinth = labyrinth;
+ this.width = width;
+ this.height = height;
+ }
+
+ public static String render(@NonNull final Labyrinth labyrinth) {
+ final int width = labyrinth.field.length;
+ if (width == 0) {
+ return "";
+ }
+ final int height = labyrinth.field[0].length;
+ final TextRenderer renderer = new TextRenderer(labyrinth, width, height);
+
+ final StringBuilder sb = new StringBuilder();
+ while (renderer.hasNext()) {
+ sb.append(renderer.next());
+ }
+ return sb.toString();
+ }
+
+ private boolean hasNext() {
+ return this.y < this.height;
+ }
+
+ private String next() {
+ final Tile currentTile = this.labyrinth.getTileAt(this.x, this.y);
+ final Tile leftTile = this.x > 0 ? this.labyrinth.getTileAt(this.x - 1, this.y) : null;
+ final Tile topTile = this.y > 0 ? this.labyrinth.getTileAt(this.x, this.y - 1) : null;
+ String s = "";
+ switch (this.border) {
+ case 0:
+ s = this.renderTop(currentTile, leftTile, topTile);
+ break;
+ case 1:
+ s = this.renderCenter(currentTile);
+ break;
+ case 2:
+ s = this.renderBottom(currentTile, leftTile);
+ break;
+ }
+ // do some magic ...
+ this.x++;
+ if (this.x == this.width) {
+ this.x = 0;
+ this.border++;
+ }
+ if (this.border == 2 && this.y < this.height - 1) {
+ this.border = 0;
+ this.y++;
+ }
+ if (this.border == 3) {
+ this.border = 0;
+ this.y++;
+ }
+ return s;
+ }
+
+ private String renderTop(@NonNull final Tile currentTile, @Nullable final Tile leftTile, @Nullable final Tile topTile) {
+ final CharDefinition.CharDefinitionBuilder builder1 = CharDefinition.builder();
+ final CharDefinition.CharDefinitionBuilder builder2 = CharDefinition.builder();
+ final CharDefinition.CharDefinitionBuilder builder3 = CharDefinition.builder();
+ String result;
+ if (currentTile.hasWallAt(Direction.LEFT)) {
+ builder1.down(true);
+ }
+ if (currentTile.hasWallAt(Direction.TOP)) {
+ builder1.right(true);
+ builder2.left(true).right(true);
+ builder3.left(true);
+ }
+ if (currentTile.hasWallAt(Direction.RIGHT)) {
+ builder3.down(true);
+ }
+ if (leftTile != null && leftTile.hasWallAt(Direction.TOP)) {
+ builder1.left(true);
+ }
+ if (topTile != null) {
+ if (topTile.hasWallAt(Direction.LEFT)) {
+ builder1.up(true);
+ }
+ if (topTile.hasWallAt(Direction.RIGHT)) {
+ builder3.up(true);
+ }
+ }
+ result = builder1.build().toString() + builder2.build();
+ if (this.x == this.width - 1) {
+ result += builder3.build() + "\n";
+ }
+ return result;
+ }
+
+ private String renderCenter(@NonNull final Tile currentTile) {
+ final CharDefinition.CharDefinitionBuilder builder1 = CharDefinition.builder();
+ final CharDefinition.CharDefinitionBuilder builder2 = CharDefinition.builder();
+ String result;
+ if (currentTile.hasWallAt(Direction.LEFT)) {
+ builder1.up(true).down(true);
+ }
+ if (currentTile.hasWallAt(Direction.RIGHT)) {
+ builder2.up(true).down(true);
+ }
+
+ result = builder1.build() + " ";
+
+ if (this.x == this.width - 1) {
+ result += builder2.build() + "\n";
+ }
+
+ return result;
+ }
+
+ private String renderBottom(@NonNull final Tile currentTile, @Nullable final Tile leftTile) {
+ String result;
+ final CharDefinition.CharDefinitionBuilder builder1 = CharDefinition.builder();
+ final CharDefinition.CharDefinitionBuilder builder2 = CharDefinition.builder();
+ final CharDefinition.CharDefinitionBuilder builder3 = CharDefinition.builder();
+
+ if (currentTile.hasWallAt(Direction.LEFT)) {
+ builder1.up(true);
+ }
+ if (currentTile.hasWallAt(Direction.BOTTOM)) {
+ builder1.right(true);
+ builder2.left(true).right(true);
+ builder3.left(true);
+ }
+ if (currentTile.hasWallAt(Direction.RIGHT)) {
+ builder3.up(true);
+ }
+ if (leftTile != null && leftTile.hasWallAt(Direction.BOTTOM)) {
+ builder1.left(true);
+ }
+
+ result = builder1.build().toString() + builder2.build();
+
+ if (this.x == this.width - 1) {
+ result += builder3.build();
+ }
+ return result;
+ }
+
+ @Value
+ @Builder
+ @With
+ static class CharDefinition {
+ @Builder.Default
+ boolean up = false;
+ @Builder.Default
+ boolean down = false;
+ @Builder.Default
+ boolean left = false;
+ @Builder.Default
+ boolean right = false;
+
+ public String toString() {
+ if (this.up) {
+ if (this.down) {
+ if (this.left) {
+ if (this.right) {
+ return CROSS;
+ } else {
+ return VERTICAL_LEFT;
+ }
+ } else {
+ if (this.right) {
+ return VERTICAL_RIGHT;
+ } else {
+ return VERTICAL;
+ }
+ }
+ } else {
+ if (this.left) {
+ if (this.right) {
+ return HORIZONTAL_UP;
+ } else {
+ return UP_LEFT;
+ }
+ } else {
+ if (this.right) {
+ return UP_RIGHT;
+ } else {
+ return UP;
+ }
+ }
+ }
+ } else {
+ if (this.down) {
+ if (this.left) {
+ if (this.right) {
+ return HORIZONTAL_DOWN;
+ } else {
+ return DOWN_LEFT;
+ }
+ } else {
+ if (this.right) {
+ return DOWN_RIGHT;
+ } else {
+ return DOWN;
+ }
+ }
+ } else {
+ if (this.left) {
+ if (this.right) {
+ return HORIZONTAL;
+ } else {
+ return LEFT;
+ }
+ } else {
+ if (this.right) {
+ return RIGHT;
+ } else {
+ return " ";
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/labyrinth/Tile.java b/src/main/java/labyrinth/Tile.java
index 7ad5135..5ba725c 100644
--- a/src/main/java/labyrinth/Tile.java
+++ b/src/main/java/labyrinth/Tile.java
@@ -46,4 +46,8 @@ public class Tile {
public Option getRandomAvailableDirection() {
return Stream.ofAll(this.walls.getSet(true)).shuffle().headOption();
}
+
+ public boolean hasWallAt(@NonNull final Direction direction) {
+ return this.walls.isSet(direction);
+ }
}
diff --git a/src/test/java/labyrinth/TextRendererTest.java b/src/test/java/labyrinth/TextRendererTest.java
new file mode 100644
index 0000000..d24dec5
--- /dev/null
+++ b/src/test/java/labyrinth/TextRendererTest.java
@@ -0,0 +1,27 @@
+package labyrinth;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class TextRendererTest {
+ @Test
+ void charDefTest() {
+ assertEquals(" ", new TextRenderer.CharDefinition(false, false, false, false).toString());
+ assertEquals("╶", new TextRenderer.CharDefinition(false, false, false, true).toString());
+ assertEquals("╴", new TextRenderer.CharDefinition(false, false, true, false).toString());
+ assertEquals("─", new TextRenderer.CharDefinition(false, false, true, true).toString());
+ assertEquals("╷", new TextRenderer.CharDefinition(false, true, false, false).toString());
+ assertEquals("┌", new TextRenderer.CharDefinition(false, true, false, true).toString());
+ assertEquals("┐", new TextRenderer.CharDefinition(false, true, true, false).toString());
+ assertEquals("┬", new TextRenderer.CharDefinition(false, true, true, true).toString());
+ assertEquals("╵", new TextRenderer.CharDefinition(true, false, false, false).toString());
+ assertEquals("└", new TextRenderer.CharDefinition(true, false, false, true).toString());
+ assertEquals("┘", new TextRenderer.CharDefinition(true, false, true, false).toString());
+ assertEquals("┴", new TextRenderer.CharDefinition(true, false, true, true).toString());
+ assertEquals("│", new TextRenderer.CharDefinition(true, true, false, false).toString());
+ assertEquals("├", new TextRenderer.CharDefinition(true, true, false, true).toString());
+ assertEquals("┤", new TextRenderer.CharDefinition(true, true, true, false).toString());
+ assertEquals("┼", new TextRenderer.CharDefinition(true, true, true, true).toString());
+ }
+}