diff --git a/pom.xml b/pom.xml
index dcdec02..54216db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,11 @@
io.vavr
vavr
+
+ com.google.guava
+ guava
+ 33.2.1-jre
+
org.apache.pdfbox
pdfbox
diff --git a/src/main/java/ch/fritteli/maze/generator/algorithm/Wilson.java b/src/main/java/ch/fritteli/maze/generator/algorithm/Wilson.java
deleted file mode 100644
index af55d7e..0000000
--- a/src/main/java/ch/fritteli/maze/generator/algorithm/Wilson.java
+++ /dev/null
@@ -1,312 +0,0 @@
-package ch.fritteli.maze.generator.algorithm;
-
-import ch.fritteli.maze.generator.model.Direction;
-import ch.fritteli.maze.generator.model.Maze;
-import ch.fritteli.maze.generator.model.Position;
-import ch.fritteli.maze.generator.model.Tile;
-import io.vavr.Tuple2;
-import io.vavr.collection.Iterator;
-import io.vavr.collection.Seq;
-import io.vavr.collection.Stream;
-import io.vavr.collection.Vector;
-import io.vavr.control.Option;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * An implementation of Wilson's Algorithm.
- */
-public class Wilson extends AbstractMazeGeneratorAlgorithm {
- public Wilson(@NotNull final Maze maze) {
- super(maze, "Wilson");
- }
-
- @Override
- public void run() {
- final MyMaze myMaze = new MyMaze(this.maze.getWidth(), this.maze.getHeight());
- // 1. Initialization: pick random location, add to maze
- final Position position = myMaze.getRandomAvailablePosition(this.random).get();
- myMaze.setPartOfMaze(position);
-
- // 2. while locations-not-in-maze exist, repeat:
-
- final List pths = new ArrayList<>();
- Position startPosition;
- while ((startPosition = myMaze.getRandomAvailablePosition(this.random).getOrNull()) != null) {
- final MyMaze.Path path = myMaze.createPath(startPosition);
- while (true) {
- final Position nextPosition = path.nextRandomPosition(this.random);
- if (path.contains(nextPosition)) {
- path.removeLoopUpTo(nextPosition);
- } else {
- path.append(nextPosition);
- if (myMaze.isPartOfMaze(nextPosition)) {
- myMaze.setPartOfMaze(path);
- pths.add(path);
- break;
- }
- }
- }
-
- }
-
- applyToMaze(pths, maze);
- solve(maze);
- // 1. pick random location not in maze
- // 2. perform random walk until you reach the maze (*)
- // 3. add path to maze
- // (*): random walk:
- // 1. advance in random direction
- // 2. if loop with current path is formed, remove loop, continue from last location before loop
- }
-
- private void applyToMaze(@NotNull final List pths, @NotNull final Maze maze) {
- pths.forEach(path -> {
- final Iterator moves = Stream.ofAll(path.path)
- .sliding(2)
- .flatMap(poss -> poss.head().getDirectionTo(poss.get(1)));
- Position position = path.path.getFirst();
- while (moves.hasNext()) {
- Tile tile = maze.getTileAt(position).get();
- final Direction move = moves.next();
- tile.digTo(move);
- position = position.move(move);
- maze.getTileAt(position).forEach(t -> t.digTo(move.invert()));
- }
- });
- Direction direction = determineDirectionForDigging(maze.getStart());
- Tile t = maze.getStartTile();
- this.digTo(t, direction);
- direction = determineDirectionForDigging(maze.getEnd());
- t = maze.getEndTile();
- this.digTo(t, direction);
- // seal all walls, mark all as visited
- for (int x = 0; x < maze.getWidth(); x++) {
- for (int y = 0; y < maze.getHeight(); y++) {
- maze.getTileAt(x, y).forEach(tile -> {
- Stream.of(Direction.values())
- .forEach(d -> {
- if (tile.hasWallAt(d)) {
- tile.preventDiggingToOrFrom(d);
- } else {
- tile.digFrom(d);
- }
- });
- });
- }
- }
- }
-
- @Nullable
- private Direction determineDirectionForDigging(@NotNull final Position position) {
- if (position.y() == 0) {
- return Direction.TOP;
- }
- if (position.x() == 0) {
- return Direction.LEFT;
- }
- if (position.y() == this.maze.getHeight() - 1) {
- return Direction.BOTTOM;
- }
- if (position.x() == this.maze.getWidth() - 1) {
- return Direction.RIGHT;
- }
- return null;
- }
-
- private void digTo(@NotNull final Tile tile, @NotNull final Direction direction) {
- tile.enableDiggingToOrFrom(direction);
- tile.digTo(direction);
- }
-
- private void solve(@NotNull final Maze maze) {
- EnumSet[][] remainingDirs = new EnumSet[maze.getWidth()][maze.getHeight()];
- for (int x = 0; x < remainingDirs.length; x++) {
- for (int y = 0; y < remainingDirs[x].length; y++) {
- remainingDirs[x][y] = EnumSet.allOf(Direction.class);
- }
- }
- Position p = maze.getStart();
- final Direction direction = this.determineDirectionForDigging(p);
- remainingDirs[p.x()][p.y()].remove(direction);
- LinkedList solution = new LinkedList<>();
- solution.add(p);
- while (!p.equals(maze.getEnd())) {
- final Tile tile = maze.getTileAt(p).get();
- EnumSet dirs = remainingDirs[p.x()][p.y()];
- dirs.removeIf(tile::hasWallAt);
- if (dirs.isEmpty()) {
- solution.pop();
- p = solution.peek();
- } else {
- final Direction nextDir = dirs.iterator().next();
- final Position nextPos = p.move(nextDir);
- solution.push(nextPos);
- remainingDirs[p.x()][p.y()].remove(nextDir);
- remainingDirs[nextPos.x()][nextPos.y()].remove(nextDir.invert());
- p = nextPos;
- }
- }
- solution.forEach(s -> maze.getTileAt(s).forEach(Tile::setSolution));
- }
-
- private static class MyMaze {
- private final int width;
- private final int height;
- private final boolean[][] partOfMaze;
- private final boolean[] completeColumns;
-
- MyMaze(final int width, final int height) {
- this.width = width;
- this.height = height;
- this.partOfMaze = new boolean[this.width][this.height];
- for (int x = 0; x < this.width; x++) {
- this.partOfMaze[x] = new boolean[this.height];
- }
- this.completeColumns = new boolean[this.width];
- }
-
- boolean isPartOfMaze(final int x, final int y) {
- return this.partOfMaze[x][y];
- }
-
- boolean isPartOfMaze(@NotNull final Position position) {
- return this.isPartOfMaze(position.x(), position.y());
- }
-
- void setPartOfMaze(final int x, final int y) {
- this.partOfMaze[x][y] = true;
- this.checkCompleteColumn(x);
- }
-
- void setPartOfMaze(@NotNull final Position position) {
- this.setPartOfMaze(position.x(), position.y());
- }
-
- void setPartOfMaze(@NotNull final Path path) {
- path.path.forEach(this::setPartOfMaze);
- }
-
- void checkCompleteColumn(final int x) {
- if (this.completeColumns[x]) {
- return;
- }
- for (int y = 0; y < this.height; y++) {
- if (!this.isPartOfMaze(x, y)) {
- return;
- }
- }
- this.completeColumns[x] = true;
- }
-
- Option getRandomAvailablePosition(@NotNull final Random random) {
- final Seq allowedColumns = Vector.ofAll(this.completeColumns)
- .zipWithIndex()
- .reject(Tuple2::_1)
- .map(Tuple2::_2);
- if (allowedColumns.isEmpty()) {
- return Option.none();
- }
- final int x = allowedColumns.get(random.nextInt(allowedColumns.size()));
- final boolean[] column = partOfMaze[x];
-
- final Seq allowedRows = Vector.ofAll(column)
- .zipWithIndex()
- .reject(Tuple2::_1)
- .map(Tuple2::_2);
- if (allowedRows.isEmpty()) {
- return Option.none();
- }
- final int y = allowedRows.get(random.nextInt(allowedRows.size()));
- return Option.some(new Position(x, y));
- }
-
- public Path createPath(@NotNull final Position position) {
- return new Path(position);
- }
-
- private class Path {
- @NotNull
- private final List path = new LinkedList<>();
-
- Path(@NotNull final Position position) {
- this.path.add(position);
- }
-
- @NotNull
- Position nextRandomPosition(@NotNull final Random random) {
- final Direction direction = this.getRandomDirectionFromLastPosition(random);
- return this.path.getLast().move(direction);
- }
-
- boolean contains(@NotNull final Position position) {
- return this.path.contains(position);
- }
-
- void removeLoopUpTo(@NotNull final Position position) {
- while (!this.path.removeLast().equals(position)) {
- }
- this.path.add(position);
- }
-
- public void append(@NotNull final Position nextPosition) {
- this.path.add(nextPosition);
- }
-
- @NotNull
- private Direction getRandomDirectionFromLastPosition(@NotNull final Random random) {
- final EnumSet validDirections = this.getValidDirectionsFromLastPosition();
- if (validDirections.isEmpty()) {
- throw new IllegalStateException("WE MUST NOT GET HERE! analyze why it happened!!!");
- }
- if (validDirections.size() == 1) {
- return validDirections.iterator().next();
- }
- final Direction[] directionArray = validDirections.toArray(Direction[]::new);
- final int index = random.nextInt(directionArray.length);
- return directionArray[index];
- }
-
- @NotNull
- private EnumSet getValidDirectionsFromLastPosition() {
- final Position fromPosition = this.path.getLast();
- final EnumSet validDirections = EnumSet.allOf(Direction.class);
- if (this.path.size() > 1) {
- final Position prevP = this.path.get(this.path.size() - 2);
- fromPosition.getDirectionTo(prevP)
- .forEach(validDirections::remove);
- }
- boolean canLeft = fromPosition.x() > 0;
- boolean canRight = fromPosition.x() < width - 1;
- boolean canUp = fromPosition.y() > 0;
- boolean canDown = fromPosition.y() < height - 1;
- if (!canLeft) {
- validDirections.remove(Direction.LEFT);
- }
- if (!canRight) {
- validDirections.remove(Direction.RIGHT);
- }
- if (!canUp) {
- validDirections.remove(Direction.TOP);
- }
- if (!canDown) {
- validDirections.remove(Direction.BOTTOM);
- }
- return validDirections;
- }
-
- @Override
- public String toString() {
- return Stream.ofAll(this.path)
- .map(position -> "(%s,%s)".formatted(position.x(), position.y()))
- .mkString("Path[", "->", "]");
- }
- }
- }
-}
diff --git a/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/MazeSolver.java b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/MazeSolver.java
new file mode 100644
index 0000000..f84a20c
--- /dev/null
+++ b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/MazeSolver.java
@@ -0,0 +1,62 @@
+package ch.fritteli.maze.generator.algorithm.wilson;
+
+import ch.fritteli.maze.generator.model.Direction;
+import ch.fritteli.maze.generator.model.Maze;
+import ch.fritteli.maze.generator.model.Position;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+import java.util.stream.Collectors;
+
+public class MazeSolver {
+ @NotNull
+ private final Maze maze;
+
+ MazeSolver(@NotNull final Maze maze) {
+ this.maze = maze;
+ }
+
+ void solve() {
+ final Direction directionToOuterWall = Wilson.getDirectionToOuterWall(
+ this.maze.getStart(),
+ this.maze.getWidth(),
+ this.maze.getHeight()
+ );
+
+ final List solution = this.getSolution(this.maze.getStart(), directionToOuterWall);
+ for (Position position : solution) {
+ this.maze.getTileAt(position).get().setSolution();
+ }
+ }
+
+ private List getSolution(@NotNull Position position,
+ @NotNull Direction forbidden) {
+ record PathElement(@NotNull Position position,
+ @NotNull EnumSet possibleDirections) {
+ }
+ final Stack solution = new Stack<>();
+ final EnumSet directions = this.maze.getTileAt(position).get().getOpenDirections();
+ directions.remove(forbidden);
+ PathElement head = new PathElement(position, directions);
+ solution.push(head);
+ while (!head.position.equals(this.maze.getEnd())) {
+ if (head.possibleDirections.isEmpty()) {
+ solution.pop();
+ head = solution.peek();
+ } else {
+ final Iterator iterator = head.possibleDirections.iterator();
+ final Direction direction = iterator.next();
+ iterator.remove();
+ final Position next = head.position.move(direction);
+ final EnumSet openDirections = this.maze.getTileAt(next).get().getOpenDirections();
+ openDirections.remove(direction.invert());
+ head = new PathElement(next, openDirections);
+ solution.push(head);
+ }
+ }
+ return solution.stream().map(PathElement::position).collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/Path.java b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/Path.java
new file mode 100644
index 0000000..ab18ec2
--- /dev/null
+++ b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/Path.java
@@ -0,0 +1,91 @@
+package ch.fritteli.maze.generator.algorithm.wilson;
+
+import ch.fritteli.maze.generator.model.Direction;
+import ch.fritteli.maze.generator.model.Position;
+import io.vavr.collection.List;
+import io.vavr.collection.Stream;
+import io.vavr.collection.Traversable;
+import io.vavr.control.Option;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+class Path {
+ private final int width;
+ private final int height;
+ @NotNull
+ private List positions;
+
+ Path(@NotNull final Position start, int width, int height) {
+ this.positions = List.of(start);
+ this.width = width;
+ this.height = height;
+ }
+
+ @NotNull
+ Position growRandom(@NotNull final Random random) {
+ final Position position = this.nextRandomPosition(random);
+ if (this.contains(position)) {
+ this.removeLoopUpTo(position);
+ return this.growRandom(random);
+ }
+ this.positions = this.positions.prepend(position);
+ return position;
+ }
+
+ @NotNull
+ List getPositions() {
+ return this.positions;
+ }
+
+ @NotNull
+ Position getStart() {
+ return this.positions.last();
+ }
+
+ @NotNull
+ Traversable getMovesFromStart() {
+ return this.positions.reverse().sliding(2)
+ .flatMap(positions1 -> Option.when(
+ positions1.size() == 2,
+ // DEV-NOTE: .get() is safe here, because in the context of a path, there MUST be a direction
+ // from one position to the next.
+ () -> positions1.head().getDirectionTo(positions1.last()).get()
+ ));
+ }
+
+ @NotNull
+ private Position nextRandomPosition(@NotNull final Random random) {
+ final Direction randomDirection = this.getRandomDirection(random);
+ final Position nextPosition = this.positions.head().move(randomDirection);
+ if (this.isWithinBounds(nextPosition) && !nextPosition.equals(this.positions.head())) {
+ return nextPosition;
+ }
+ return this.nextRandomPosition(random);
+ }
+
+ private boolean isWithinBounds(@NotNull final Position position) {
+ return position.x() >= 0 && position.x() < this.width && position.y() >= 0 && position.y() < this.height;
+ }
+
+ private boolean contains(@NotNull final Position position) {
+ return this.positions.contains(position);
+ }
+
+ private void removeLoopUpTo(@NotNull final Position position) {
+ this.positions = this.positions.dropUntil(position::equals);
+ }
+
+ @NotNull
+ private Direction getRandomDirection(@NotNull final Random random) {
+ final Direction[] array = Direction.values();
+ return array[random.nextInt(array.length)];
+ }
+
+ @Override
+ public String toString() {
+ return Stream.ofAll(this.positions)
+ .map(position -> "(%s,%s)".formatted(position.x(), position.y()))
+ .mkString("Path[", "->", "]");
+ }
+}
diff --git a/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/PathsBuilder.java b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/PathsBuilder.java
new file mode 100644
index 0000000..098ed81
--- /dev/null
+++ b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/PathsBuilder.java
@@ -0,0 +1,131 @@
+package ch.fritteli.maze.generator.algorithm.wilson;
+
+import ch.fritteli.maze.generator.model.Maze;
+import ch.fritteli.maze.generator.model.Position;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import io.vavr.Tuple;
+import io.vavr.collection.Stream;
+import io.vavr.collection.Traversable;
+import io.vavr.control.Option;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Random;
+
+/**
+ * This class will build paths such that in the end all fields of the maze are covered by exactly one path.
+ */
+class PathsBuilder {
+ private final int width;
+ private final int height;
+ @NotNull
+ private final Random random;
+ @NotNull
+ private final Multimap availablePositions;
+
+ PathsBuilder(@NotNull final Maze maze,
+ @NotNull final Random random) {
+ this.width = maze.getWidth();
+ this.height = maze.getHeight();
+ this.random = random;
+ this.availablePositions = HashMultimap.create(this.width, this.height);
+
+ // Initialize the available positions.
+ for (int x = 0; x < this.width; x++) {
+ for (int y = 0; y < this.height; y++) {
+ this.availablePositions.put(x, y);
+ }
+ }
+ }
+
+ /**
+ * Create all the paths such that the maze will be completely filled and every field of it will be covered by
+ * exactly one path.
+ *
+ * @return A {@link Traversable} of generated {@link Path Paths}.
+ */
+ @NotNull
+ Traversable buildPaths() {
+ this.initializeWithRandomStartingPosition();
+
+ return Stream.unfoldLeft(
+ this,
+ builder -> builder.buildPath()
+ .map(path -> {
+ builder.setPartOfMaze(path);
+ return Tuple.of(builder, path);
+ })
+ );
+ }
+
+ private void initializeWithRandomStartingPosition() {
+ this.popRandomPosition();
+ }
+
+ /**
+ * Creates one new path, if possible. If the maze is already filled, {@link io.vavr.control.Option.None} is
+ * returned.
+ *
+ * @return An {@link Option} of a new {@link Path} instance.
+ */
+ @NotNull
+ private Option buildPath() {
+ return this.initializeNewPath()
+ .map(this::growPath);
+ }
+
+ @NotNull
+ private Option initializeNewPath() {
+ return this.popRandomPosition()
+ .map(position -> new Path(position, this.width, this.height));
+ }
+
+ /**
+ * Randomly grow the {@code path} until it reaches a field that is part of the maze and return it. The resulting
+ * path will contain no loops.
+ *
+ * @param path The {@link Path} to grow.
+ * @return The final {@link Path} that reaches the maze.
+ */
+ @NotNull
+ private Path growPath(@NotNull final Path path) {
+ Position lastPosition;
+ do {
+ lastPosition = path.growRandom(this.random);
+ } while (this.isNotPartOfMaze(lastPosition));
+ return path;
+ }
+
+ private boolean isNotPartOfMaze(@NotNull final Position position) {
+ return this.availablePositions.containsEntry(position.x(), position.y());
+ }
+
+ private void setPartOfMaze(@NotNull final Position position) {
+ this.availablePositions.remove(position.x(), position.y());
+ }
+
+ private void setPartOfMaze(@NotNull final Path path) {
+ path.getPositions().forEach(this::setPartOfMaze);
+ }
+
+ /**
+ * Finds a random {@link Position}, that is not yet part of the maze, marks it as being part of the maze and returns
+ * it. If no position is available, {@link io.vavr.control.Option.None} is returned.
+ *
+ * @return An available position or {@link io.vavr.control.Option.None}.
+ */
+ @NotNull
+ private Option popRandomPosition() {
+ if (this.availablePositions.isEmpty()) {
+ return Option.none();
+ }
+
+ final Integer[] keys = this.availablePositions.keySet().toArray(Integer[]::new);
+ final int key = keys[this.random.nextInt(keys.length)];
+ final Integer[] values = this.availablePositions.get(key).toArray(Integer[]::new);
+ final int value = values[this.random.nextInt(values.length)];
+
+ this.availablePositions.remove(key, value);
+ return Option.some(new Position(key, value));
+ }
+}
diff --git a/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/Wilson.java b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/Wilson.java
new file mode 100644
index 0000000..1587e6e
--- /dev/null
+++ b/src/main/java/ch/fritteli/maze/generator/algorithm/wilson/Wilson.java
@@ -0,0 +1,96 @@
+package ch.fritteli.maze.generator.algorithm.wilson;
+
+import ch.fritteli.maze.generator.algorithm.AbstractMazeGeneratorAlgorithm;
+import ch.fritteli.maze.generator.model.Direction;
+import ch.fritteli.maze.generator.model.Maze;
+import ch.fritteli.maze.generator.model.Position;
+import ch.fritteli.maze.generator.model.Tile;
+import io.vavr.collection.Traversable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * An implementation of Wilson's Algorithm.
+ * In short:
+ *
+ * - Pick random location, add to maze
+ * - While locations that are not part of the maze exist, loop:
+ *
+ * - Pick random location that's not part of the maze
+ * - Randomly walk from this location, until ...
+ *
+ * - ... either you hit the current path, forming a loop. Then remove the entire loop and continue
+ * walking.
+ * - ... or you hit a position that is part of the maze. Then add the path to the maze and start the next
+ * walk.
+ *
+ *
+ *
+ */
+public class Wilson extends AbstractMazeGeneratorAlgorithm {
+
+ public Wilson(@NotNull final Maze maze) {
+ super(maze, "Wilson");
+ }
+
+ @Nullable
+ static Direction getDirectionToOuterWall(@NotNull final Position position,
+ final int width,
+ final int height) {
+ if (position.y() == 0) {
+ return Direction.TOP;
+ }
+ if (position.y() == height - 1) {
+ return Direction.BOTTOM;
+ }
+ if (position.x() == 0) {
+ return Direction.LEFT;
+ }
+ if (position.x() == width - 1) {
+ return Direction.RIGHT;
+ }
+ return null;
+ }
+
+ @Override
+ public void run() {
+ final Traversable paths = new PathsBuilder(this.maze, this.random)
+ .buildPaths();
+
+ this.applyPathsToMaze(paths);
+ }
+
+ private void applyPathsToMaze(@NotNull final Traversable paths) {
+ this.openStartAndEndWalls();
+ paths.forEach(path -> path.getMovesFromStart()
+ .foldLeft(
+ path.getStart(),
+ (position, direction) -> {
+ this.maze.getTileAt(position).get()
+ .digTo(direction);
+ final Position next = position.move(direction);
+ this.maze.getTileAt(next).get()
+ .digTo(direction.invert());
+ return next;
+ }));
+
+ final MazeSolver solver = new MazeSolver(this.maze);
+ solver.solve();
+ }
+
+ private void openStartAndEndWalls() {
+ this.openWall(this.maze.getStart(), this.maze.getStartTile());
+ this.openWall(this.maze.getEnd(), this.maze.getEndTile());
+ }
+
+ private void openWall(@NotNull final Position position, @NotNull final Tile tile) {
+ final Direction direction = this.getDirectionToOuterWall(position);
+ tile.enableDiggingToOrFrom(direction);
+ tile.digTo(direction);
+ }
+
+ @Nullable
+ private Direction getDirectionToOuterWall(@NotNull final Position position) {
+ return getDirectionToOuterWall(position, this.maze.getWidth(), this.maze.getHeight());
+ }
+}
diff --git a/src/main/java/ch/fritteli/maze/generator/model/Tile.java b/src/main/java/ch/fritteli/maze/generator/model/Tile.java
index c18ef5d..b4428f1 100644
--- a/src/main/java/ch/fritteli/maze/generator/model/Tile.java
+++ b/src/main/java/ch/fritteli/maze/generator/model/Tile.java
@@ -1,6 +1,6 @@
package ch.fritteli.maze.generator.model;
-import io.vavr.collection.Stream;
+import io.vavr.collection.Vector;
import io.vavr.control.Option;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
@@ -17,6 +17,7 @@ import java.util.Random;
@ToString
public class Tile {
final Walls walls = new Walls();
+ @EqualsAndHashCode.Exclude
boolean visited = false;
@Getter
boolean solution = false;
@@ -65,13 +66,23 @@ public class Tile {
this.walls.set(direction);
}
+ @NotNull
+ public EnumSet getOpenDirections() {
+ return this.walls.getOpen();
+ }
+
+ @NotNull
public Option getRandomAvailableDirection(@NotNull final Random random) {
- final Stream availableDirections = this.walls.getUnsealedSet();
+ final EnumSet availableDirections = this.walls.getUnsealedSet();
if (availableDirections.isEmpty()) {
return Option.none();
}
- final int index = random.nextInt(availableDirections.length());
- return Option.of(availableDirections.get(index));
+ if (availableDirections.size() == 1) {
+ return Option.some(availableDirections.iterator().next());
+ }
+ final Vector directions = Vector.ofAll(availableDirections);
+ final int index = random.nextInt(directions.size());
+ return Option.of(directions.get(index));
}
public boolean hasWallAt(@NotNull final Direction direction) {
diff --git a/src/main/java/ch/fritteli/maze/generator/model/Walls.java b/src/main/java/ch/fritteli/maze/generator/model/Walls.java
index 8a4b340..4a899c7 100644
--- a/src/main/java/ch/fritteli/maze/generator/model/Walls.java
+++ b/src/main/java/ch/fritteli/maze/generator/model/Walls.java
@@ -1,21 +1,17 @@
package ch.fritteli.maze.generator.model;
-import io.vavr.collection.Stream;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
@EqualsAndHashCode
@ToString
public class Walls {
- private final SortedSet directions = new TreeSet<>();
- private final Set sealed = new HashSet<>();
+ private final EnumSet directions = EnumSet.noneOf(Direction.class);
+ @EqualsAndHashCode.Exclude
+ private final EnumSet sealed = EnumSet.noneOf(Direction.class);
public void set(@NotNull final Direction direction) {
this.directions.add(direction);
@@ -36,9 +32,11 @@ public class Walls {
return this.directions.contains(direction);
}
- public Stream getUnsealedSet() {
- return Stream.ofAll(this.directions)
- .removeAll(this.sealed);
+ @NotNull
+ public EnumSet getUnsealedSet() {
+ final EnumSet result = EnumSet.copyOf(this.directions);
+ result.removeAll(this.sealed);
+ return result;
}
public void seal(@NotNull final Direction direction) {
@@ -51,4 +49,9 @@ public class Walls {
public void unseal(@NotNull final Direction direction) {
this.sealed.remove(direction);
}
+
+ @NotNull
+ public EnumSet getOpen() {
+ return EnumSet.complementOf(this.directions);
+ }
}
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/MazeConstants.java b/src/main/java/ch/fritteli/maze/generator/serialization/MazeConstants.java
new file mode 100644
index 0000000..4b9c200
--- /dev/null
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/MazeConstants.java
@@ -0,0 +1,9 @@
+package ch.fritteli.maze.generator.serialization;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class MazeConstants {
+ public final byte MAGIC_BYTE_1 = 0x1a;
+ public final byte MAGIC_BYTE_2 = (byte) 0xb1;
+}
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeInputStreamV1.java b/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeInputStreamV1.java
index 5ec5c7c..2532787 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeInputStreamV1.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeInputStreamV1.java
@@ -4,6 +4,7 @@ import ch.fritteli.maze.generator.model.Maze;
import ch.fritteli.maze.generator.model.Tile;
import ch.fritteli.maze.generator.serialization.AbstractMazeInputStream;
import ch.fritteli.maze.generator.serialization.CommonTileHandler;
+import ch.fritteli.maze.generator.serialization.MazeConstants;
import org.jetbrains.annotations.NotNull;
public class MazeInputStreamV1 extends AbstractMazeInputStream {
@@ -18,11 +19,11 @@ public class MazeInputStreamV1 extends AbstractMazeInputStream {
// 01 0xb1 magic
// 02 0x01 version
final byte magic1 = this.readByte();
- if (magic1 != SerializerDeserializerV1.MAGIC_BYTE_1) {
+ if (magic1 != MazeConstants.MAGIC_BYTE_1) {
throw new IllegalArgumentException("Invalid maze data.");
}
final byte magic2 = this.readByte();
- if (magic2 != SerializerDeserializerV1.MAGIC_BYTE_2) {
+ if (magic2 != MazeConstants.MAGIC_BYTE_2) {
throw new IllegalArgumentException("Invalid maze data.");
}
final int version = this.readByte();
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeOutputStreamV1.java b/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeOutputStreamV1.java
index aa8d3c2..7085b04 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeOutputStreamV1.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v1/MazeOutputStreamV1.java
@@ -4,6 +4,7 @@ import ch.fritteli.maze.generator.model.Maze;
import ch.fritteli.maze.generator.model.Tile;
import ch.fritteli.maze.generator.serialization.AbstractMazeOutputStream;
import ch.fritteli.maze.generator.serialization.CommonTileHandler;
+import ch.fritteli.maze.generator.serialization.MazeConstants;
import org.jetbrains.annotations.NotNull;
public class MazeOutputStreamV1 extends AbstractMazeOutputStream {
@@ -13,8 +14,8 @@ public class MazeOutputStreamV1 extends AbstractMazeOutputStream {
// 00 0x1a magic
// 01 0xb1 magic
// 02 0x02 version
- this.writeByte(SerializerDeserializerV1.MAGIC_BYTE_1);
- this.writeByte(SerializerDeserializerV1.MAGIC_BYTE_2);
+ this.writeByte(MazeConstants.MAGIC_BYTE_1);
+ this.writeByte(MazeConstants.MAGIC_BYTE_2);
this.writeByte(SerializerDeserializerV1.VERSION_BYTE);
}
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v1/SerializerDeserializerV1.java b/src/main/java/ch/fritteli/maze/generator/serialization/v1/SerializerDeserializerV1.java
index f9f02d9..9f4a561 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v1/SerializerDeserializerV1.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v1/SerializerDeserializerV1.java
@@ -24,9 +24,7 @@ import java.lang.reflect.InvocationTargetException;
*/
@UtilityClass
public class SerializerDeserializerV1 {
- final byte MAGIC_BYTE_1 = 0x1a;
- final byte MAGIC_BYTE_2 = (byte) 0xb1;
- final byte VERSION_BYTE = 0x01;
+ public final byte VERSION_BYTE = 0x01;
/**
* Serializes the {@code maze} into a byte array.
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeInputStreamV2.java b/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeInputStreamV2.java
index bbe42b1..036d636 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeInputStreamV2.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeInputStreamV2.java
@@ -5,6 +5,7 @@ import ch.fritteli.maze.generator.model.Position;
import ch.fritteli.maze.generator.model.Tile;
import ch.fritteli.maze.generator.serialization.AbstractMazeInputStream;
import ch.fritteli.maze.generator.serialization.CommonTileHandler;
+import ch.fritteli.maze.generator.serialization.MazeConstants;
import org.jetbrains.annotations.NotNull;
public class MazeInputStreamV2 extends AbstractMazeInputStream {
@@ -19,11 +20,11 @@ public class MazeInputStreamV2 extends AbstractMazeInputStream {
// 01 0xb1 magic
// 02 0x02 version
final byte magic1 = this.readByte();
- if (magic1 != SerializerDeserializerV2.MAGIC_BYTE_1) {
+ if (magic1 != MazeConstants.MAGIC_BYTE_1) {
throw new IllegalArgumentException("Invalid maze data.");
}
final byte magic2 = this.readByte();
- if (magic2 != SerializerDeserializerV2.MAGIC_BYTE_2) {
+ if (magic2 != MazeConstants.MAGIC_BYTE_2) {
throw new IllegalArgumentException("Invalid maze data.");
}
final int version = this.readByte();
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeOutputStreamV2.java b/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeOutputStreamV2.java
index c39ad3d..1cb8f78 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeOutputStreamV2.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v2/MazeOutputStreamV2.java
@@ -5,6 +5,7 @@ import ch.fritteli.maze.generator.model.Position;
import ch.fritteli.maze.generator.model.Tile;
import ch.fritteli.maze.generator.serialization.AbstractMazeOutputStream;
import ch.fritteli.maze.generator.serialization.CommonTileHandler;
+import ch.fritteli.maze.generator.serialization.MazeConstants;
import org.jetbrains.annotations.NotNull;
public class MazeOutputStreamV2 extends AbstractMazeOutputStream {
@@ -14,8 +15,8 @@ public class MazeOutputStreamV2 extends AbstractMazeOutputStream {
// 00 0x1a magic
// 01 0xb1 magic
// 02 0x02 version
- this.writeByte(SerializerDeserializerV2.MAGIC_BYTE_1);
- this.writeByte(SerializerDeserializerV2.MAGIC_BYTE_2);
+ this.writeByte(MazeConstants.MAGIC_BYTE_1);
+ this.writeByte(MazeConstants.MAGIC_BYTE_2);
this.writeByte(SerializerDeserializerV2.VERSION_BYTE);
}
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2.java b/src/main/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2.java
index 5b7753e..99f8e22 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2.java
@@ -29,10 +29,7 @@ import java.lang.reflect.InvocationTargetException;
*/
@UtilityClass
public class SerializerDeserializerV2 {
-
- final byte MAGIC_BYTE_1 = 0x1a;
- final byte MAGIC_BYTE_2 = (byte) 0xb1;
- final byte VERSION_BYTE = 0x02;
+ public final byte VERSION_BYTE = 0x02;
/**
* Serializes the {@code maze} into a byte array.
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeInputStreamV3.java b/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeInputStreamV3.java
index af809b9..8a0dc26 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeInputStreamV3.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeInputStreamV3.java
@@ -5,6 +5,7 @@ import ch.fritteli.maze.generator.model.Position;
import ch.fritteli.maze.generator.model.Tile;
import ch.fritteli.maze.generator.serialization.AbstractMazeInputStream;
import ch.fritteli.maze.generator.serialization.CommonTileHandler;
+import ch.fritteli.maze.generator.serialization.MazeConstants;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -22,11 +23,11 @@ public class MazeInputStreamV3 extends AbstractMazeInputStream {
// 01 0xb1 magic
// 02 0x03 version
final byte magic1 = this.readByte();
- if (magic1 != SerializerDeserializerV3.MAGIC_BYTE_1) {
+ if (magic1 != MazeConstants.MAGIC_BYTE_1) {
throw new IllegalArgumentException("Invalid maze data.");
}
final byte magic2 = this.readByte();
- if (magic2 != SerializerDeserializerV3.MAGIC_BYTE_2) {
+ if (magic2 != MazeConstants.MAGIC_BYTE_2) {
throw new IllegalArgumentException("Invalid maze data.");
}
final int version = this.readByte();
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeOutputStreamV3.java b/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeOutputStreamV3.java
index 891f0bb..c9da80e 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeOutputStreamV3.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v3/MazeOutputStreamV3.java
@@ -5,6 +5,7 @@ import ch.fritteli.maze.generator.model.Position;
import ch.fritteli.maze.generator.model.Tile;
import ch.fritteli.maze.generator.serialization.AbstractMazeOutputStream;
import ch.fritteli.maze.generator.serialization.CommonTileHandler;
+import ch.fritteli.maze.generator.serialization.MazeConstants;
import org.jetbrains.annotations.NotNull;
import java.nio.charset.StandardCharsets;
@@ -16,8 +17,8 @@ public class MazeOutputStreamV3 extends AbstractMazeOutputStream {
// 00 0x1a magic
// 01 0xb1 magic
// 02 0x03 version
- this.writeByte(SerializerDeserializerV3.MAGIC_BYTE_1);
- this.writeByte(SerializerDeserializerV3.MAGIC_BYTE_2);
+ this.writeByte(MazeConstants.MAGIC_BYTE_1);
+ this.writeByte(MazeConstants.MAGIC_BYTE_2);
this.writeByte(SerializerDeserializerV3.VERSION_BYTE);
}
diff --git a/src/main/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3.java b/src/main/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3.java
index ac9375d..1da19cc 100644
--- a/src/main/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3.java
+++ b/src/main/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3.java
@@ -32,10 +32,7 @@ import java.lang.reflect.InvocationTargetException;
*/
@UtilityClass
public class SerializerDeserializerV3 {
-
- final byte MAGIC_BYTE_1 = 0x1a;
- final byte MAGIC_BYTE_2 = (byte) 0xb1;
- final byte VERSION_BYTE = 0x03;
+ public final byte VERSION_BYTE = 0x03;
/**
* Serializes the {@code maze} into a byte array.
diff --git a/src/test/java/ch/fritteli/maze/generator/algorithm/WilsonTest.java b/src/test/java/ch/fritteli/maze/generator/algorithm/WilsonTest.java
deleted file mode 100644
index a4f8c9f..0000000
--- a/src/test/java/ch/fritteli/maze/generator/algorithm/WilsonTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package ch.fritteli.maze.generator.algorithm;
-
-import ch.fritteli.maze.generator.model.Maze;
-import ch.fritteli.maze.generator.renderer.text.TextRenderer;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-class WilsonTest {
- @Test
- void foo() {
- // arrange
- final Maze maze = new Maze(10, 10, 0);
- final Wilson wilson = new Wilson(maze);
-
- // act
- wilson.run();
-
- // assert
- final String textRepresentation = TextRenderer.newInstance().render(maze);
- assertThat(textRepresentation).isEqualTo("""
- ╷ ╶─────┬─────┬───┬─┐
- │ │ │ │ │
- │ ╷ ╶─┬─┴─┬─╴ ╵ ╷ │ │
- │ │ │ │ │ │ │
- │ └─┐ │ ╶─┼─┬─┬─┘ │ │
- │ │ │ │ │ │ │ │
- │ ╷ │ └─╴ │ ╵ ╵ ╶─┘ │
- │ │ │ │ │
- ├─┴─┘ ╷ ┌─┴───┐ ╷ ╶─┤
- │ │ │ │ │ │
- │ ╷ ┌─┘ └───╴ │ └─┬─┤
- │ │ │ │ │ │
- ├─┴─┘ ┌───╴ ╷ └─┐ ╵ │
- │ │ │ │ │
- │ ╶─┬─┴─╴ ┌─┘ ╶─┘ ╶─┤
- │ │ │ │
- ├─╴ ├─╴ ┌─┘ ╶─┐ ╶───┤
- │ │ │ │ │
- ├───┴─╴ └─┐ ╶─┴───┐ │
- │ │ │ │
- └─────────┴───────┘ ╵""");
- }
-}
diff --git a/src/test/java/ch/fritteli/maze/generator/algorithm/wilson/WilsonTest.java b/src/test/java/ch/fritteli/maze/generator/algorithm/wilson/WilsonTest.java
new file mode 100644
index 0000000..4457c42
--- /dev/null
+++ b/src/test/java/ch/fritteli/maze/generator/algorithm/wilson/WilsonTest.java
@@ -0,0 +1,100 @@
+package ch.fritteli.maze.generator.algorithm.wilson;
+
+import ch.fritteli.maze.generator.model.Maze;
+import ch.fritteli.maze.generator.renderer.text.TextRenderer;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class WilsonTest {
+ @Test
+ void testTinyGeneration() {
+ // arrange
+ final Maze maze = new Maze(3, 3, 0);
+ final Wilson wilson = new Wilson(maze);
+
+ // act
+ wilson.run();
+
+ // assert
+ final String textRepresentation = TextRenderer.newInstance().render(maze);
+ assertThat(textRepresentation).isEqualTo("""
+ ╷ ╶───┐
+ │ │
+ │ ┌─┐ │
+ │ │ │ │
+ │ ╵ │ │
+ │ │ │
+ └───┘ ╵""");
+ }
+
+ @Test
+ void testSimpleGeneration() {
+ // arrange
+ final Maze maze = new Maze(10, 10, 0);
+ final Wilson wilson = new Wilson(maze);
+
+ // act
+ wilson.run();
+
+ // assert
+ final String textRepresentation = TextRenderer.newInstance().render(maze);
+ assertThat(textRepresentation).isEqualTo("""
+ ╷ ╶─────┬─────┬─────┐
+ │ │ │ │
+ ├─╴ ╷ ╶─┴─┬─╴ ├─┐ ╶─┤
+ │ │ │ │ │ │
+ │ ╷ └─┐ ╶─┘ ┌─┘ ╵ ╷ │
+ │ │ │ │ │ │
+ │ │ ╶─┤ ╶─┐ ╵ ╷ ╶─┤ │
+ │ │ │ │ │ │ │
+ │ ├─┐ ├─╴ └─┐ │ ╶─┼─┤
+ │ │ │ │ │ │ │ │
+ ├─┘ └─┘ ╶─┐ └─┤ ╶─┤ │
+ │ │ │ │ │
+ ├───┐ ╷ ╶─┴───┴─┐ │ │
+ │ │ │ │ │ │
+ ├─╴ └─┼─╴ ╷ ╷ ┌─┴─┘ │
+ │ │ │ │ │ │
+ │ ╷ ╶─┴─┬─┤ ├─┘ ╶─┐ │
+ │ │ │ │ │ │ │
+ │ ├─╴ ╷ ╵ ╵ ╵ ┌─╴ │ │
+ │ │ │ │ │ │
+ └─┴───┴───────┴───┘ ╵""");
+ }
+
+ @Test
+ void testSimpleGenerationWithSolution() {
+ // arrange
+ final Maze maze = new Maze(10, 10, 0);
+ final Wilson wilson = new Wilson(maze);
+
+ // act
+ wilson.run();
+
+ // assert
+ final String textRepresentation = TextRenderer.newInstance().setRenderSolution(true).render(maze);
+ assertThat(textRepresentation).isEqualTo("""
+ ╷│╶─────┬─────┬─────┐
+ │╰───╮ │ │ │
+ ├─╴ ╷│╶─┴─┬─╴ ├─┐ ╶─┤
+ │ │╰─╮ │ │ │ │
+ │ ╷ └─┐│╶─┘ ┌─┘ ╵ ╷ │
+ │ │ ││ │ │ │
+ │ │ ╶─┤│╶─┐ ╵ ╷ ╶─┤ │
+ │ │ │╰─╮│ │ │ │
+ │ ├─┐ ├─╴│└─┐ │ ╶─┼─┤
+ │ │ │ │╭─╯ │ │ │ │
+ ├─┘ └─┘│╶─┐ └─┤ ╶─┤ │
+ │ │ │ │ │ │
+ ├───┐ ╷│╶─┴───┴─┐ │ │
+ │ │ │╰───╮ │ │ │
+ ├─╴ └─┼─╴ ╷│╷ ┌─┴─┘ │
+ │ │ │││ │╭───╮│
+ │ ╷ ╶─┴─┬─┤│├─┘│╶─┐││
+ │ │ │ │││╭─╯ │││
+ │ ├─╴ ╷ ╵ ╵│╵│┌─╴ │││
+ │ │ │ ╰─╯│ │││
+ └─┴───┴───────┴───┘│╵""");
+ }
+}
diff --git a/src/test/java/ch/fritteli/maze/generator/model/WallsTest.java b/src/test/java/ch/fritteli/maze/generator/model/WallsTest.java
index 7be7269..d0f861f 100644
--- a/src/test/java/ch/fritteli/maze/generator/model/WallsTest.java
+++ b/src/test/java/ch/fritteli/maze/generator/model/WallsTest.java
@@ -3,6 +3,8 @@ package ch.fritteli.maze.generator.model;
import io.vavr.collection.Stream;
import org.junit.jupiter.api.Test;
+import java.util.EnumSet;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -113,7 +115,7 @@ class WallsTest {
final Walls sut = new Walls();
// act
- Stream result = sut.getUnsealedSet();
+ EnumSet result = sut.getUnsealedSet();
// assert
assertThat(result).isEmpty();
diff --git a/src/test/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2Test.java b/src/test/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2Test.java
index c4898c7..a89e947 100644
--- a/src/test/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2Test.java
+++ b/src/test/java/ch/fritteli/maze/generator/serialization/v2/SerializerDeserializerV2Test.java
@@ -1,7 +1,7 @@
package ch.fritteli.maze.generator.serialization.v2;
import ch.fritteli.maze.generator.algorithm.RandomDepthFirst;
-import ch.fritteli.maze.generator.algorithm.Wilson;
+import ch.fritteli.maze.generator.algorithm.wilson.Wilson;
import ch.fritteli.maze.generator.model.Maze;
import ch.fritteli.maze.generator.model.Position;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3Test.java b/src/test/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3Test.java
index fde2008..801c677 100644
--- a/src/test/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3Test.java
+++ b/src/test/java/ch/fritteli/maze/generator/serialization/v3/SerializerDeserializerV3Test.java
@@ -1,7 +1,7 @@
package ch.fritteli.maze.generator.serialization.v3;
import ch.fritteli.maze.generator.algorithm.RandomDepthFirst;
-import ch.fritteli.maze.generator.algorithm.Wilson;
+import ch.fritteli.maze.generator.algorithm.wilson.Wilson;
import ch.fritteli.maze.generator.model.Maze;
import ch.fritteli.maze.generator.model.Position;
import org.junit.jupiter.api.Test;
@@ -37,4 +37,13 @@ class SerializerDeserializerV3Test {
final Maze result = SerializerDeserializerV3.deserialize(bytes);
assertThat(result).isEqualTo(expected);
}
+
+ @Test
+ void testSerializeDeserializeLargeRandom() throws IOException {
+ final Maze expected = new Maze(200, 320, 3141592653589793238L);
+ new RandomDepthFirst(expected).run();
+ final byte[] bytes = SerializerDeserializerV3.serialize(expected);
+ final Maze result = SerializerDeserializerV3.deserialize(bytes);
+ assertThat(result).isEqualTo(expected);
+ }
}