Some more refactoring.

This commit is contained in:
Manuel Friedli 2020-09-30 23:18:26 +02:00
parent 8c68ea4844
commit 57d9d8c56b
4 changed files with 169 additions and 106 deletions

View file

@ -1,14 +1,17 @@
package ch.fritteli.labyrinth; package ch.fritteli.labyrinth;
import io.vavr.control.Option; import io.vavr.control.Option;
import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import java.util.Deque; import java.util.Deque;
import java.util.LinkedList; import java.util.LinkedList;
public class Labyrinth { public class Labyrinth {
final Tile[][] field; private final Tile[][] field;
@Getter
private final int width; private final int width;
@Getter
private final int height; private final int height;
public Labyrinth(final int width, final int height) { public Labyrinth(final int width, final int height) {
@ -41,34 +44,35 @@ public class Labyrinth {
private void hardenWalls(@NonNull final Tile tile, final int x, final int y) { private void hardenWalls(@NonNull final Tile tile, final int x, final int y) {
if (x == 0) { if (x == 0) {
tile.preventDiggingToOrFrom(Direction.LEFT); tile.preventDiggingToOrFrom(Direction.LEFT);
} else if (x == width - 1) { } else if (x == this.width - 1) {
tile.preventDiggingToOrFrom(Direction.RIGHT); tile.preventDiggingToOrFrom(Direction.RIGHT);
} }
if (y == 0) { if (y == 0) {
tile.preventDiggingToOrFrom(Direction.TOP); tile.preventDiggingToOrFrom(Direction.TOP);
} else if (y == height - 1) { } else if (y == this.height - 1) {
tile.preventDiggingToOrFrom(Direction.BOTTOM); tile.preventDiggingToOrFrom(Direction.BOTTOM);
} }
} }
private void generate() { private void generate() {
new Generator(); new Generator().run();
} }
public class Generator { private class Generator {
private final Deque<Position> positions = new LinkedList<>(); private final Deque<Position> positions = new LinkedList<>();
Generator() { void run() {
this.preDig();
this.dig();
this.postDig();
}
private void preDig() {
final Position bottomRight = new Position(Labyrinth.this.width - 1, Labyrinth.this.height - 1); final Position bottomRight = new Position(Labyrinth.this.width - 1, Labyrinth.this.height - 1);
final Tile bottomRightTile = Labyrinth.this.getTileAt(bottomRight); final Tile bottomRightTile = Labyrinth.this.getTileAt(bottomRight);
bottomRightTile.enableDiggingToOrFrom(Direction.BOTTOM); bottomRightTile.enableDiggingToOrFrom(Direction.BOTTOM);
bottomRightTile.digFrom(Direction.BOTTOM); bottomRightTile.digFrom(Direction.BOTTOM);
this.positions.push(bottomRight); 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() { private void dig() {
@ -94,5 +98,12 @@ public class Labyrinth {
} }
} }
} }
private void postDig() {
final Position topLeft = new Position(0, 0);
final Tile topLeftTile = Labyrinth.this.getTileAt(topLeft);
topLeftTile.enableDiggingToOrFrom(Direction.TOP);
topLeftTile.digTo(Direction.TOP);
}
} }
} }

View file

@ -1,33 +1,19 @@
package ch.fritteli.labyrinth; package ch.fritteli.labyrinth;
import lombok.Builder; import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.experimental.FieldDefaults;
import lombok.With;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class TextRenderer { 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 Labyrinth labyrinth;
private final int width; private final int width;
private final int height; private final int height;
private int x = 0; private int x = 0;
private int y = 0; private int y = 0;
private int border = 0; private int line = 0;
private TextRenderer(@NonNull final Labyrinth labyrinth, final int width, final int height) { private TextRenderer(@NonNull final Labyrinth labyrinth, final int width, final int height) {
this.labyrinth = labyrinth; this.labyrinth = labyrinth;
@ -36,11 +22,11 @@ public class TextRenderer {
} }
public static String render(@NonNull final Labyrinth labyrinth) { public static String render(@NonNull final Labyrinth labyrinth) {
final int width = labyrinth.field.length; final int width = labyrinth.getWidth();
if (width == 0) { if (width == 0) {
return ""; return "";
} }
final int height = labyrinth.field[0].length; final int height = labyrinth.getHeight();
final TextRenderer renderer = new TextRenderer(labyrinth, width, height); final TextRenderer renderer = new TextRenderer(labyrinth, width, height);
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@ -54,135 +40,200 @@ public class TextRenderer {
return this.y < this.height; return this.y < this.height;
} }
private Tile getTileOrNull(final int x, final int y) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
return null;
}
return this.labyrinth.getTileAt(x, y);
}
private String next() { private String next() {
final Tile currentTile = this.labyrinth.getTileAt(this.x, this.y); 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 leftTile = this.getTileOrNull(this.x - 1, this.y);
final Tile topTile = this.y > 0 ? this.labyrinth.getTileAt(this.x, this.y - 1) : null; final Tile topTile = this.getTileOrNull(this.x, this.y - 1);
String s = ""; final String s;
switch (this.border) { switch (this.line) {
case 0: case 0:
s = this.renderTop(currentTile, leftTile, topTile); s = this.renderTopLine(currentTile, leftTile, topTile);
break; break;
case 1: case 1:
s = this.renderCenter(currentTile); s = this.renderCenterLine(currentTile);
break; break;
case 2: case 2:
s = this.renderBottom(currentTile, leftTile); s = this.renderBottomLine(currentTile, leftTile);
break;
default:
s = "";
break; break;
} }
// do some magic ... // do some magic ...
this.x++; this.x++;
if (this.x == this.width) { if (this.x == this.width) {
this.x = 0; this.x = 0;
this.border++; this.line++;
} }
if (this.border == 2 && this.y < this.height - 1) { if (this.line == 2 && this.y < this.height - 1) {
this.border = 0; this.line = 0;
this.y++; this.y++;
} }
if (this.border == 3) { if (this.line == 3) {
this.border = 0; this.line = 0;
this.y++; this.y++;
} }
return s; return s;
} }
private String renderTop(@NonNull final Tile currentTile, @Nullable final Tile leftTile, @Nullable final Tile topTile) { private String renderTopLine(@NonNull final Tile currentTile, @Nullable final Tile leftTile, @Nullable final Tile topTile) {
final CharDefinition.CharDefinitionBuilder builder1 = CharDefinition.builder(); final CharDefinition charDef1 = new CharDefinition();
final CharDefinition.CharDefinitionBuilder builder2 = CharDefinition.builder(); final CharDefinition charDef2 = new CharDefinition();
final CharDefinition.CharDefinitionBuilder builder3 = CharDefinition.builder(); final CharDefinition charDef3 = new CharDefinition();
String result; String result;
if (currentTile.hasWallAt(Direction.LEFT)) { if (currentTile.hasWallAt(Direction.LEFT)) {
builder1.down(true); charDef1.down();
} }
if (currentTile.hasWallAt(Direction.TOP)) { if (currentTile.hasWallAt(Direction.TOP)) {
builder1.right(true); charDef1.right();
builder2.left(true).right(true); charDef2.horizontal();
builder3.left(true); charDef3.left();
} }
if (currentTile.hasWallAt(Direction.RIGHT)) { if (currentTile.hasWallAt(Direction.RIGHT)) {
builder3.down(true); charDef3.down();
} }
if (leftTile != null && leftTile.hasWallAt(Direction.TOP)) { if (leftTile != null && leftTile.hasWallAt(Direction.TOP)) {
builder1.left(true); charDef1.left();
} }
if (topTile != null) { if (topTile != null) {
if (topTile.hasWallAt(Direction.LEFT)) { if (topTile.hasWallAt(Direction.LEFT)) {
builder1.up(true); charDef1.up();
} }
if (topTile.hasWallAt(Direction.RIGHT)) { if (topTile.hasWallAt(Direction.RIGHT)) {
builder3.up(true); charDef3.up();
} }
} }
result = builder1.build().toString() + builder2.build(); result = charDef1.toString() + charDef2;
if (this.x == this.width - 1) { if (this.x == this.width - 1) {
result += builder3.build() + "\n"; result += charDef3 + "\n";
} }
return result; return result;
} }
private String renderCenter(@NonNull final Tile currentTile) { private String renderCenterLine(@NonNull final Tile currentTile) {
final CharDefinition.CharDefinitionBuilder builder1 = CharDefinition.builder(); final CharDefinition charDef1 = new CharDefinition();
final CharDefinition.CharDefinitionBuilder builder2 = CharDefinition.builder(); final CharDefinition charDef2 = new CharDefinition();
String result; String result;
if (currentTile.hasWallAt(Direction.LEFT)) { if (currentTile.hasWallAt(Direction.LEFT)) {
builder1.up(true).down(true); charDef1.vertical();
} }
if (currentTile.hasWallAt(Direction.RIGHT)) { if (currentTile.hasWallAt(Direction.RIGHT)) {
builder2.up(true).down(true); charDef2.vertical();
} }
result = builder1.build() + " "; result = charDef1 + " ";
if (this.x == this.width - 1) { if (this.x == this.width - 1) {
result += builder2.build() + "\n"; result += charDef2 + "\n";
} }
return result; return result;
} }
private String renderBottom(@NonNull final Tile currentTile, @Nullable final Tile leftTile) { private String renderBottomLine(@NonNull final Tile currentTile, @Nullable final Tile leftTile) {
String result; String result;
final CharDefinition.CharDefinitionBuilder builder1 = CharDefinition.builder(); final CharDefinition charDef1 = new CharDefinition();
final CharDefinition.CharDefinitionBuilder builder2 = CharDefinition.builder(); final CharDefinition charDef2 = new CharDefinition();
final CharDefinition.CharDefinitionBuilder builder3 = CharDefinition.builder(); final CharDefinition charDef3 = new CharDefinition();
if (currentTile.hasWallAt(Direction.LEFT)) { if (currentTile.hasWallAt(Direction.LEFT)) {
builder1.up(true); charDef1.up();
} }
if (currentTile.hasWallAt(Direction.BOTTOM)) { if (currentTile.hasWallAt(Direction.BOTTOM)) {
builder1.right(true); charDef1.right();
builder2.left(true).right(true); charDef2.horizontal();
builder3.left(true); charDef3.left();
} }
if (currentTile.hasWallAt(Direction.RIGHT)) { if (currentTile.hasWallAt(Direction.RIGHT)) {
builder3.up(true); charDef3.up();
} }
if (leftTile != null && leftTile.hasWallAt(Direction.BOTTOM)) { if (leftTile != null && leftTile.hasWallAt(Direction.BOTTOM)) {
builder1.left(true); charDef1.left();
} }
result = builder1.build().toString() + builder2.build(); result = charDef1.toString() + charDef2;
if (this.x == this.width - 1) { if (this.x == this.width - 1) {
result += builder3.build(); result += charDef3;
} }
return result; return result;
} }
@Value @FieldDefaults(level = AccessLevel.PRIVATE)
@Builder @NoArgsConstructor
@With @AllArgsConstructor
static class CharDefinition { static class CharDefinition {
@Builder.Default //
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";
boolean up = false; boolean up = false;
@Builder.Default
boolean down = false; boolean down = false;
@Builder.Default
boolean left = false; boolean left = false;
@Builder.Default
boolean right = false; boolean right = false;
CharDefinition up() {
this.up = true;
return this;
}
CharDefinition down() {
this.down = true;
return this;
}
CharDefinition vertical() {
return this.up().down();
}
CharDefinition left() {
this.left = true;
return this;
}
CharDefinition right() {
this.right = true;
return this;
}
CharDefinition horizontal() {
return this.left().right();
}
public String toString() { public String toString() {
if (this.up) { if (this.up) {
if (this.down) { if (this.down) {

View file

@ -3,16 +3,12 @@ package ch.fritteli.labyrinth;
import io.vavr.collection.Stream; import io.vavr.collection.Stream;
import io.vavr.control.Option; import io.vavr.control.Option;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
public class Tile { public class Tile {
// FIXME remove me; only for debugging
@Getter
final Walls walls = new Walls(); final Walls walls = new Walls();
@Getter
boolean visited = false; boolean visited = false;
public Tile() { public Tile() {

View file

@ -1,27 +1,32 @@
package ch.fritteli.labyrinth; package ch.fritteli.labyrinth;
import ch.fritteli.labyrinth.TextRenderer.CharDefinition;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
class TextRendererTest { class TextRendererTest {
@Test @Nested
void charDefTest() { class CharDefinitionTest {
assertEquals(" ", new TextRenderer.CharDefinition(false, false, false, false).toString()); @Test
assertEquals("", new TextRenderer.CharDefinition(false, false, false, true).toString()); void testRendering() {
assertEquals("", new TextRenderer.CharDefinition(false, false, true, false).toString()); assertEquals(" ", new CharDefinition(false, false, false, false).toString());
assertEquals("", new TextRenderer.CharDefinition(false, false, true, true).toString()); assertEquals("", new CharDefinition(false, false, false, true).toString());
assertEquals("", new TextRenderer.CharDefinition(false, true, false, false).toString()); assertEquals("", new CharDefinition(false, false, true, false).toString());
assertEquals("", new TextRenderer.CharDefinition(false, true, false, true).toString()); assertEquals("", new CharDefinition(false, false, true, true).toString());
assertEquals("", new TextRenderer.CharDefinition(false, true, true, false).toString()); assertEquals("", new CharDefinition(false, true, false, false).toString());
assertEquals("", new TextRenderer.CharDefinition(false, true, true, true).toString()); assertEquals("", new CharDefinition(false, true, false, true).toString());
assertEquals("", new TextRenderer.CharDefinition(true, false, false, false).toString()); assertEquals("", new CharDefinition(false, true, true, false).toString());
assertEquals("", new TextRenderer.CharDefinition(true, false, false, true).toString()); assertEquals("", new CharDefinition(false, true, true, true).toString());
assertEquals("", new TextRenderer.CharDefinition(true, false, true, false).toString()); assertEquals("", new CharDefinition(true, false, false, false).toString());
assertEquals("", new TextRenderer.CharDefinition(true, false, true, true).toString()); assertEquals("", new CharDefinition(true, false, false, true).toString());
assertEquals("", new TextRenderer.CharDefinition(true, true, false, false).toString()); assertEquals("", new CharDefinition(true, false, true, false).toString());
assertEquals("", new TextRenderer.CharDefinition(true, true, false, true).toString()); assertEquals("", new CharDefinition(true, false, true, true).toString());
assertEquals("", new TextRenderer.CharDefinition(true, true, true, false).toString()); assertEquals("", new CharDefinition(true, true, false, false).toString());
assertEquals("", new TextRenderer.CharDefinition(true, true, true, true).toString()); assertEquals("", new CharDefinition(true, true, false, true).toString());
assertEquals("", new CharDefinition(true, true, true, false).toString());
assertEquals("", new CharDefinition(true, true, true, true).toString());
}
} }
} }