Refactoring, more tests.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
ad0759b36f
commit
d6029471f0
7 changed files with 93 additions and 64 deletions
|
@ -7,26 +7,16 @@ import ch.fritteli.labyrinth.renderer.htmlfile.HTMLFileRenderer;
|
|||
import ch.fritteli.labyrinth.renderer.pdffile.PDFFileRenderer;
|
||||
import ch.fritteli.labyrinth.renderer.text.TextRenderer;
|
||||
import ch.fritteli.labyrinth.renderer.textfile.TextFileRenderer;
|
||||
import io.vavr.control.Try;
|
||||
import io.vavr.control.Option;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class Main {
|
||||
public static void main(@NonNull final String[] args) throws IOException {
|
||||
final String listenerPort = System.getProperty("fritteli.labyrinth.listenerport");
|
||||
if (listenerPort != null) {
|
||||
final Try<Integer> portTry = Try.of(() -> Integer.valueOf(listenerPort));
|
||||
if (portTry.isFailure()) {
|
||||
System.err.println("Invalid port specified via sysprop 'fritteli.labyrinth.listenerport': " + listenerPort + ". Not starting webserver.");
|
||||
} else {
|
||||
final TheListener listener = new TheListener(portTry.get());
|
||||
listener.start();
|
||||
System.out.println("Listening on port " + portTry.get());
|
||||
}
|
||||
} else {
|
||||
public static void main(@NonNull final String[] args) {
|
||||
final Option<TheListener> listener = TheListener.createListener();
|
||||
if (listener.isEmpty()) {
|
||||
System.out.println("In order to start the webserver, specify the port to listen to via the system property 'fritteli.labyrinth.listenerport', i.e.: -Dfritteli.labyrinth.listenerport=12345");
|
||||
int width = 100;
|
||||
int height = 100;
|
||||
|
|
|
@ -3,7 +3,6 @@ package ch.fritteli.labyrinth.model;
|
|||
import io.vavr.control.Option;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
|
@ -43,36 +42,26 @@ public class Labyrinth {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
public Tile getTileAt(@NonNull final Position position) {
|
||||
public Option<Tile> getTileAt(@NonNull final Position position) {
|
||||
return this.getTileAt(position.getX(), position.getY());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Tile getTileAtOrNull(@NonNull final Position position) {
|
||||
return this.getTileAtOrNull(position.getX(), position.getY());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Tile getTileAt(final int x, final int y) {
|
||||
return this.field[x][y];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Tile getTileAtOrNull(final int x, final int y) {
|
||||
public Option<Tile> getTileAt(final int x, final int y) {
|
||||
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
|
||||
return null;
|
||||
return Option.none();
|
||||
}
|
||||
return this.getTileAt(x, y);
|
||||
return Option.of(this.field[x][y]);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Tile getStartTile() {
|
||||
return this.getTileAt(this.start);
|
||||
return this.getTileAt(this.start).get();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Tile getEndTile() {
|
||||
return this.getTileAt(this.end);
|
||||
return this.getTileAt(this.end).get();
|
||||
}
|
||||
|
||||
private void initField() {
|
||||
|
@ -124,13 +113,13 @@ public class Labyrinth {
|
|||
private void dig() {
|
||||
while (!this.positions.isEmpty()) {
|
||||
final Position currentPosition = this.positions.peek();
|
||||
final Tile currentTile = Labyrinth.this.getTileAt(currentPosition);
|
||||
final Tile currentTile = Labyrinth.this.getTileAt(currentPosition).get();
|
||||
final Option<Direction> directionToDigTo = currentTile.getRandomAvailableDirection(Labyrinth.this.random);
|
||||
if (directionToDigTo.isDefined()) {
|
||||
final Direction digTo = directionToDigTo.get();
|
||||
final Direction digFrom = digTo.invert();
|
||||
final Position neighborPosition = currentPosition.move(digTo);
|
||||
final Tile neighborTile = Labyrinth.this.getTileAt(neighborPosition);
|
||||
final Tile neighborTile = Labyrinth.this.getTileAt(neighborPosition).get();
|
||||
if (currentTile.digTo(digTo) && neighborTile.digFrom(digFrom)) {
|
||||
// all ok!
|
||||
this.positions.push(neighborPosition);
|
||||
|
@ -149,7 +138,7 @@ public class Labyrinth {
|
|||
}
|
||||
|
||||
private void markSolution() {
|
||||
this.positions.forEach(position -> Labyrinth.this.getTileAt(position).setSolution());
|
||||
this.positions.forEach(position -> Labyrinth.this.getTileAt(position).get().setSolution());
|
||||
}
|
||||
|
||||
private void postDig() {
|
||||
|
|
|
@ -76,6 +76,21 @@ public class TheListener {
|
|||
});
|
||||
}
|
||||
|
||||
public static Option<TheListener> createListener() {
|
||||
final String listenerPort = System.getProperty("fritteli.labyrinth.listenerport");
|
||||
final Option<TheListener> listenerOption = Option.of(listenerPort)
|
||||
.toTry()
|
||||
.map(Integer::valueOf)
|
||||
.onFailure(cause -> System.err.println("Invalid port specified via system property 'fritteli.labyrinth.listenerport': "
|
||||
+ listenerPort
|
||||
+ ". Not starting webserver."))
|
||||
.mapTry(TheListener::new)
|
||||
.onFailure(cause -> System.err.println("Failed to create Listener: " + cause))
|
||||
.toOption();
|
||||
listenerOption.forEach(TheListener::start);
|
||||
return listenerOption;
|
||||
}
|
||||
|
||||
private <T> T getOrDefault(@NonNull final Option<String> input, @NonNull final Function<String, T> mapper, @Nullable final T defaultValue) {
|
||||
return input.toTry().map(mapper).getOrElse(defaultValue);
|
||||
}
|
||||
|
@ -111,11 +126,15 @@ public class TheListener {
|
|||
}
|
||||
|
||||
public void start() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "listener-stopper"));
|
||||
this.httpServer.start();
|
||||
System.out.println("Listening on " + this.httpServer.getAddress());
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.httpServer.stop(10);
|
||||
System.out.println("Stopping listener ...");
|
||||
this.httpServer.stop(5);
|
||||
System.out.println("Listener stopped.");
|
||||
}
|
||||
|
||||
private enum RequestParameter {
|
||||
|
|
|
@ -21,7 +21,7 @@ class Generator {
|
|||
String next() {
|
||||
StringBuilder sb = new StringBuilder("<tr>");
|
||||
for (int x = 0; x < this.labyrinth.getWidth(); x++) {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, this.y);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, this.y).get();
|
||||
sb.append("<td class=\"");
|
||||
sb.append(this.getClasses(currentTile).mkString(" "));
|
||||
sb.append("\"> </td>");
|
||||
|
|
|
@ -4,6 +4,7 @@ import ch.fritteli.labyrinth.model.Direction;
|
|||
import ch.fritteli.labyrinth.model.Labyrinth;
|
||||
import ch.fritteli.labyrinth.model.Position;
|
||||
import ch.fritteli.labyrinth.model.Tile;
|
||||
import io.vavr.control.Option;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
@ -74,7 +75,7 @@ class Generator {
|
|||
boolean isPainting = false;
|
||||
coordinate = coordinate.withY(y);
|
||||
for (int x = 0; x < this.labyrinth.getWidth(); x++) {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, y);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, y).get();
|
||||
coordinate = coordinate.withX(x);
|
||||
if (currentTile.hasWallAt(Direction.TOP)) {
|
||||
if (!isPainting) {
|
||||
|
@ -105,7 +106,7 @@ class Generator {
|
|||
int y = this.labyrinth.getHeight();
|
||||
coordinate = coordinate.withY(this.labyrinth.getHeight());
|
||||
for (int x = 0; x < this.labyrinth.getWidth(); x++) {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, y - 1);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, y - 1).get();
|
||||
coordinate = coordinate.withX(x);
|
||||
if (currentTile.hasWallAt(Direction.BOTTOM)) {
|
||||
if (!isPainting) {
|
||||
|
@ -140,7 +141,7 @@ class Generator {
|
|||
boolean isPainting = false;
|
||||
coordinate = coordinate.withX(x);
|
||||
for (int y = 0; y < this.labyrinth.getHeight(); y++) {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, y);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x, y).get();
|
||||
coordinate = coordinate.withY(y);
|
||||
if (currentTile.hasWallAt(Direction.LEFT)) {
|
||||
if (!isPainting) {
|
||||
|
@ -171,7 +172,7 @@ class Generator {
|
|||
int x = this.labyrinth.getWidth();
|
||||
coordinate = coordinate.withX(this.labyrinth.getWidth());
|
||||
for (int y = 0; y < this.labyrinth.getHeight(); y++) {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x - 1, y);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(x - 1, y).get();
|
||||
coordinate = coordinate.withY(y);
|
||||
if (currentTile.hasWallAt(Direction.RIGHT)) {
|
||||
if (!isPainting) {
|
||||
|
@ -220,15 +221,15 @@ class Generator {
|
|||
|
||||
@NonNull
|
||||
private Position findNextSolutionPosition(@Nullable final Position previousPosition, @NonNull final Position currentPosition) {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(currentPosition);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(currentPosition).get();
|
||||
for (final Direction direction : Direction.values()) {
|
||||
if (!currentTile.hasWallAt(direction)) {
|
||||
final Position position = currentPosition.move(direction);
|
||||
final Tile tileAtPosition = this.labyrinth.getTileAtOrNull(position);
|
||||
if (position.equals(previousPosition) || tileAtPosition == null) {
|
||||
final Option<Tile> tileAtPosition = this.labyrinth.getTileAt(position);
|
||||
if (position.equals(previousPosition)) {
|
||||
continue;
|
||||
}
|
||||
if (tileAtPosition.isSolution()) {
|
||||
if (tileAtPosition.map(Tile::isSolution).getOrElse(false)) {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ package ch.fritteli.labyrinth.renderer.text;
|
|||
import ch.fritteli.labyrinth.model.Direction;
|
||||
import ch.fritteli.labyrinth.model.Labyrinth;
|
||||
import ch.fritteli.labyrinth.model.Tile;
|
||||
import io.vavr.control.Option;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
class Generator {
|
||||
|
@ -22,11 +22,11 @@ class Generator {
|
|||
}
|
||||
|
||||
String next() {
|
||||
final Tile currentTile = this.labyrinth.getTileAt(this.x, this.y);
|
||||
final Tile topTile = this.labyrinth.getTileAtOrNull(this.x, this.y - 1);
|
||||
final Tile rightTile = this.labyrinth.getTileAtOrNull(this.x + 1, this.y);
|
||||
final Tile bottomTile = this.labyrinth.getTileAtOrNull(this.x, this.y + 1);
|
||||
final Tile leftTile = this.labyrinth.getTileAtOrNull(this.x - 1, this.y);
|
||||
final Tile currentTile = this.labyrinth.getTileAt(this.x, this.y).get();
|
||||
final Option<Tile> topTile = this.labyrinth.getTileAt(this.x, this.y - 1);
|
||||
final Option<Tile> rightTile = this.labyrinth.getTileAt(this.x + 1, this.y);
|
||||
final Option<Tile> bottomTile = this.labyrinth.getTileAt(this.x, this.y + 1);
|
||||
final Option<Tile> leftTile = this.labyrinth.getTileAt(this.x - 1, this.y);
|
||||
final String s;
|
||||
switch (this.line) {
|
||||
case 0:
|
||||
|
@ -69,7 +69,7 @@ class Generator {
|
|||
}
|
||||
}
|
||||
|
||||
private String renderTopLine(@NonNull final Tile currentTile, @Nullable final Tile leftTile, @Nullable final Tile topTile) {
|
||||
private String renderTopLine(@NonNull final Tile currentTile, @NonNull final Option<Tile> leftTile, @NonNull final Option<Tile> topTile) {
|
||||
final CharDefinition charDef1 = new CharDefinition();
|
||||
final CharDefinition charDef2 = new CharDefinition();
|
||||
final CharDefinition charDef3 = new CharDefinition();
|
||||
|
@ -82,7 +82,7 @@ class Generator {
|
|||
charDef2.horizontal();
|
||||
charDef3.left();
|
||||
} else {
|
||||
if (this.isSolution(currentTile) && (this.isSolution(topTile) || topTile == null)) {
|
||||
if (this.isSolution(currentTile) && (this.isSolution(topTile) || topTile.isEmpty())) {
|
||||
charDef2.solution().vertical();
|
||||
}
|
||||
}
|
||||
|
@ -106,10 +106,10 @@ class Generator {
|
|||
}
|
||||
|
||||
private String renderCenterLine(@NonNull final Tile currentTile,
|
||||
@Nullable final Tile topTile,
|
||||
@Nullable final Tile rightTile,
|
||||
@Nullable final Tile bottomTile,
|
||||
@Nullable final Tile leftTile) {
|
||||
@NonNull final Option<Tile> topTile,
|
||||
@NonNull final Option<Tile> rightTile,
|
||||
@NonNull final Option<Tile> bottomTile,
|
||||
@NonNull final Option<Tile> leftTile) {
|
||||
final CharDefinition charDef1 = new CharDefinition();
|
||||
final CharDefinition charDef2 = new CharDefinition();
|
||||
final CharDefinition charDef3 = new CharDefinition();
|
||||
|
@ -123,16 +123,16 @@ class Generator {
|
|||
}
|
||||
if (this.isSolution(currentTile)) {
|
||||
charDef2.solution();
|
||||
if (!currentTile.hasWallAt(Direction.LEFT) && (this.isSolution(leftTile) || leftTile == null)) {
|
||||
if (!currentTile.hasWallAt(Direction.LEFT) && (this.isSolution(leftTile) || leftTile.isEmpty())) {
|
||||
charDef2.left();
|
||||
}
|
||||
if (!currentTile.hasWallAt(Direction.TOP) && (this.isSolution(topTile) || topTile == null)) {
|
||||
if (!currentTile.hasWallAt(Direction.TOP) && (this.isSolution(topTile) || topTile.isEmpty())) {
|
||||
charDef2.up();
|
||||
}
|
||||
if (!currentTile.hasWallAt(Direction.RIGHT) && (this.isSolution(rightTile) || rightTile == null)) {
|
||||
if (!currentTile.hasWallAt(Direction.RIGHT) && (this.isSolution(rightTile) || rightTile.isEmpty())) {
|
||||
charDef2.right();
|
||||
}
|
||||
if (!currentTile.hasWallAt(Direction.BOTTOM) && (this.isSolution(bottomTile) || bottomTile == null)) {
|
||||
if (!currentTile.hasWallAt(Direction.BOTTOM) && (this.isSolution(bottomTile) || bottomTile.isEmpty())) {
|
||||
charDef2.down();
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ class Generator {
|
|||
return result;
|
||||
}
|
||||
|
||||
private String renderBottomLine(@NonNull final Tile currentTile, @Nullable final Tile leftTile) {
|
||||
private String renderBottomLine(@NonNull final Tile currentTile, @NonNull final Option<Tile> leftTile) {
|
||||
String result;
|
||||
final CharDefinition charDef1 = new CharDefinition();
|
||||
final CharDefinition charDef2 = new CharDefinition();
|
||||
|
@ -186,11 +186,15 @@ class Generator {
|
|||
return result;
|
||||
}
|
||||
|
||||
private boolean hasWallAt(@Nullable final Tile tile, @NonNull final Direction direction) {
|
||||
return tile != null && tile.hasWallAt(direction);
|
||||
private boolean hasWallAt(@NonNull final Option<Tile> tile, @NonNull final Direction direction) {
|
||||
return tile.map(t -> t.hasWallAt(direction)).getOrElse(false);
|
||||
}
|
||||
|
||||
private boolean isSolution(@Nullable final Tile tile) {
|
||||
private boolean isSolution(@NonNull final Tile tile) {
|
||||
return this.renderSolution && tile != null && tile.isSolution();
|
||||
}
|
||||
|
||||
private boolean isSolution(@NonNull final Option<Tile> tile) {
|
||||
return this.renderSolution && tile.map(Tile::isSolution).getOrElse(false);
|
||||
}
|
||||
}
|
||||
|
|
26
src/test/java/ch/fritteli/labyrinth/model/LabyrinthTest.java
Normal file
26
src/test/java/ch/fritteli/labyrinth/model/LabyrinthTest.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package ch.fritteli.labyrinth.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class LabyrinthTest {
|
||||
@Test
|
||||
void testConstruct() {
|
||||
// act / assert on simple cases
|
||||
assertThrows(IllegalArgumentException.class, () -> new Labyrinth(0, 0));
|
||||
assertThrows(IllegalArgumentException.class, () -> new Labyrinth(0, 0, 0));
|
||||
|
||||
// now for the real work:
|
||||
// arrange
|
||||
final Labyrinth sut = new Labyrinth(2, 3, 5);
|
||||
|
||||
// assert
|
||||
assertEquals(2, sut.getWidth());
|
||||
assertEquals(3, sut.getHeight());
|
||||
assertEquals(5, sut.getRandomSeed());
|
||||
assertEquals(new Position(0, 0), sut.getStart());
|
||||
assertEquals(new Position(1, 2), sut.getEnd());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue