Make the generation of a labyrinth reproducible and refactor the
PDFRenderer a bit.
This commit is contained in:
parent
fd38b141a1
commit
6060a08573
6 changed files with 114 additions and 74 deletions
|
@ -6,33 +6,6 @@ import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
public class HTMLRenderer implements Renderer<String> {
|
public class HTMLRenderer implements Renderer<String> {
|
||||||
private static final String PREAMBLE = "<!DOCTYPE html><html lang=\"en\">" +
|
|
||||||
"<head>" +
|
|
||||||
"<title>Labyrinth</title>" +
|
|
||||||
"<meta charset=\"utf-8\">" +
|
|
||||||
"<style>" +
|
|
||||||
"table{border-collapse:collapse;}" +
|
|
||||||
"td{border:0 solid black;height:1em;width:1em;}" +
|
|
||||||
"td.top{border-top-width:1px;}" +
|
|
||||||
"td.right{border-right-width:1px;}" +
|
|
||||||
"td.bottom{border-bottom-width:1px;}" +
|
|
||||||
"td.left{border-left-width:1px;}" +
|
|
||||||
"</style>" +
|
|
||||||
"<script>" +
|
|
||||||
"let solution = false;" +
|
|
||||||
"function toggleSolution() {" +
|
|
||||||
"let stylesheet = document.styleSheets[0];" +
|
|
||||||
"if(solution){" +
|
|
||||||
"stylesheet.deleteRule(0);" +
|
|
||||||
"}else{" +
|
|
||||||
"stylesheet.insertRule(\"td.solution{background-color:lightgray;}\", 0);" +
|
|
||||||
"}" +
|
|
||||||
"solution = !solution;" +
|
|
||||||
"}" +
|
|
||||||
"</script>" +
|
|
||||||
"</head>" +
|
|
||||||
"<body>" +
|
|
||||||
"<input type=\"checkbox\" onclick=\"toggleSolution()\">show solution</input>";
|
|
||||||
private static final String POSTAMBLE = "</body></html>";
|
private static final String POSTAMBLE = "</body></html>";
|
||||||
|
|
||||||
private HTMLRenderer() {
|
private HTMLRenderer() {
|
||||||
|
@ -46,10 +19,10 @@ public class HTMLRenderer implements Renderer<String> {
|
||||||
@NonNull
|
@NonNull
|
||||||
public String render(@NonNull final Labyrinth labyrinth) {
|
public String render(@NonNull final Labyrinth labyrinth) {
|
||||||
if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) {
|
if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) {
|
||||||
return PREAMBLE + POSTAMBLE;
|
return this.getPreamble(labyrinth) + POSTAMBLE;
|
||||||
}
|
}
|
||||||
final Generator generator = new Generator(labyrinth);
|
final Generator generator = new Generator(labyrinth);
|
||||||
final StringBuilder sb = new StringBuilder(PREAMBLE);
|
final StringBuilder sb = new StringBuilder(this.getPreamble(labyrinth));
|
||||||
sb.append("<table>");
|
sb.append("<table>");
|
||||||
while (generator.hasNext()) {
|
while (generator.hasNext()) {
|
||||||
sb.append(generator.next());
|
sb.append(generator.next());
|
||||||
|
@ -59,6 +32,36 @@ public class HTMLRenderer implements Renderer<String> {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getPreamble(@NonNull final Labyrinth labyrinth) {
|
||||||
|
return "<!DOCTYPE html><html lang=\"en\">" +
|
||||||
|
"<head>" +
|
||||||
|
"<title>Labyrinth " + labyrinth.getWidth() + "x" + labyrinth.getHeight() + ", ID " + labyrinth.getRandomSeed() + "</title>" +
|
||||||
|
"<meta charset=\"utf-8\">" +
|
||||||
|
"<style>" +
|
||||||
|
"table{border-collapse:collapse;}" +
|
||||||
|
"td{border:0 solid black;height:1em;width:1em;}" +
|
||||||
|
"td.top{border-top-width:1px;}" +
|
||||||
|
"td.right{border-right-width:1px;}" +
|
||||||
|
"td.bottom{border-bottom-width:1px;}" +
|
||||||
|
"td.left{border-left-width:1px;}" +
|
||||||
|
"</style>" +
|
||||||
|
"<script>" +
|
||||||
|
"let solution = false;" +
|
||||||
|
"function toggleSolution() {" +
|
||||||
|
"let stylesheet = document.styleSheets[0];" +
|
||||||
|
"if(solution){" +
|
||||||
|
"stylesheet.deleteRule(0);" +
|
||||||
|
"}else{" +
|
||||||
|
"stylesheet.insertRule(\"td.solution{background-color:lightgray;}\", 0);" +
|
||||||
|
"}" +
|
||||||
|
"solution = !solution;" +
|
||||||
|
"}" +
|
||||||
|
"</script>" +
|
||||||
|
"</head>" +
|
||||||
|
"<body>" +
|
||||||
|
"<input type=\"checkbox\" onclick=\"toggleSolution()\">show solution</input>";
|
||||||
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
private static class Generator {
|
private static class Generator {
|
||||||
private final Labyrinth labyrinth;
|
private final Labyrinth labyrinth;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import lombok.NonNull;
|
||||||
|
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class Labyrinth {
|
public class Labyrinth {
|
||||||
private final Tile[][] field;
|
private final Tile[][] field;
|
||||||
|
@ -14,13 +15,22 @@ public class Labyrinth {
|
||||||
@Getter
|
@Getter
|
||||||
private final int height;
|
private final int height;
|
||||||
@Getter
|
@Getter
|
||||||
|
private final long randomSeed;
|
||||||
|
private final Random random;
|
||||||
|
@Getter
|
||||||
private final Position start;
|
private final Position start;
|
||||||
@Getter
|
@Getter
|
||||||
private final Position end;
|
private final Position end;
|
||||||
|
|
||||||
public Labyrinth(final int width, final int height) {
|
public Labyrinth(final int width, final int height) {
|
||||||
|
this(width, height, System.nanoTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Labyrinth(final int width, final int height, final long randomSeed) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
this.randomSeed = randomSeed;
|
||||||
|
this.random = new Random(this.randomSeed);
|
||||||
this.field = new Tile[width][height];
|
this.field = new Tile[width][height];
|
||||||
this.start = new Position(0, 0);
|
this.start = new Position(0, 0);
|
||||||
this.end = new Position(this.width - 1, this.height - 1);
|
this.end = new Position(this.width - 1, this.height - 1);
|
||||||
|
@ -94,7 +104,7 @@ public class Labyrinth {
|
||||||
while (!this.positions.isEmpty()) {
|
while (!this.positions.isEmpty()) {
|
||||||
final Position currentPosition = this.positions.peek();
|
final Position currentPosition = this.positions.peek();
|
||||||
final Tile currentTile = Labyrinth.this.getTileAt(currentPosition);
|
final Tile currentTile = Labyrinth.this.getTileAt(currentPosition);
|
||||||
final Option<Direction> directionToDigTo = currentTile.getRandomAvailableDirection();
|
final Option<Direction> directionToDigTo = currentTile.getRandomAvailableDirection(Labyrinth.this.random);
|
||||||
if (directionToDigTo.isDefined()) {
|
if (directionToDigTo.isDefined()) {
|
||||||
final Direction digTo = directionToDigTo.get();
|
final Direction digTo = directionToDigTo.get();
|
||||||
final Direction digFrom = digTo.invert();
|
final Direction digFrom = digTo.invert();
|
||||||
|
|
|
@ -9,17 +9,20 @@ public class Main {
|
||||||
public static void main(@NonNull final String[] args) {
|
public static void main(@NonNull final String[] args) {
|
||||||
int width = 100;
|
int width = 100;
|
||||||
int height = 100;
|
int height = 100;
|
||||||
final Labyrinth labyrinth = new Labyrinth(width, height);
|
final Labyrinth labyrinth = new Labyrinth(width, height/*, 0*/);
|
||||||
final TextRenderer textRenderer = TextRenderer.newInstance();
|
final TextRenderer textRenderer = TextRenderer.newInstance();
|
||||||
final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance();
|
final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance();
|
||||||
final Path userHome = Paths.get(System.getProperty("user.home"));
|
final Path userHome = Paths.get(System.getProperty("user.home"));
|
||||||
|
final String baseFilename = getBaseFilename(labyrinth);
|
||||||
final TextFileRenderer textFileRenderer = TextFileRenderer.newInstance()
|
final TextFileRenderer textFileRenderer = TextFileRenderer.newInstance()
|
||||||
.setTargetLabyrinthFile(userHome.resolve("labyrinth.txt"))
|
.setTargetLabyrinthFile(userHome.resolve(baseFilename + ".txt"))
|
||||||
.setTargetSolutionFile(userHome.resolve("labyrinth-solution.txt"));
|
.setTargetSolutionFile(userHome.resolve(baseFilename + "-solution.txt"));
|
||||||
final HTMLFileRenderer htmlFileRenderer = HTMLFileRenderer.newInstance()
|
final HTMLFileRenderer htmlFileRenderer = HTMLFileRenderer.newInstance()
|
||||||
.setTargetFile(userHome.resolve("labyrinth.html"));
|
.setTargetFile(userHome.resolve(baseFilename + ".html"));
|
||||||
final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance().setTargetFile(userHome.resolve("labyrinth.pdf"));
|
final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance()
|
||||||
|
.setTargetFile(userHome.resolve(baseFilename + ".pdf"));
|
||||||
|
|
||||||
|
System.out.println("Labyrinth-ID: " + labyrinth.getRandomSeed());
|
||||||
// Render Labyrinth to stdout
|
// Render Labyrinth to stdout
|
||||||
System.out.println(textRenderer.render(labyrinth));
|
System.out.println(textRenderer.render(labyrinth));
|
||||||
// Render Labyrinth solution to stdout
|
// Render Labyrinth solution to stdout
|
||||||
|
@ -33,4 +36,8 @@ public class Main {
|
||||||
// Render PDF to file
|
// Render PDF to file
|
||||||
System.out.println(pdfFileRenderer.render(labyrinth));
|
System.out.println(pdfFileRenderer.render(labyrinth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getBaseFilename(@NonNull final Labyrinth labyrinth) {
|
||||||
|
return "labyrinth-" + labyrinth.getWidth() + "x" + labyrinth.getHeight() + "-" + labyrinth.getRandomSeed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ch.fritteli.labyrinth;
|
||||||
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||||
|
@ -35,30 +36,22 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
final float pageHeight = labyrinth.getHeight() * SCALE + 2 * MARGIN;
|
final float pageHeight = labyrinth.getHeight() * SCALE + 2 * MARGIN;
|
||||||
|
|
||||||
final PDDocument pdDocument = new PDDocument();
|
final PDDocument pdDocument = new PDDocument();
|
||||||
|
final PDDocumentInformation info = new PDDocumentInformation();
|
||||||
|
info.setTitle("Labyrinth " + labyrinth.getWidth() + "x" + labyrinth.getHeight() + ", ID " + labyrinth.getRandomSeed());
|
||||||
|
pdDocument.setDocumentInformation(info);
|
||||||
final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
||||||
pdDocument.addPage(page);
|
|
||||||
try (PDPageContentStream pdPageContentStream = new PDPageContentStream(pdDocument, page)) {
|
|
||||||
pdPageContentStream.setLineCapStyle(BasicStroke.CAP_ROUND);
|
|
||||||
pdPageContentStream.setLineJoinStyle(BasicStroke.JOIN_MITER);
|
|
||||||
pdPageContentStream.setLineWidth(1.0f);
|
|
||||||
pdPageContentStream.setStrokingColor(Color.BLACK);
|
|
||||||
pdPageContentStream.setNonStrokingColor(Color.BLACK);
|
|
||||||
this.drawHorizonzalLines(labyrinth, pdPageContentStream);
|
|
||||||
this.drawVerticalLines(labyrinth, pdPageContentStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
final PDPage solution = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
final PDPage solution = new PDPage(new PDRectangle(pageWidth, pageHeight));
|
||||||
|
pdDocument.addPage(page);
|
||||||
pdDocument.addPage(solution);
|
pdDocument.addPage(solution);
|
||||||
try (PDPageContentStream pdPageContentStream = new PDPageContentStream(pdDocument, solution)) {
|
try (final PDPageContentStream labyrinthPageContentStream = new PDPageContentStream(pdDocument, page);
|
||||||
pdPageContentStream.setLineCapStyle(BasicStroke.CAP_ROUND);
|
final PDPageContentStream solutionPageContentStream = new PDPageContentStream(pdDocument, solution)) {
|
||||||
pdPageContentStream.setLineJoinStyle(BasicStroke.JOIN_MITER);
|
setUpPageContentStream(labyrinthPageContentStream);
|
||||||
pdPageContentStream.setLineWidth(1.0f);
|
setUpPageContentStream(solutionPageContentStream);
|
||||||
pdPageContentStream.setStrokingColor(Color.BLACK);
|
this.drawHorizonzalLines(labyrinth, labyrinthPageContentStream);
|
||||||
pdPageContentStream.setNonStrokingColor(Color.BLACK);
|
this.drawVerticalLines(labyrinth, labyrinthPageContentStream);
|
||||||
this.drawHorizonzalLines(labyrinth, pdPageContentStream);
|
this.drawHorizonzalLines(labyrinth, solutionPageContentStream);
|
||||||
this.drawVerticalLines(labyrinth, pdPageContentStream);
|
this.drawVerticalLines(labyrinth, solutionPageContentStream);
|
||||||
this.drawSolution(labyrinth, pdPageContentStream);
|
this.drawSolution(labyrinth, solutionPageContentStream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -72,51 +65,65 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
return output.toByteArray();
|
return output.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setUpPageContentStream(@NonNull final PDPageContentStream pageContentStream) throws IOException {
|
||||||
|
pageContentStream.setLineCapStyle(BasicStroke.CAP_ROUND);
|
||||||
|
pageContentStream.setLineJoinStyle(BasicStroke.JOIN_ROUND);
|
||||||
|
pageContentStream.setLineWidth(1.0f);
|
||||||
|
pageContentStream.setStrokingColor(Color.BLACK);
|
||||||
|
pageContentStream.setNonStrokingColor(Color.BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth,
|
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth,
|
||||||
@NonNull final PDPageContentStream pdPageContentStream) throws IOException {
|
@NonNull final PDPageContentStream pdPageContentStream) throws IOException {
|
||||||
// PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required.
|
// PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required.
|
||||||
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
||||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
|
final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN;
|
||||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x, y);
|
final Tile currentTile = labyrinth.getTileAt(x, y);
|
||||||
|
final float xCoordinate = x * SCALE + MARGIN;
|
||||||
if (currentTile.hasWallAt(Direction.TOP)) {
|
if (currentTile.hasWallAt(Direction.TOP)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.moveTo(xCoordinate, yCoordinate);
|
||||||
isPainting = true;
|
isPainting = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
isPainting = false;
|
isPainting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
final float xCoordinate = labyrinth.getWidth() * SCALE + MARGIN;
|
||||||
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
int y = labyrinth.getHeight();
|
int y = labyrinth.getHeight();
|
||||||
|
final float yCoordinate = /*labyrinthHeight - y * SCALE +*/ MARGIN;
|
||||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x, y - 1);
|
final Tile currentTile = labyrinth.getTileAt(x, y - 1);
|
||||||
|
final float xCoordinate = x * SCALE + MARGIN;
|
||||||
if (currentTile.hasWallAt(Direction.BOTTOM)) {
|
if (currentTile.hasWallAt(Direction.BOTTOM)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.moveTo(xCoordinate, yCoordinate);
|
||||||
isPainting = true;
|
isPainting = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
isPainting = false;
|
isPainting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
final float xCoordinate = labyrinth.getWidth() * SCALE + MARGIN;
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,45 +134,49 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
final float labyrinthHeight = labyrinth.getHeight() * SCALE;
|
||||||
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
for (int x = 0; x < labyrinth.getWidth(); x++) {
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
|
final float xCoordinate = x * SCALE + MARGIN;
|
||||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x, y);
|
final Tile currentTile = labyrinth.getTileAt(x, y);
|
||||||
|
final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN;
|
||||||
if (currentTile.hasWallAt(Direction.LEFT)) {
|
if (currentTile.hasWallAt(Direction.LEFT)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.moveTo(xCoordinate, yCoordinate);
|
||||||
isPainting = true;
|
isPainting = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
isPainting = false;
|
isPainting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, MARGIN);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean isPainting = false;
|
boolean isPainting = false;
|
||||||
int x = labyrinth.getWidth();
|
int x = labyrinth.getWidth();
|
||||||
|
final float xCoordinate = x * SCALE + MARGIN;
|
||||||
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
for (int y = 0; y < labyrinth.getHeight(); y++) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(x - 1, y);
|
final Tile currentTile = labyrinth.getTileAt(x - 1, y);
|
||||||
|
final float yCoordinate = labyrinthHeight - y * SCALE + MARGIN;
|
||||||
if (currentTile.hasWallAt(Direction.RIGHT)) {
|
if (currentTile.hasWallAt(Direction.RIGHT)) {
|
||||||
if (!isPainting) {
|
if (!isPainting) {
|
||||||
pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.moveTo(xCoordinate, yCoordinate);
|
||||||
isPainting = true;
|
isPainting = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
isPainting = false;
|
isPainting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPainting) {
|
if (isPainting) {
|
||||||
pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN);
|
pdPageContentStream.lineTo(xCoordinate, MARGIN);
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,11 +195,14 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition);
|
Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition);
|
||||||
previousPosition = currentPosition;
|
previousPosition = currentPosition;
|
||||||
currentPosition = newCurrent;
|
currentPosition = newCurrent;
|
||||||
pdPageContentStream.lineTo(MARGIN + currentPosition.getX() * SCALE + SCALE / 2, MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2));
|
final float xCoordinate = MARGIN + currentPosition.getX() * SCALE + SCALE / 2;
|
||||||
|
final float yCoordinate = MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2);
|
||||||
|
pdPageContentStream.lineTo(xCoordinate, yCoordinate);
|
||||||
} while (!currentPosition.equals(end));
|
} while (!currentPosition.equals(end));
|
||||||
pdPageContentStream.stroke();
|
pdPageContentStream.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
private Position findNextSolutionPosition(@NonNull final Labyrinth labyrinth, @Nullable final Position previousPosition, @NonNull final Position currentPosition) {
|
private Position findNextSolutionPosition(@NonNull final Labyrinth labyrinth, @Nullable final Position previousPosition, @NonNull final Position currentPosition) {
|
||||||
final Tile currentTile = labyrinth.getTileAt(currentPosition);
|
final Tile currentTile = labyrinth.getTileAt(currentPosition);
|
||||||
for (final Direction direction : Direction.values()) {
|
for (final Direction direction : Direction.values()) {
|
||||||
|
@ -202,7 +216,6 @@ public class PDFRenderer implements Renderer<byte[]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We *SHOULD* never get here. ... famous last words ...
|
throw new IllegalStateException("We *SHOULD* never have gotten here. ... famous last words ...");
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.experimental.FieldDefaults;
|
import lombok.experimental.FieldDefaults;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||||
public class Tile {
|
public class Tile {
|
||||||
final Walls walls = new Walls();
|
final Walls walls = new Walls();
|
||||||
|
@ -42,8 +44,13 @@ public class Tile {
|
||||||
this.walls.set(direction);
|
this.walls.set(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Option<Direction> getRandomAvailableDirection() {
|
public Option<Direction> getRandomAvailableDirection(@NonNull final Random random) {
|
||||||
return Stream.ofAll(this.walls.getUnhardenedSet()).shuffle().headOption();
|
final Stream<Direction> availableDirections = this.walls.getUnhardenedSet();
|
||||||
|
if (availableDirections.isEmpty()) {
|
||||||
|
return Option.none();
|
||||||
|
}
|
||||||
|
final int index = random.nextInt(availableDirections.length());
|
||||||
|
return Option.of(availableDirections.get(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasWallAt(@NonNull final Direction direction) {
|
public boolean hasWallAt(@NonNull final Direction direction) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class Walls {
|
||||||
return this.directions.contains(direction);
|
return this.directions.contains(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterable<Direction> getUnhardenedSet() {
|
public Stream<Direction> getUnhardenedSet() {
|
||||||
return Stream.ofAll(this.directions)
|
return Stream.ofAll(this.directions)
|
||||||
.removeAll(this.hardened);
|
.removeAll(this.hardened);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue