Chore: Java 21. #9
					 34 changed files with 279 additions and 290 deletions
				
			
		|  | @ -3,7 +3,7 @@ type: docker | |||
| name: default | ||||
| steps: | ||||
|   - name: build | ||||
|     image: maven:3.8-openjdk-18-slim | ||||
|     image: maven:3.9-eclipse-temurin-21 | ||||
|     commands: | ||||
|       - mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -B -V | ||||
|     when: | ||||
|  | @ -13,7 +13,7 @@ steps: | |||
|           - refs/head/feature/** | ||||
|           - refs/tags/** | ||||
|   - name: test | ||||
|     image: maven:3.8-openjdk-18-slim | ||||
|     image: maven:3.9-eclipse-temurin-21 | ||||
|     commands: | ||||
|       - mvn test -B | ||||
|     when: | ||||
|  | @ -22,7 +22,7 @@ steps: | |||
|           - master | ||||
|           - feature/* | ||||
|   - name: deploy | ||||
|     image: maven:3.8-openjdk-18-slim | ||||
|     image: maven:3.9-eclipse-temurin-21 | ||||
|     environment: | ||||
|       REPO_TOKEN: | ||||
|         from_secret: repo-token | ||||
|  |  | |||
							
								
								
									
										13
									
								
								pom.xml
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								pom.xml
									
										
									
									
									
								
							|  | @ -46,7 +46,6 @@ | |||
|         <tag>HEAD</tag> | ||||
|     </scm> | ||||
| 
 | ||||
| 
 | ||||
|     <distributionManagement> | ||||
|         <snapshotRepository> | ||||
|             <id>ossrh</id> | ||||
|  | @ -56,16 +55,22 @@ | |||
|     </distributionManagement> | ||||
| 
 | ||||
|     <properties> | ||||
|         <jackson.version>2.15.0</jackson.version> | ||||
|         <assertj.version>3.25.3</assertj.version> | ||||
|         <jackson.version>2.17.1</jackson.version> | ||||
|         <jsonschema2pojo-maven-plugin.version>1.2.1</jsonschema2pojo-maven-plugin.version> | ||||
|         <logback.version>1.5.6</logback.version> | ||||
|         <lombok.version>1.18.32</lombok.version> | ||||
|         <maven.compiler.release>21</maven.compiler.release> | ||||
|         <maven-site-plugin.version>4.0.0-M8</maven-site-plugin.version> | ||||
|         <pdfbox.version>2.0.28</pdfbox.version> | ||||
|         <pdfbox.version>3.0.2</pdfbox.version> | ||||
|         <slf4j.version>2.0.12</slf4j.version> | ||||
|     </properties> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>org.projectlombok</groupId> | ||||
|             <artifactId>lombok</artifactId> | ||||
|             <version>${lombok.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.jetbrains</groupId> | ||||
|  | @ -107,7 +112,7 @@ | |||
|         <dependency> | ||||
|             <groupId>org.assertj</groupId> | ||||
|             <artifactId>assertj-core</artifactId> | ||||
|             <version>3.24.2</version> | ||||
|             <version>${assertj.version}</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|  |  | |||
|  | @ -9,17 +9,18 @@ import ch.fritteli.maze.generator.renderer.jsonfile.JsonFileRenderer; | |||
| import ch.fritteli.maze.generator.renderer.pdffile.PDFFileRenderer; | ||||
| import ch.fritteli.maze.generator.renderer.text.TextRenderer; | ||||
| import ch.fritteli.maze.generator.renderer.textfile.TextFileRenderer; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
| import lombok.NonNull; | ||||
| import lombok.experimental.UtilityClass; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
| 
 | ||||
| @Slf4j | ||||
| @UtilityClass | ||||
| public class Main { | ||||
| 
 | ||||
|     public static void main(@NonNull final String[] args) { | ||||
|     public static void main(@NotNull final String[] args) { | ||||
|         final int width = 20; | ||||
|         final int height = 30; | ||||
|         final Maze maze = new Maze(width, height/*, 0*/); | ||||
|  | @ -58,7 +59,7 @@ public class Main { | |||
|         log.info("PDF rendering to file:\n{}", pdfFileRenderer.render(maze)); | ||||
|     } | ||||
| 
 | ||||
|     private static String getBaseFilename(@NonNull final Maze maze) { | ||||
|     private static String getBaseFilename(@NotNull final Maze maze) { | ||||
|         return "maze-" + maze.getWidth() + "x" + maze.getHeight() + "-" + maze.getRandomSeed(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -5,21 +5,22 @@ import ch.fritteli.maze.generator.model.Maze; | |||
| import ch.fritteli.maze.generator.model.Position; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import io.vavr.control.Option; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.util.Deque; | ||||
| import java.util.LinkedList; | ||||
| import java.util.Random; | ||||
| import lombok.NonNull; | ||||
| 
 | ||||
| public class RandomDepthFirst { | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final Maze maze; | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final Random random; | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final Deque<Position> positions = new LinkedList<>(); | ||||
| 
 | ||||
|     public RandomDepthFirst(@NonNull final Maze maze) { | ||||
|     public RandomDepthFirst(@NotNull final Maze maze) { | ||||
|         this.maze = maze; | ||||
|         this.random = new Random(maze.getRandomSeed()); | ||||
|     } | ||||
|  | @ -34,16 +35,16 @@ public class RandomDepthFirst { | |||
|         final Position end = this.maze.getEnd(); | ||||
|         final Tile endTile = this.maze.getEndTile(); | ||||
| 
 | ||||
|         if (end.getY() == 0) { | ||||
|         if (end.y() == 0) { | ||||
|             endTile.enableDiggingToOrFrom(Direction.TOP); | ||||
|             endTile.digFrom(Direction.TOP); | ||||
|         } else if (end.getX() == 0) { | ||||
|         } else if (end.x() == 0) { | ||||
|             endTile.enableDiggingToOrFrom(Direction.LEFT); | ||||
|             endTile.digFrom(Direction.LEFT); | ||||
|         } else if (end.getY() == this.maze.getHeight() - 1) { | ||||
|         } else if (end.y() == this.maze.getHeight() - 1) { | ||||
|             endTile.enableDiggingToOrFrom(Direction.BOTTOM); | ||||
|             endTile.digFrom(Direction.BOTTOM); | ||||
|         } else if (end.getX() == this.maze.getWidth() - 1) { | ||||
|         } else if (end.x() == this.maze.getWidth() - 1) { | ||||
|             endTile.enableDiggingToOrFrom(Direction.RIGHT); | ||||
|             endTile.digFrom(Direction.RIGHT); | ||||
|         } | ||||
|  | @ -86,16 +87,16 @@ public class RandomDepthFirst { | |||
|         final Position start = this.maze.getStart(); | ||||
|         final Tile startTile = this.maze.getStartTile(); | ||||
| 
 | ||||
|         if (start.getY() == 0) { | ||||
|         if (start.y() == 0) { | ||||
|             startTile.enableDiggingToOrFrom(Direction.TOP); | ||||
|             startTile.digTo(Direction.TOP); | ||||
|         } else if (start.getX() == 0) { | ||||
|         } else if (start.x() == 0) { | ||||
|             startTile.enableDiggingToOrFrom(Direction.LEFT); | ||||
|             startTile.digTo(Direction.LEFT); | ||||
|         } else if (start.getY() == this.maze.getHeight() - 1) { | ||||
|         } else if (start.y() == this.maze.getHeight() - 1) { | ||||
|             startTile.enableDiggingToOrFrom(Direction.BOTTOM); | ||||
|             startTile.digTo(Direction.BOTTOM); | ||||
|         } else if (start.getX() == this.maze.getWidth() - 1) { | ||||
|         } else if (start.x() == this.maze.getWidth() - 1) { | ||||
|             startTile.enableDiggingToOrFrom(Direction.RIGHT); | ||||
|             startTile.digTo(Direction.RIGHT); | ||||
|         } | ||||
|  |  | |||
|  | @ -7,17 +7,11 @@ public enum Direction { | |||
|     LEFT; | ||||
| 
 | ||||
|     public Direction invert() { | ||||
|         switch (this) { | ||||
|             case TOP: | ||||
|                 return BOTTOM; | ||||
|             case RIGHT: | ||||
|                 return LEFT; | ||||
|             case BOTTOM: | ||||
|                 return TOP; | ||||
|             case LEFT: | ||||
|                 return RIGHT; | ||||
|             default: | ||||
|                 throw new IllegalStateException("Programming error: Not all enum values covered in enum Direction#invert()!"); | ||||
|         } | ||||
|         return switch (this) { | ||||
|             case TOP -> BOTTOM; | ||||
|             case RIGHT -> LEFT; | ||||
|             case BOTTOM -> TOP; | ||||
|             case LEFT -> RIGHT; | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ package ch.fritteli.maze.generator.model; | |||
| import io.vavr.control.Option; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.Getter; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| @EqualsAndHashCode | ||||
| @ToString | ||||
|  | @ -26,7 +26,7 @@ public class Maze { | |||
|         this(width, height, System.nanoTime()); | ||||
|     } | ||||
| 
 | ||||
|     public Maze(final int width, final int height, @NonNull final Position start, @NonNull final Position end) { | ||||
|     public Maze(final int width, final int height, @NotNull final Position start, @NotNull final Position end) { | ||||
|         this(width, height, System.nanoTime(), start, end); | ||||
|     } | ||||
| 
 | ||||
|  | @ -34,17 +34,17 @@ public class Maze { | |||
|         this(width, height, randomSeed, new Position(0, 0), new Position(width - 1, height - 1)); | ||||
|     } | ||||
| 
 | ||||
|     public Maze(final int width, final int height, final long randomSeed, @NonNull final Position start, @NonNull final Position end) { | ||||
|     public Maze(final int width, final int height, final long randomSeed, @NotNull final Position start, @NotNull final Position end) { | ||||
|         if (width <= 1 || height <= 1) { | ||||
|             throw new IllegalArgumentException("width and height must be >1"); | ||||
|         } | ||||
|         if (start.equals(end)) { | ||||
|             throw new IllegalArgumentException("'start' must not be equal to 'end'"); | ||||
|         } | ||||
|         if (start.getX() != 0 && start.getX() != width - 1 && start.getY() != 0 && start.getY() != height - 1) { | ||||
|         if (start.x() != 0 && start.x() != width - 1 && start.y() != 0 && start.y() != height - 1) { | ||||
|             throw new IllegalArgumentException("'start' must be at the edge of the maze"); | ||||
|         } | ||||
|         if (end.getX() != 0 && end.getX() != width - 1 && end.getY() != 0 && end.getY() != height - 1) { | ||||
|         if (end.x() != 0 && end.x() != width - 1 && end.y() != 0 && end.y() != height - 1) { | ||||
|             throw new IllegalArgumentException("'end' must be at the edge of the maze"); | ||||
|         } | ||||
|         this.width = width; | ||||
|  | @ -59,7 +59,7 @@ public class Maze { | |||
|     /** | ||||
|      * INTERNAL API. Exists only for deserialization. Not to be called from user code. | ||||
|      */ | ||||
|     private Maze(@NonNull final Tile[][] field, final int width, final int height, final long randomSeed) { | ||||
|     private Maze(@NotNull final Tile[][] field, final int width, final int height, final long randomSeed) { | ||||
|         this.field = field; | ||||
|         this.width = width; | ||||
|         this.height = height; | ||||
|  | @ -71,7 +71,7 @@ public class Maze { | |||
|     /** | ||||
|      * INTERNAL API. Exists only for deserialization. Not to be called from user code. | ||||
|      */ | ||||
|     private Maze(@NonNull final Tile[][] field, final int width, final int height, @NonNull final Position start, @NonNull final Position end, final long randomSeed) { | ||||
|     private Maze(@NotNull final Tile[][] field, final int width, final int height, @NotNull final Position start, @NotNull final Position end, final long randomSeed) { | ||||
|         this.field = field; | ||||
|         this.width = width; | ||||
|         this.height = height; | ||||
|  | @ -80,12 +80,12 @@ public class Maze { | |||
|         this.end = end; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public Option<Tile> getTileAt(@NonNull final Position position) { | ||||
|         return this.getTileAt(position.getX(), position.getY()); | ||||
|     @NotNull | ||||
|     public Option<Tile> getTileAt(@NotNull final Position position) { | ||||
|         return this.getTileAt(position.x(), position.y()); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public Option<Tile> getTileAt(final int x, final int y) { | ||||
|         if (x < 0 || y < 0 || x >= this.width || y >= this.height) { | ||||
|             return Option.none(); | ||||
|  | @ -93,12 +93,12 @@ public class Maze { | |||
|         return Option.of(this.field[x][y]); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public Tile getStartTile() { | ||||
|         return this.getTileAt(this.start).get(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public Tile getEndTile() { | ||||
|         return this.getTileAt(this.end).get(); | ||||
|     } | ||||
|  | @ -114,7 +114,7 @@ public class Maze { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void hardenWalls(@NonNull final Tile tile, final int x, final int y) { | ||||
|     private void hardenWalls(@NotNull final Tile tile, final int x, final int y) { | ||||
|         if (x == 0) { | ||||
|             tile.preventDiggingToOrFrom(Direction.LEFT); | ||||
|         } | ||||
|  |  | |||
|  | @ -1,27 +1,16 @@ | |||
| package ch.fritteli.maze.generator.model; | ||||
| 
 | ||||
| import lombok.NonNull; | ||||
| import lombok.Value; | ||||
| import lombok.With; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| @Value | ||||
| @With | ||||
| public class Position { | ||||
|     int x; | ||||
|     int y; | ||||
| 
 | ||||
|     public Position move(@NonNull final Direction direction) { | ||||
|         switch (direction) { | ||||
|             case BOTTOM: | ||||
|                 return this.withY(this.y + 1); | ||||
|             case LEFT: | ||||
|                 return this.withX(this.x - 1); | ||||
|             case RIGHT: | ||||
|                 return this.withX(this.x + 1); | ||||
|             case TOP: | ||||
|                 return this.withY(this.y - 1); | ||||
|             default: | ||||
|                 throw new IllegalStateException("Programming error: Not all Direction enum values covered in Position#move(Direction)!"); | ||||
|         } | ||||
| public record Position(int x, int y) { | ||||
|     public Position move(@NotNull final Direction direction) { | ||||
|         return switch (direction) { | ||||
|             case BOTTOM -> this.withY(this.y + 1); | ||||
|             case LEFT -> this.withX(this.x - 1); | ||||
|             case RIGHT -> this.withX(this.x + 1); | ||||
|             case TOP -> this.withY(this.y - 1); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -5,9 +5,9 @@ import io.vavr.control.Option; | |||
| import lombok.AccessLevel; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.Getter; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.FieldDefaults; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.util.EnumSet; | ||||
| import java.util.Random; | ||||
|  | @ -32,7 +32,7 @@ public class Tile { | |||
|      * @param walls | ||||
|      * @param solution | ||||
|      */ | ||||
|     private Tile(@NonNull final EnumSet<Direction> walls, final boolean solution) { | ||||
|     private Tile(@NotNull final EnumSet<Direction> walls, final boolean solution) { | ||||
|         for (final Direction direction : walls) { | ||||
|             this.walls.set(direction); | ||||
|             this.walls.harden(direction); | ||||
|  | @ -41,15 +41,15 @@ public class Tile { | |||
|         this.solution = solution; | ||||
|     } | ||||
| 
 | ||||
|     public void preventDiggingToOrFrom(@NonNull final Direction direction) { | ||||
|     public void preventDiggingToOrFrom(@NotNull final Direction direction) { | ||||
|         this.walls.harden(direction); | ||||
|     } | ||||
| 
 | ||||
|     public void enableDiggingToOrFrom(@NonNull final Direction direction) { | ||||
|     public void enableDiggingToOrFrom(@NotNull final Direction direction) { | ||||
|         this.walls.unharden(direction); | ||||
|     } | ||||
| 
 | ||||
|     public boolean digFrom(@NonNull final Direction direction) { | ||||
|     public boolean digFrom(@NotNull final Direction direction) { | ||||
|         if (this.visited) { | ||||
|             return false; | ||||
|         } | ||||
|  | @ -57,15 +57,15 @@ public class Tile { | |||
|         return this.walls.clear(direction); | ||||
|     } | ||||
| 
 | ||||
|     public boolean digTo(@NonNull final Direction direction) { | ||||
|     public boolean digTo(@NotNull final Direction direction) { | ||||
|         return this.walls.clear(direction); | ||||
|     } | ||||
| 
 | ||||
|     public void undigTo(@NonNull final Direction direction) { | ||||
|     public void undigTo(@NotNull final Direction direction) { | ||||
|         this.walls.set(direction); | ||||
|     } | ||||
| 
 | ||||
|     public Option<Direction> getRandomAvailableDirection(@NonNull final Random random) { | ||||
|     public Option<Direction> getRandomAvailableDirection(@NotNull final Random random) { | ||||
|         final Stream<Direction> availableDirections = this.walls.getUnhardenedSet(); | ||||
|         if (availableDirections.isEmpty()) { | ||||
|             return Option.none(); | ||||
|  | @ -74,7 +74,7 @@ public class Tile { | |||
|         return Option.of(availableDirections.get(index)); | ||||
|     } | ||||
| 
 | ||||
|     public boolean hasWallAt(@NonNull final Direction direction) { | ||||
|     public boolean hasWallAt(@NotNull final Direction direction) { | ||||
|         return this.walls.isSet(direction); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,8 +2,8 @@ package ch.fritteli.maze.generator.model; | |||
| 
 | ||||
| import io.vavr.collection.Stream; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.util.EnumSet; | ||||
| import java.util.HashSet; | ||||
|  | @ -17,7 +17,7 @@ public class Walls { | |||
|     private final SortedSet<Direction> directions = new TreeSet<>(); | ||||
|     private final Set<Direction> hardened = new HashSet<>(); | ||||
| 
 | ||||
|     public void set(@NonNull final Direction direction) { | ||||
|     public void set(@NotNull final Direction direction) { | ||||
|         this.directions.add(direction); | ||||
|     } | ||||
| 
 | ||||
|  | @ -25,14 +25,14 @@ public class Walls { | |||
|         this.directions.addAll(EnumSet.allOf(Direction.class)); | ||||
|     } | ||||
| 
 | ||||
|     public boolean clear(@NonNull final Direction direction) { | ||||
|     public boolean clear(@NotNull final Direction direction) { | ||||
|         if (this.hardened.contains(direction)) { | ||||
|             return false; | ||||
|         } | ||||
|         return this.directions.remove(direction); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isSet(@NonNull final Direction direction) { | ||||
|     public boolean isSet(@NotNull final Direction direction) { | ||||
|         return this.directions.contains(direction); | ||||
|     } | ||||
| 
 | ||||
|  | @ -41,14 +41,14 @@ public class Walls { | |||
|                 .removeAll(this.hardened); | ||||
|     } | ||||
| 
 | ||||
|     public void harden(@NonNull final Direction direction) { | ||||
|     public void harden(@NotNull final Direction direction) { | ||||
|         if (!this.directions.contains(direction)) { | ||||
|             throw new IllegalStateException("Trying to harden cleared Direction: " + direction); | ||||
|         } | ||||
|         this.hardened.add(direction); | ||||
|     } | ||||
| 
 | ||||
|     public void unharden(@NonNull final Direction direction) { | ||||
|     public void unharden(@NotNull final Direction direction) { | ||||
|         this.hardened.remove(direction); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| package ch.fritteli.maze.generator.renderer; | ||||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public interface Renderer<T> { | ||||
|     @NonNull | ||||
|     T render(@NonNull final Maze maze); | ||||
|     @NotNull | ||||
|     T render(@NotNull final Maze maze); | ||||
| } | ||||
|  |  | |||
|  | @ -6,8 +6,8 @@ import ch.fritteli.maze.generator.model.Tile; | |||
| import io.vavr.collection.HashSet; | ||||
| import io.vavr.collection.Set; | ||||
| import lombok.AccessLevel; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| @RequiredArgsConstructor(access = AccessLevel.PACKAGE) | ||||
| class Generator { | ||||
|  | @ -31,7 +31,7 @@ class Generator { | |||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
|     private Set<String> getClasses(@NonNull final Tile tile) { | ||||
|     private Set<String> getClasses(@NotNull final Tile tile) { | ||||
|         Set<String> result = HashSet.empty(); | ||||
|         if (tile.hasWallAt(Direction.TOP)) { | ||||
|             result = result.add("top"); | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ package ch.fritteli.maze.generator.renderer.html; | |||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.renderer.Renderer; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public class HTMLRenderer implements Renderer<String> { | ||||
| 
 | ||||
|  | @ -112,14 +112,14 @@ public class HTMLRenderer implements Renderer<String> { | |||
|     private HTMLRenderer() { | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static HTMLRenderer newInstance() { | ||||
|         return new HTMLRenderer(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public String render(@NonNull final Maze maze) { | ||||
|     public String render(@NotNull final Maze maze) { | ||||
|         if (maze.getWidth() == 0 || maze.getHeight() == 0) { | ||||
|             return this.getPreamble(maze) + POSTAMBLE; | ||||
|         } | ||||
|  | @ -134,7 +134,7 @@ public class HTMLRenderer implements Renderer<String> { | |||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
|     private String getPreamble(@NonNull final Maze maze) { | ||||
|     private String getPreamble(@NotNull final Maze maze) { | ||||
|         return "<!DOCTYPE html><html lang=\"en\">" + | ||||
|                 "<head>" + | ||||
|                 "<title>Maze " + maze.getWidth() + "x" + maze.getHeight() + ", ID " + maze.getRandomSeed() + "</title>" + | ||||
|  |  | |||
|  | @ -5,8 +5,8 @@ import ch.fritteli.maze.generator.renderer.Renderer; | |||
| import ch.fritteli.maze.generator.renderer.html.HTMLRenderer; | ||||
| import io.vavr.control.Option; | ||||
| import io.vavr.control.Try; | ||||
| import lombok.NonNull; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
|  | @ -17,9 +17,9 @@ import java.util.NoSuchElementException; | |||
| 
 | ||||
| @Slf4j | ||||
| public class HTMLFileRenderer implements Renderer<Path> { | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private static final HTMLRenderer HTML_RENDERER = HTMLRenderer.newInstance(); | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private Option<Path> targetFile; | ||||
| 
 | ||||
|     private HTMLFileRenderer() { | ||||
|  | @ -29,7 +29,7 @@ public class HTMLFileRenderer implements Renderer<Path> { | |||
|                 .toOption(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static HTMLFileRenderer newInstance() { | ||||
|         return new HTMLFileRenderer(); | ||||
|     } | ||||
|  | @ -40,15 +40,15 @@ public class HTMLFileRenderer implements Renderer<Path> { | |||
|                 .exists(File::canWrite); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public HTMLFileRenderer setTargetFile(@NonNull final Path targetFile) { | ||||
|     @NotNull | ||||
|     public HTMLFileRenderer setTargetFile(@NotNull final Path targetFile) { | ||||
|         this.targetFile = Option.of(targetFile); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public Path render(@NonNull final Maze maze) { | ||||
|     public Path render(@NotNull final Maze maze) { | ||||
|         if (!this.isTargetFileDefinedAndWritable()) { | ||||
|             try { | ||||
|                 Files.createFile(this.targetFile.get()); | ||||
|  |  | |||
|  | @ -7,8 +7,8 @@ import ch.fritteli.maze.generator.model.Direction; | |||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import lombok.AccessLevel; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | @ -16,10 +16,10 @@ import java.util.List; | |||
| @RequiredArgsConstructor(access = AccessLevel.PACKAGE) | ||||
| class Generator { | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final Maze maze; | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     JsonMaze generate() { | ||||
|         final JsonMaze result = new JsonMaze(); | ||||
|         result.setId(String.valueOf(this.maze.getRandomSeed())); | ||||
|  | @ -30,7 +30,7 @@ class Generator { | |||
|             final ArrayList<JsonCell> row = new ArrayList<>(); | ||||
|             for (int x = 0; x < this.maze.getWidth(); x++) { | ||||
|                 // x and y are not effectively final and can therefore not be accessed from within the lambda. Hence, create the string beforehand. | ||||
|                 final String exceptionString = "Failed to obtain tile at %dx%d, although maze has dimensoins %dx%d" | ||||
|                 final String exceptionString = "Failed to obtain tile at %dx%d, although maze has dimensions %dx%d" | ||||
|                         .formatted(x, y, this.maze.getWidth(), this.maze.getHeight()); | ||||
|                 final Tile tile = this.maze.getTileAt(x, y) | ||||
|                         .getOrElseThrow(() -> new IllegalStateException(exceptionString)); | ||||
|  | @ -46,12 +46,12 @@ class Generator { | |||
|         } | ||||
|         result.setGrid(rows); | ||||
|         final JsonCoordinates start = new JsonCoordinates(); | ||||
|         start.setX(this.maze.getStart().getX()); | ||||
|         start.setY(this.maze.getStart().getY()); | ||||
|         start.setX(this.maze.getStart().x()); | ||||
|         start.setY(this.maze.getStart().y()); | ||||
|         result.setStart(start); | ||||
|         final JsonCoordinates end = new JsonCoordinates(); | ||||
|         end.setX(this.maze.getEnd().getX()); | ||||
|         end.setY(this.maze.getEnd().getY()); | ||||
|         end.setX(this.maze.getEnd().x()); | ||||
|         end.setY(this.maze.getEnd().y()); | ||||
|         result.setEnd(end); | ||||
|         return result; | ||||
|     } | ||||
|  |  | |||
|  | @ -7,14 +7,14 @@ import ch.fritteli.maze.generator.renderer.Renderer; | |||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.fasterxml.jackson.databind.SerializationFeature; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class JsonRenderer implements Renderer<String> { | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final ObjectMapper objectMapper; | ||||
| 
 | ||||
|     private JsonRenderer() { | ||||
|  | @ -22,12 +22,12 @@ public class JsonRenderer implements Renderer<String> { | |||
|                 .enable(SerializationFeature.INDENT_OUTPUT); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static JsonRenderer newInstance() { | ||||
|         return new JsonRenderer(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private static JsonMaze createSingleCellMaze() { | ||||
|         // This is the only cell. | ||||
|         final JsonCell cell = new JsonCell(); | ||||
|  | @ -37,7 +37,7 @@ public class JsonRenderer implements Renderer<String> { | |||
|         // Wrap that in a nested list. | ||||
|         final List<List<JsonCell>> rows = new ArrayList<>(); | ||||
|         rows.add(new ArrayList<>()); | ||||
|         rows.get(0).add(cell); | ||||
|         rows.getFirst().add(cell); | ||||
|         // Wrap it all in an instance of JsonMaze. | ||||
|         final JsonMaze jsonMaze = new JsonMaze(); | ||||
|         jsonMaze.setId("0"); | ||||
|  | @ -45,8 +45,8 @@ public class JsonRenderer implements Renderer<String> { | |||
|         return jsonMaze; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private String toString(@NonNull final JsonMaze jsonMaze) { | ||||
|     @NotNull | ||||
|     private String toString(@NotNull final JsonMaze jsonMaze) { | ||||
|         try { | ||||
|             return this.objectMapper.writeValueAsString(jsonMaze); | ||||
|         } catch (final JsonProcessingException e) { | ||||
|  | @ -54,9 +54,9 @@ public class JsonRenderer implements Renderer<String> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public String render(@NonNull final Maze maze) { | ||||
|     public String render(@NotNull final Maze maze) { | ||||
|         final JsonMaze jsonMaze; | ||||
|         if (maze.getWidth() == 0 || maze.getHeight() == 0) { | ||||
|             jsonMaze = createSingleCellMaze(); | ||||
|  |  | |||
|  | @ -5,21 +5,22 @@ import ch.fritteli.maze.generator.renderer.Renderer; | |||
| import ch.fritteli.maze.generator.renderer.json.JsonRenderer; | ||||
| import io.vavr.control.Option; | ||||
| import io.vavr.control.Try; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.NoSuchElementException; | ||||
| import lombok.NonNull; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| 
 | ||||
| @Slf4j | ||||
| public class JsonFileRenderer implements Renderer<Path> { | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private static final JsonRenderer JSON_RENDERER = JsonRenderer.newInstance(); | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private Option<Path> targetFile; | ||||
| 
 | ||||
|     private JsonFileRenderer() { | ||||
|  | @ -29,7 +30,7 @@ public class JsonFileRenderer implements Renderer<Path> { | |||
|                 .toOption(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static JsonFileRenderer newInstance() { | ||||
|         return new JsonFileRenderer(); | ||||
|     } | ||||
|  | @ -40,15 +41,15 @@ public class JsonFileRenderer implements Renderer<Path> { | |||
|                 .exists(File::canWrite); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public JsonFileRenderer setTargetFile(@NonNull final Path targetFile) { | ||||
|     @NotNull | ||||
|     public JsonFileRenderer setTargetFile(@NotNull final Path targetFile) { | ||||
|         this.targetFile = Option.of(targetFile); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public Path render(@NonNull final Maze maze) { | ||||
|     public Path render(@NotNull final Maze maze) { | ||||
|         if (!this.isTargetFileDefinedAndWritable()) { | ||||
|             try { | ||||
|                 Files.createFile(this.targetFile.get()); | ||||
|  |  | |||
|  | @ -5,11 +5,6 @@ import ch.fritteli.maze.generator.model.Maze; | |||
| import ch.fritteli.maze.generator.model.Position; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import io.vavr.control.Option; | ||||
| import java.awt.BasicStroke; | ||||
| import java.awt.Color; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.Value; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
|  | @ -18,16 +13,21 @@ import org.apache.pdfbox.pdmodel.PDDocumentInformation; | |||
| import org.apache.pdfbox.pdmodel.PDPage; | ||||
| import org.apache.pdfbox.pdmodel.PDPageContentStream; | ||||
| import org.apache.pdfbox.pdmodel.common.PDRectangle; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| import org.jetbrains.annotations.Nullable; | ||||
| 
 | ||||
| import java.awt.*; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| @RequiredArgsConstructor | ||||
| @Slf4j | ||||
| class Generator { | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final Maze maze; | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public ByteArrayOutputStream generate() { | ||||
|         final float pageWidth = this.maze.getWidth() * PDFRenderer.SCALE + 2 * PDFRenderer.MARGIN; | ||||
|         final float pageHeight = this.maze.getHeight() * PDFRenderer.SCALE + 2 * PDFRenderer.MARGIN; | ||||
|  | @ -60,7 +60,7 @@ class Generator { | |||
|         return output; | ||||
|     } | ||||
| 
 | ||||
|     private void setUpPageContentStream(@NonNull final PDPageContentStream pageContentStream) throws IOException { | ||||
|     private void setUpPageContentStream(@NotNull final PDPageContentStream pageContentStream) throws IOException { | ||||
|         pageContentStream.setLineCapStyle(BasicStroke.CAP_ROUND); | ||||
|         pageContentStream.setLineJoinStyle(BasicStroke.JOIN_ROUND); | ||||
|         pageContentStream.setLineWidth(1.0f); | ||||
|  | @ -68,7 +68,7 @@ class Generator { | |||
|         pageContentStream.setNonStrokingColor(Color.BLACK); | ||||
|     } | ||||
| 
 | ||||
|     private void drawHorizontalLines(@NonNull final PDPageContentStream... contentStreams) throws IOException { | ||||
|     private void drawHorizontalLines(@NotNull final PDPageContentStream... contentStreams) throws IOException { | ||||
|         // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. | ||||
|         Coordinate coordinate = new Coordinate(0f, 0f); | ||||
|         // Draw the TOP borders of all tiles. | ||||
|  | @ -136,7 +136,7 @@ class Generator { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void drawVerticalLines(@NonNull final PDPageContentStream... contentStreams) throws IOException { | ||||
|     private void drawVerticalLines(@NotNull final PDPageContentStream... contentStreams) throws IOException { | ||||
|         // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. | ||||
|         Coordinate coordinate = new Coordinate(0f, 0f); | ||||
|         // Draw the LEFT borders of all tiles. | ||||
|  | @ -204,27 +204,27 @@ class Generator { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void drawSolution(@NonNull final PDPageContentStream pageContentStream) throws IOException { | ||||
|     private void drawSolution(@NotNull final PDPageContentStream pageContentStream) throws IOException { | ||||
|         // Draw the solution in red | ||||
|         pageContentStream.setStrokingColor(Color.RED); | ||||
|         // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. | ||||
|         final Position end = this.maze.getEnd(); | ||||
|         Position currentPosition = this.maze.getStart(); | ||||
|         Position previousPosition = null; | ||||
|         SolutionCoordinate coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY()); | ||||
|         SolutionCoordinate coordinate = new SolutionCoordinate(currentPosition.x(), currentPosition.y()); | ||||
|         pageContentStream.moveTo(coordinate.getX(), coordinate.getY()); | ||||
|         do { | ||||
|             Position newCurrent = this.findNextSolutionPosition(previousPosition, currentPosition); | ||||
|             previousPosition = currentPosition; | ||||
|             currentPosition = newCurrent; | ||||
|             coordinate = new SolutionCoordinate(currentPosition.getX(), currentPosition.getY()); | ||||
|             coordinate = new SolutionCoordinate(currentPosition.x(), currentPosition.y()); | ||||
|             pageContentStream.lineTo(coordinate.getX(), coordinate.getY()); | ||||
|         } while (!currentPosition.equals(end)); | ||||
|         pageContentStream.stroke(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private Position findNextSolutionPosition(@Nullable final Position previousPosition, @NonNull final Position currentPosition) { | ||||
|     @NotNull | ||||
|     private Position findNextSolutionPosition(@Nullable final Position previousPosition, @NotNull final Position currentPosition) { | ||||
|         final Tile currentTile = this.maze.getTileAt(currentPosition).get(); | ||||
|         for (final Direction direction : Direction.values()) { | ||||
|             if (!currentTile.hasWallAt(direction)) { | ||||
|  |  | |||
|  | @ -2,9 +2,9 @@ package ch.fritteli.maze.generator.renderer.pdf; | |||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.renderer.Renderer; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import lombok.NonNull; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| 
 | ||||
| public class PDFRenderer implements Renderer<ByteArrayOutputStream> { | ||||
|     static final float MARGIN = 10; | ||||
|  | @ -13,14 +13,14 @@ public class PDFRenderer implements Renderer<ByteArrayOutputStream> { | |||
|     private PDFRenderer() { | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static PDFRenderer newInstance() { | ||||
|         return new PDFRenderer(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public ByteArrayOutputStream render(@NonNull final Maze maze) { | ||||
|     public ByteArrayOutputStream render(@NotNull final Maze maze) { | ||||
|         final Generator generator = new Generator(maze); | ||||
|         return generator.generate(); | ||||
|     } | ||||
|  |  | |||
|  | @ -5,21 +5,22 @@ import ch.fritteli.maze.generator.renderer.Renderer; | |||
| import ch.fritteli.maze.generator.renderer.pdf.PDFRenderer; | ||||
| import io.vavr.control.Option; | ||||
| import io.vavr.control.Try; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.NoSuchElementException; | ||||
| import lombok.NonNull; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| 
 | ||||
| @Slf4j | ||||
| public class PDFFileRenderer implements Renderer<Path> { | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private static final PDFRenderer PDF_RENDERER = PDFRenderer.newInstance(); | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private Option<Path> targetFile; | ||||
| 
 | ||||
|     private PDFFileRenderer() { | ||||
|  | @ -29,7 +30,7 @@ public class PDFFileRenderer implements Renderer<Path> { | |||
|                 .toOption(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static PDFFileRenderer newInstance() { | ||||
|         return new PDFFileRenderer(); | ||||
|     } | ||||
|  | @ -40,15 +41,15 @@ public class PDFFileRenderer implements Renderer<Path> { | |||
|                 .exists(File::canWrite); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public PDFFileRenderer setTargetFile(@NonNull final Path targetFile) { | ||||
|     @NotNull | ||||
|     public PDFFileRenderer setTargetFile(@NotNull final Path targetFile) { | ||||
|         this.targetFile = Option.of(targetFile); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public Path render(@NonNull final Maze maze) { | ||||
|     public Path render(@NotNull final Maze maze) { | ||||
|         if (!this.isTargetFileDefinedAndWritable()) { | ||||
|             try { | ||||
|                 Files.createFile(this.targetFile.get()); | ||||
|  |  | |||
|  | @ -5,12 +5,12 @@ import ch.fritteli.maze.generator.model.Maze; | |||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import io.vavr.control.Option; | ||||
| import lombok.AccessLevel; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| @RequiredArgsConstructor(access = AccessLevel.PACKAGE) | ||||
| class Generator { | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private final Maze maze; | ||||
|     private final boolean renderSolution; | ||||
|     private int x = 0; | ||||
|  | @ -34,21 +34,12 @@ class Generator { | |||
|         final Option<Tile> rightTile = this.maze.getTileAt(this.x + 1, this.y); | ||||
|         final Option<Tile> bottomTile = this.maze.getTileAt(this.x, this.y + 1); | ||||
|         final Option<Tile> leftTile = this.maze.getTileAt(this.x - 1, this.y); | ||||
|         final String s; | ||||
|         switch (this.line) { | ||||
|             case 0: | ||||
|                 s = this.renderTopLine(currentTile, leftTile, topTile); | ||||
|                 break; | ||||
|             case 1: | ||||
|                 s = this.renderCenterLine(currentTile, topTile, rightTile, bottomTile, leftTile); | ||||
|                 break; | ||||
|             case 2: | ||||
|                 s = this.renderBottomLine(currentTile, leftTile); | ||||
|                 break; | ||||
|             default: | ||||
|                 s = ""; | ||||
|                 break; | ||||
|         } | ||||
|         final String s = switch (this.line) { | ||||
|             case 0 -> this.renderTopLine(currentTile, leftTile, topTile); | ||||
|             case 1 -> this.renderCenterLine(currentTile, topTile, rightTile, bottomTile, leftTile); | ||||
|             case 2 -> this.renderBottomLine(currentTile, leftTile); | ||||
|             default -> ""; | ||||
|         }; | ||||
|         this.prepareNextStep(); | ||||
|         return s; | ||||
|     } | ||||
|  | @ -76,7 +67,7 @@ class Generator { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private String renderTopLine(@NonNull final Tile currentTile, @NonNull final Option<Tile> leftTile, @NonNull final Option<Tile> topTile) { | ||||
|     private String renderTopLine(@NotNull final Tile currentTile, @NotNull final Option<Tile> leftTile, @NotNull final Option<Tile> topTile) { | ||||
|         final CharDefinition charDef1 = new CharDefinition(); | ||||
|         final CharDefinition charDef2 = new CharDefinition(); | ||||
|         final CharDefinition charDef3 = new CharDefinition(); | ||||
|  | @ -112,11 +103,11 @@ class Generator { | |||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     private String renderCenterLine(@NonNull final Tile currentTile, | ||||
|                                     @NonNull final Option<Tile> topTile, | ||||
|                                     @NonNull final Option<Tile> rightTile, | ||||
|                                     @NonNull final Option<Tile> bottomTile, | ||||
|                                     @NonNull final Option<Tile> leftTile) { | ||||
|     private String renderCenterLine(@NotNull final Tile currentTile, | ||||
|                                     @NotNull final Option<Tile> topTile, | ||||
|                                     @NotNull final Option<Tile> rightTile, | ||||
|                                     @NotNull final Option<Tile> bottomTile, | ||||
|                                     @NotNull final Option<Tile> leftTile) { | ||||
|         final CharDefinition charDef1 = new CharDefinition(); | ||||
|         final CharDefinition charDef2 = new CharDefinition(); | ||||
|         final CharDefinition charDef3 = new CharDefinition(); | ||||
|  | @ -160,7 +151,7 @@ class Generator { | |||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     private String renderBottomLine(@NonNull final Tile currentTile, @NonNull final Option<Tile> leftTile) { | ||||
|     private String renderBottomLine(@NotNull final Tile currentTile, @NotNull final Option<Tile> leftTile) { | ||||
|         String result; | ||||
|         final CharDefinition charDef1 = new CharDefinition(); | ||||
|         final CharDefinition charDef2 = new CharDefinition(); | ||||
|  | @ -193,15 +184,15 @@ class Generator { | |||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     private boolean hasWallAt(@NonNull final Option<Tile> tile, @NonNull final Direction direction) { | ||||
|     private boolean hasWallAt(@NotNull final Option<Tile> tile, @NotNull final Direction direction) { | ||||
|         return tile.map(t -> t.hasWallAt(direction)).getOrElse(false); | ||||
|     } | ||||
| 
 | ||||
|     private boolean isSolution(@NonNull final Tile tile) { | ||||
|         return this.renderSolution && tile != null && tile.isSolution(); | ||||
|     private boolean isSolution(@NotNull final Tile tile) { | ||||
|         return this.renderSolution && tile.isSolution(); | ||||
|     } | ||||
| 
 | ||||
|     private boolean isSolution(@NonNull final Option<Tile> tile) { | ||||
|     private boolean isSolution(@NotNull final Option<Tile> tile) { | ||||
|         return this.renderSolution && tile.map(Tile::isSolution).getOrElse(false); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ package ch.fritteli.maze.generator.renderer.text; | |||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.renderer.Renderer; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public class TextRenderer implements Renderer<String> { | ||||
|     private boolean renderSolution; | ||||
|  | @ -11,20 +11,20 @@ public class TextRenderer implements Renderer<String> { | |||
|         this.renderSolution = false; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static TextRenderer newInstance() { | ||||
|         return new TextRenderer(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public TextRenderer setRenderSolution(final boolean renderSolution) { | ||||
|         this.renderSolution = renderSolution; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public String render(@NonNull final Maze maze) { | ||||
|     public String render(@NotNull final Maze maze) { | ||||
|         if (maze.getWidth() == 0 || maze.getHeight() == 0) { | ||||
|             return ""; | ||||
|         } | ||||
|  |  | |||
|  | @ -6,23 +6,22 @@ import ch.fritteli.maze.generator.renderer.text.TextRenderer; | |||
| import io.vavr.collection.List; | ||||
| import io.vavr.control.Option; | ||||
| import io.vavr.control.Try; | ||||
| import lombok.NonNull; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.NoSuchElementException; | ||||
| 
 | ||||
| @Slf4j | ||||
| public class TextFileRenderer implements Renderer<List<Path>> { | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private static final TextRenderer TEXT_RENDERER = TextRenderer.newInstance(); | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private Option<Path> targetMazeFile; | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     private Option<Path> targetSolutionFile; | ||||
| 
 | ||||
|     private TextFileRenderer() { | ||||
|  | @ -42,7 +41,7 @@ public class TextFileRenderer implements Renderer<List<Path>> { | |||
|                 .toOption(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public static TextFileRenderer newInstance() { | ||||
|         return new TextFileRenderer(); | ||||
|     } | ||||
|  | @ -59,21 +58,21 @@ public class TextFileRenderer implements Renderer<List<Path>> { | |||
|                 .exists(File::canWrite); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public TextFileRenderer setTargetMazeFile(@NonNull final Path targetMazeFile) { | ||||
|     @NotNull | ||||
|     public TextFileRenderer setTargetMazeFile(@NotNull final Path targetMazeFile) { | ||||
|         this.targetMazeFile = Option.of(targetMazeFile); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public TextFileRenderer setTargetSolutionFile(@NonNull final Path targetSolutionFile) { | ||||
|     @NotNull | ||||
|     public TextFileRenderer setTargetSolutionFile(@NotNull final Path targetSolutionFile) { | ||||
|         this.targetSolutionFile = Option.of(targetSolutionFile); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public List<Path> render(@NonNull final Maze maze) { | ||||
|     public List<Path> render(@NotNull final Maze maze) { | ||||
|         if (!this.isTargetMazeFileDefinedAndWritable()) { | ||||
|             try { | ||||
|                 Files.createFile(this.targetMazeFile.get()); | ||||
|  | @ -98,12 +97,12 @@ public class TextFileRenderer implements Renderer<List<Path>> { | |||
|         final Path targetMazeFile = this.targetMazeFile.get(); | ||||
|         final Path targetSolutionFile = this.targetSolutionFile.get(); | ||||
|         try { | ||||
|             Files.write(targetMazeFile, text.getBytes(StandardCharsets.UTF_8)); | ||||
|             Files.writeString(targetMazeFile, text); | ||||
|         } catch (IOException e) { | ||||
|             log.error("Failed writing to file " + targetMazeFile.normalize(), e); | ||||
|         } | ||||
|         try { | ||||
|             Files.write(targetSolutionFile, solution.getBytes(StandardCharsets.UTF_8)); | ||||
|             Files.writeString(targetSolutionFile, solution); | ||||
|         } catch (IOException e) { | ||||
|             log.error("Failed writing to file " + targetSolutionFile.normalize()); | ||||
|         } | ||||
|  |  | |||
|  | @ -1,18 +1,19 @@ | |||
| package ch.fritteli.maze.generator.serialization; | ||||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.io.ByteArrayInputStream; | ||||
| import lombok.NonNull; | ||||
| 
 | ||||
| public abstract class AbstractMazeInputStream extends ByteArrayInputStream { | ||||
| 
 | ||||
|     public AbstractMazeInputStream(@NonNull final byte[] buf) { | ||||
|     public AbstractMazeInputStream(@NotNull final byte[] buf) { | ||||
|         super(buf); | ||||
|     } | ||||
| 
 | ||||
|     public abstract void checkHeader(); | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     public abstract Maze readMazeData(); | ||||
| 
 | ||||
|     public byte readByte() { | ||||
|  |  | |||
|  | @ -1,14 +1,15 @@ | |||
| package ch.fritteli.maze.generator.serialization; | ||||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import lombok.NonNull; | ||||
| 
 | ||||
| public abstract class AbstractMazeOutputStream extends ByteArrayOutputStream { | ||||
| 
 | ||||
|     public abstract void writeHeader(); | ||||
| 
 | ||||
|     public abstract void writeMazeData(@NonNull final Maze maze); | ||||
|     public abstract void writeMazeData(@NotNull final Maze maze); | ||||
| 
 | ||||
|     public void writeByte(final byte value) { | ||||
|         this.write(value); | ||||
|  |  | |||
|  | @ -3,11 +3,11 @@ package ch.fritteli.maze.generator.serialization.v1; | |||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import ch.fritteli.maze.generator.serialization.AbstractMazeInputStream; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public class MazeInputStreamV1 extends AbstractMazeInputStream { | ||||
| 
 | ||||
|     public MazeInputStreamV1(@NonNull final byte[] buf) { | ||||
|     public MazeInputStreamV1(@NotNull final byte[] buf) { | ||||
|         super(buf); | ||||
|     } | ||||
| 
 | ||||
|  | @ -27,7 +27,7 @@ public class MazeInputStreamV1 extends AbstractMazeInputStream { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public Maze readMazeData() { | ||||
|         final long randomSeed = this.readLong(); | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ package ch.fritteli.maze.generator.serialization.v1; | |||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import ch.fritteli.maze.generator.serialization.AbstractMazeOutputStream; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public class MazeOutputStreamV1 extends AbstractMazeOutputStream { | ||||
| 
 | ||||
|  | @ -15,7 +15,7 @@ public class MazeOutputStreamV1 extends AbstractMazeOutputStream { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void writeMazeData(@NonNull final Maze maze) { | ||||
|     public void writeMazeData(@NotNull final Maze maze) { | ||||
|         final long randomSeed = maze.getRandomSeed(); | ||||
|         final int width = maze.getWidth(); | ||||
|         final int height = maze.getHeight(); | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ package ch.fritteli.maze.generator.serialization.v1; | |||
| import ch.fritteli.maze.generator.model.Direction; | ||||
| import ch.fritteli.maze.generator.model.Maze; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import lombok.NonNull; | ||||
| import lombok.experimental.UtilityClass; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
|  | @ -62,8 +62,8 @@ public class SerializerDeserializerV1 { | |||
|      * @param maze The {@link Maze} to be serialized. | ||||
|      * @return The resulting byte array. | ||||
|      */ | ||||
|     @NonNull | ||||
|     public byte[] serialize(@NonNull final Maze maze) { | ||||
|     @NotNull | ||||
|     public byte[] serialize(@NotNull final Maze maze) { | ||||
|         final MazeOutputStreamV1 stream = new MazeOutputStreamV1(); | ||||
|         stream.writeHeader(); | ||||
|         stream.writeMazeData(maze); | ||||
|  | @ -76,38 +76,38 @@ public class SerializerDeserializerV1 { | |||
|      * @param bytes The byte array to be deserialized. | ||||
|      * @return An instance of {@link Maze}. | ||||
|      */ | ||||
|     @NonNull | ||||
|     public Maze deserialize(@NonNull final byte[] bytes) { | ||||
|     @NotNull | ||||
|     public Maze deserialize(@NotNull final byte[] bytes) { | ||||
|         final MazeInputStreamV1 stream = new MazeInputStreamV1(bytes); | ||||
|         stream.checkHeader(); | ||||
|         return stream.readMazeData(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     Maze createMaze(@NonNull final Tile[][] field, final int width, final int height, final long randomSeed) { | ||||
|     @NotNull | ||||
|     Maze createMaze(@NotNull final Tile[][] field, final int width, final int height, final long randomSeed) { | ||||
|         try { | ||||
|             final Constructor<Maze> constructor = Maze.class.getDeclaredConstructor(Tile[][].class, Integer.TYPE, Integer.TYPE, Long.TYPE); | ||||
|             constructor.setAccessible(true); | ||||
|             return constructor.newInstance(field, width, height, randomSeed); | ||||
|         } catch (@NonNull final NoSuchMethodException | IllegalAccessException | InstantiationException | | ||||
|         } catch (@NotNull final NoSuchMethodException | IllegalAccessException | InstantiationException | | ||||
|                                 InvocationTargetException e) { | ||||
|             throw new RuntimeException("Can not deserialize Maze from maze data.", e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private Tile createTile(@NonNull final EnumSet<Direction> walls, boolean solution) { | ||||
|     @NotNull | ||||
|     private Tile createTile(@NotNull final EnumSet<Direction> walls, boolean solution) { | ||||
|         try { | ||||
|             final Constructor<Tile> constructor = Tile.class.getDeclaredConstructor(EnumSet.class, Boolean.TYPE); | ||||
|             constructor.setAccessible(true); | ||||
|             return constructor.newInstance(walls, solution); | ||||
|         } catch (@NonNull final NoSuchMethodException | InstantiationException | IllegalAccessException | | ||||
|         } catch (@NotNull final NoSuchMethodException | InstantiationException | IllegalAccessException | | ||||
|                                 InvocationTargetException e) { | ||||
|             throw new RuntimeException("Can not deserialize Tile from maze data.", e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     byte getBitmaskForTile(@NonNull final Tile tile) { | ||||
|     byte getBitmaskForTile(@NotNull final Tile tile) { | ||||
|         byte bitmask = 0; | ||||
|         if (tile.hasWallAt(Direction.TOP)) { | ||||
|             bitmask |= TOP_BIT; | ||||
|  | @ -127,7 +127,7 @@ public class SerializerDeserializerV1 { | |||
|         return bitmask; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     Tile getTileForBitmask(final byte bitmask) { | ||||
|         final EnumSet<Direction> walls = EnumSet.noneOf(Direction.class); | ||||
|         if ((bitmask & TOP_BIT) == TOP_BIT) { | ||||
|  |  | |||
|  | @ -4,11 +4,11 @@ import ch.fritteli.maze.generator.model.Maze; | |||
| import ch.fritteli.maze.generator.model.Position; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import ch.fritteli.maze.generator.serialization.AbstractMazeInputStream; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public class MazeInputStreamV2 extends AbstractMazeInputStream { | ||||
| 
 | ||||
|     public MazeInputStreamV2(@NonNull final byte[] buf) { | ||||
|     public MazeInputStreamV2(@NotNull final byte[] buf) { | ||||
|         super(buf); | ||||
|     } | ||||
| 
 | ||||
|  | @ -31,7 +31,7 @@ public class MazeInputStreamV2 extends AbstractMazeInputStream { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     @Override | ||||
|     public Maze readMazeData() { | ||||
|         // 03..06  width (int) | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import ch.fritteli.maze.generator.model.Maze; | |||
| import ch.fritteli.maze.generator.model.Position; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import ch.fritteli.maze.generator.serialization.AbstractMazeOutputStream; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| public class MazeOutputStreamV2 extends AbstractMazeOutputStream { | ||||
| 
 | ||||
|  | @ -19,7 +19,7 @@ public class MazeOutputStreamV2 extends AbstractMazeOutputStream { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void writeMazeData(@NonNull final Maze maze) { | ||||
|     public void writeMazeData(@NotNull final Maze maze) { | ||||
|         // 03..06  width (int) | ||||
|         // 07..10  height (int) | ||||
|         // 11..14  start-x (int) | ||||
|  | @ -35,10 +35,10 @@ public class MazeOutputStreamV2 extends AbstractMazeOutputStream { | |||
|         final Position end = maze.getEnd(); | ||||
|         this.writeInt(width); | ||||
|         this.writeInt(height); | ||||
|         this.writeInt(start.getX()); | ||||
|         this.writeInt(start.getY()); | ||||
|         this.writeInt(end.getX()); | ||||
|         this.writeInt(end.getY()); | ||||
|         this.writeInt(start.x()); | ||||
|         this.writeInt(start.y()); | ||||
|         this.writeInt(end.x()); | ||||
|         this.writeInt(end.y()); | ||||
|         this.writeLong(randomSeed); | ||||
| 
 | ||||
|         for (int y = 0; y < height; y++) { | ||||
|  |  | |||
|  | @ -4,8 +4,8 @@ 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 lombok.NonNull; | ||||
| import lombok.experimental.UtilityClass; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| 
 | ||||
| import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
|  | @ -67,8 +67,8 @@ public class SerializerDeserializerV2 { | |||
|      * @param maze The {@link Maze} to be serialized. | ||||
|      * @return The resulting byte array. | ||||
|      */ | ||||
|     @NonNull | ||||
|     public byte[] serialize(@NonNull final Maze maze) { | ||||
|     @NotNull | ||||
|     public byte[] serialize(@NotNull final Maze maze) { | ||||
|         final MazeOutputStreamV2 stream = new MazeOutputStreamV2(); | ||||
|         stream.writeHeader(); | ||||
|         stream.writeMazeData(maze); | ||||
|  | @ -81,38 +81,38 @@ public class SerializerDeserializerV2 { | |||
|      * @param bytes The byte array to be deserialized. | ||||
|      * @return An instance of {@link Maze}. | ||||
|      */ | ||||
|     @NonNull | ||||
|     public Maze deserialize(@NonNull final byte[] bytes) { | ||||
|     @NotNull | ||||
|     public Maze deserialize(@NotNull final byte[] bytes) { | ||||
|         final MazeInputStreamV2 stream = new MazeInputStreamV2(bytes); | ||||
|         stream.checkHeader(); | ||||
|         return stream.readMazeData(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     Maze createMaze(@NonNull final Tile[][] field, final int width, final int height, @NonNull final Position start, @NonNull final Position end, final long randomSeed) { | ||||
|     @NotNull | ||||
|     Maze createMaze(@NotNull final Tile[][] field, final int width, final int height, @NotNull final Position start, @NotNull final Position end, final long randomSeed) { | ||||
|         try { | ||||
|             final Constructor<Maze> constructor = Maze.class.getDeclaredConstructor(Tile[][].class, Integer.TYPE, Integer.TYPE, Position.class, Position.class, Long.TYPE); | ||||
|             constructor.setAccessible(true); | ||||
|             return constructor.newInstance(field, width, height, start, end, randomSeed); | ||||
|         } catch (@NonNull final NoSuchMethodException | IllegalAccessException | InstantiationException | | ||||
|         } catch (@NotNull final NoSuchMethodException | IllegalAccessException | InstantiationException | | ||||
|                                 InvocationTargetException e) { | ||||
|             throw new RuntimeException("Can not deserialize Maze from maze data.", e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private Tile createTile(@NonNull final EnumSet<Direction> walls, boolean solution) { | ||||
|     @NotNull | ||||
|     private Tile createTile(@NotNull final EnumSet<Direction> walls, boolean solution) { | ||||
|         try { | ||||
|             final Constructor<Tile> constructor = Tile.class.getDeclaredConstructor(EnumSet.class, Boolean.TYPE); | ||||
|             constructor.setAccessible(true); | ||||
|             return constructor.newInstance(walls, solution); | ||||
|         } catch (@NonNull final NoSuchMethodException | InstantiationException | IllegalAccessException | | ||||
|         } catch (@NotNull final NoSuchMethodException | InstantiationException | IllegalAccessException | | ||||
|                                 InvocationTargetException e) { | ||||
|             throw new RuntimeException("Can not deserialize Tile from maze data.", e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     byte getBitmaskForTile(@NonNull final Tile tile) { | ||||
|     byte getBitmaskForTile(@NotNull final Tile tile) { | ||||
|         byte bitmask = 0; | ||||
|         if (tile.hasWallAt(Direction.TOP)) { | ||||
|             bitmask |= TOP_BIT; | ||||
|  | @ -132,7 +132,7 @@ public class SerializerDeserializerV2 { | |||
|         return bitmask; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @NotNull | ||||
|     Tile getTileForBitmask(final byte bitmask) { | ||||
|         final EnumSet<Direction> walls = EnumSet.noneOf(Direction.class); | ||||
|         if ((bitmask & TOP_BIT) == TOP_BIT) { | ||||
|  |  | |||
|  | @ -1,13 +1,12 @@ | |||
| package ch.fritteli.maze.generator.model; | ||||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Direction; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| class DirectionTest { | ||||
|     @Test | ||||
|     void invert() { | ||||
|     void shouldInvertTheDirection() { | ||||
|         assertThat(Direction.TOP.invert()).isEqualTo(Direction.BOTTOM); | ||||
|         assertThat(Direction.RIGHT.invert()).isEqualTo(Direction.LEFT); | ||||
|         assertThat(Direction.BOTTOM.invert()).isEqualTo(Direction.TOP); | ||||
|  |  | |||
|  | @ -7,14 +7,24 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; | |||
| 
 | ||||
| class MazeTest { | ||||
|     @Test | ||||
|     void testConstruct() { | ||||
|         // act / assert on simple cases | ||||
|     void shouldNotAccept0AsWidthOrHeight() { | ||||
|         // act / assert | ||||
|         assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new Maze(0, 0)) | ||||
|                 .withMessage("width and height must be >1"); | ||||
|         assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new Maze(0, 0, 0)) | ||||
|                 .withMessage("width and height must be >1"); | ||||
|         assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new Maze(0, 5)) | ||||
|                 .withMessage("width and height must be >1"); | ||||
|         assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new Maze(0, 5, 0)) | ||||
|                 .withMessage("width and height must be >1"); | ||||
|         assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new Maze(5, 0)) | ||||
|                 .withMessage("width and height must be >1"); | ||||
|         assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new Maze(5, 0, 0)) | ||||
|                 .withMessage("width and height must be >1"); | ||||
|     } | ||||
| 
 | ||||
|         // now for the real work: | ||||
|     @Test | ||||
|     void testConstruct() { | ||||
|         // arrange | ||||
|         final Maze sut = new Maze(2, 3, 5); | ||||
| 
 | ||||
|  | @ -23,7 +33,9 @@ class MazeTest { | |||
|                 .returns(2, Maze::getWidth) | ||||
|                 .returns(3, Maze::getHeight) | ||||
|                 .returns(5L, Maze::getRandomSeed) | ||||
|                 .returns(new Position(0, 0), Maze::getStart) | ||||
|                 .returns(new Position(1, 2), Maze::getEnd); | ||||
|                 .satisfies( | ||||
|                         maze -> assertThat(maze.getStart()).isEqualTo(new Position(0, 0)), | ||||
|                         maze -> assertThat(maze.getEnd()).isEqualTo(new Position(1, 2)) | ||||
|                 ); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,14 +1,12 @@ | |||
| package ch.fritteli.maze.generator.model; | ||||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Direction; | ||||
| import ch.fritteli.maze.generator.model.Position; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| class PositionTest { | ||||
|     @Test | ||||
|     void move() { | ||||
|     void shouldMoveToCorrectNeighborPosition() { | ||||
|         // arrange | ||||
|         final Position sut = new Position(0, 0); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,5 @@ | |||
| package ch.fritteli.maze.generator.model; | ||||
| 
 | ||||
| import ch.fritteli.maze.generator.model.Direction; | ||||
| import ch.fritteli.maze.generator.model.Tile; | ||||
| import io.vavr.control.Option; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
|  | @ -11,21 +9,20 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
| 
 | ||||
| class TileTest { | ||||
|     @Test | ||||
|     void testConstruct() { | ||||
|     void shouldConstructATileWithDefaultValues() { | ||||
|         // arrange / act | ||||
|         final Tile sut = new Tile(); | ||||
| 
 | ||||
|         //assert | ||||
|         assertThat(sut) | ||||
|                 .returns(true, v -> v.hasWallAt(Direction.TOP)) | ||||
|                 .returns(true, v -> v.hasWallAt(Direction.RIGHT)) | ||||
|                 .returns(true, v -> v.hasWallAt(Direction.BOTTOM)) | ||||
|                 .returns(true, v -> v.hasWallAt(Direction.LEFT)) | ||||
|                 .returns(false, Tile::isSolution); | ||||
|         assertThat(sut.hasWallAt(Direction.TOP)).isTrue(); | ||||
|         assertThat(sut.hasWallAt(Direction.RIGHT)).isTrue(); | ||||
|         assertThat(sut.hasWallAt(Direction.BOTTOM)).isTrue(); | ||||
|         assertThat(sut.hasWallAt(Direction.LEFT)).isTrue(); | ||||
|         assertThat(sut.isSolution()).isFalse(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void testDigFrom() { | ||||
|     void tileCanBeDugIntoOnlyOnce() { | ||||
|         // arrange | ||||
|         final Tile sut = new Tile(); | ||||
| 
 | ||||
|  | @ -45,29 +42,27 @@ class TileTest { | |||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void testDigTo() { | ||||
|     void canDigToDirectionOnlyOnce() { | ||||
|         // arrange | ||||
|         final Tile sut = new Tile(); | ||||
| 
 | ||||
|         // act / assert | ||||
|         assertThat(sut) | ||||
|                 .returns(true, v -> v.digTo(Direction.TOP)) | ||||
|                 .returns(true, v -> v.digTo(Direction.RIGHT)) | ||||
|                 .returns(true, v -> v.digTo(Direction.BOTTOM)) | ||||
|                 .returns(true, v -> v.digTo(Direction.LEFT)) | ||||
|         assertThat(sut.digTo(Direction.TOP)).isTrue(); | ||||
|         assertThat(sut.digTo(Direction.RIGHT)).isTrue(); | ||||
|         assertThat(sut.digTo(Direction.BOTTOM)).isTrue(); | ||||
|         assertThat(sut.digTo(Direction.LEFT)).isTrue(); | ||||
|         // digging a second time does not succeed | ||||
|                 .returns(false, v -> v.digTo(Direction.LEFT)); | ||||
|         assertThat(sut.digTo(Direction.LEFT)).isFalse(); | ||||
| 
 | ||||
|         // assert | ||||
|         assertThat(sut) | ||||
|                 .returns(false, v -> v.hasWallAt(Direction.TOP)) | ||||
|                 .returns(false, v -> v.hasWallAt(Direction.RIGHT)) | ||||
|                 .returns(false, v -> v.hasWallAt(Direction.BOTTOM)) | ||||
|                 .returns(false, v -> v.hasWallAt(Direction.LEFT)); | ||||
|         assertThat(sut.hasWallAt(Direction.TOP)).isFalse(); | ||||
|         assertThat(sut.hasWallAt(Direction.RIGHT)).isFalse(); | ||||
|         assertThat(sut.hasWallAt(Direction.BOTTOM)).isFalse(); | ||||
|         assertThat(sut.hasWallAt(Direction.LEFT)).isFalse(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void testPreventDiggingToOrFrom() { | ||||
|     void canNotDigToOrFromDirectionWhenPrevented() { | ||||
|         // arrange | ||||
|         final Tile sut = new Tile(); | ||||
| 
 | ||||
|  | @ -75,10 +70,11 @@ class TileTest { | |||
|         sut.preventDiggingToOrFrom(Direction.LEFT); | ||||
| 
 | ||||
|         // assert | ||||
|         assertThat(sut) | ||||
|                 .returns(false, v -> v.digTo(Direction.LEFT)) | ||||
|                 .returns(false, v -> v.digFrom(Direction.LEFT)) | ||||
|                 .returns(true, v -> v.hasWallAt(Direction.LEFT)); | ||||
|         assertThat(sut.digTo(Direction.LEFT)).isFalse(); | ||||
|         assertThat(sut.digFrom(Direction.LEFT)).isFalse(); | ||||
|         assertThat(sut.hasWallAt(Direction.LEFT)).isTrue(); | ||||
|         // Digging in another direction is still permitted | ||||
|         assertThat(sut.digTo(Direction.RIGHT)).isTrue(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue