Enable showing/rendering the solution.

This commit is contained in:
Manuel Friedli 2020-10-02 18:07:56 +02:00
parent 0a655bd617
commit c6b8b0e3bd
4 changed files with 83 additions and 23 deletions

View file

@ -1,9 +1,36 @@
package ch.fritteli.labyrinth; package ch.fritteli.labyrinth;
import io.vavr.collection.HashSet;
import io.vavr.collection.Set;
import lombok.NonNull; import lombok.NonNull;
public class HTMLRenderer { public class HTMLRenderer {
private static final String PREAMBLE = "<!DOCTYPE html><html><head><title>Labyrinth</title><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></head><body>"; private static final String PREAMBLE = "<!DOCTYPE html><html lang=\"en\">" +
"<head>" +
"<title>Labyrinth</title>" +
"<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 final Labyrinth labyrinth; private final Labyrinth labyrinth;
private final int width; private final int width;
@ -44,22 +71,31 @@ public class HTMLRenderer {
for (int x = 0; x < this.width; x++) { for (int x = 0; x < this.width; x++) {
final Tile currentTile = this.labyrinth.getTileAt(x, this.y); final Tile currentTile = this.labyrinth.getTileAt(x, this.y);
sb.append("<td class=\""); sb.append("<td class=\"");
if (currentTile.hasWallAt(Direction.TOP)) { sb.append(this.getClasses(currentTile).mkString(" "));
sb.append("top ");
}
if (currentTile.hasWallAt(Direction.RIGHT)) {
sb.append("right ");
}
if (currentTile.hasWallAt(Direction.BOTTOM)) {
sb.append("bottom ");
}
if (currentTile.hasWallAt(Direction.LEFT)) {
sb.append("left ");
}
sb.append("\">&nbsp;</td>"); sb.append("\">&nbsp;</td>");
} }
sb.append("</tr>"); sb.append("</tr>");
this.y++; this.y++;
return sb.toString(); return sb.toString();
} }
private Set<String> getClasses(@NonNull final Tile tile) {
Set<String> result = HashSet.empty();
if (tile.hasWallAt(Direction.TOP)) {
result = result.add("top");
}
if (tile.hasWallAt(Direction.RIGHT)) {
result = result.add("right");
}
if (tile.hasWallAt(Direction.BOTTOM)) {
result = result.add("bottom");
}
if (tile.hasWallAt(Direction.LEFT)) {
result = result.add("left");
}
if (tile.isSolution()) {
result = result.add("solution");
}
return result;
}
} }

View file

@ -13,11 +13,15 @@ public class Labyrinth {
private final int width; private final int width;
@Getter @Getter
private final int height; private final int height;
private final Position start;
private final Position end;
public Labyrinth(final int width, final int height) { public Labyrinth(final int width, final int height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
this.field = new Tile[width][height]; this.field = new Tile[width][height];
this.start = new Position(0, 0);
this.end = new Position(this.width - 1, this.height - 1);
this.initField(); this.initField();
this.generate(); this.generate();
} }
@ -30,6 +34,14 @@ public class Labyrinth {
return this.field[x][y]; return this.field[x][y];
} }
Tile getStartTile() {
return this.getTileAt(this.start);
}
Tile getEndTile() {
return this.getTileAt(this.end);
}
private void initField() { private void initField() {
for (int x = 0; x < this.width; x++) { for (int x = 0; x < this.width; x++) {
this.field[x] = new Tile[this.height]; this.field[x] = new Tile[this.height];
@ -70,11 +82,10 @@ public class Labyrinth {
} }
private void preDig() { private void preDig() {
final Position bottomRight = new Position(Labyrinth.this.width - 1, Labyrinth.this.height - 1); final Tile endTile = Labyrinth.this.getEndTile();
final Tile bottomRightTile = Labyrinth.this.getTileAt(bottomRight); endTile.enableDiggingToOrFrom(Direction.BOTTOM);
bottomRightTile.enableDiggingToOrFrom(Direction.BOTTOM); endTile.digFrom(Direction.BOTTOM);
bottomRightTile.digFrom(Direction.BOTTOM); this.positions.push(Labyrinth.this.end);
this.positions.push(bottomRight);
} }
private void dig() { private void dig() {
@ -90,6 +101,9 @@ public class Labyrinth {
if (currentTile.digTo(digTo) && neighborTile.digFrom(digFrom)) { if (currentTile.digTo(digTo) && neighborTile.digFrom(digFrom)) {
// all ok! // all ok!
this.positions.push(neighborPosition); this.positions.push(neighborPosition);
if (neighborPosition.equals(Labyrinth.this.start)) {
this.markSolution();
}
} else { } else {
// Hm, didn't work. // Hm, didn't work.
currentTile.undigTo(digTo); currentTile.undigTo(digTo);
@ -101,11 +115,14 @@ public class Labyrinth {
} }
} }
private void markSolution() {
this.positions.forEach(position -> Labyrinth.this.getTileAt(position).setSolution());
}
private void postDig() { private void postDig() {
final Position topLeft = new Position(0, 0); final Tile startTile = Labyrinth.this.getStartTile();
final Tile topLeftTile = Labyrinth.this.getTileAt(topLeft); startTile.enableDiggingToOrFrom(Direction.TOP);
topLeftTile.enableDiggingToOrFrom(Direction.TOP); startTile.digTo(Direction.TOP);
topLeftTile.digTo(Direction.TOP);
} }
} }
} }

View file

@ -141,7 +141,7 @@ public class TextRenderer {
charDef2.vertical(); charDef2.vertical();
} }
result = charDef1 + " "; result = charDef1 + (currentTile.isSolution() ? "x" : " ");
if (this.x == this.width - 1) { if (this.x == this.width - 1) {
result += charDef2 + "\n"; result += charDef2 + "\n";

View file

@ -3,6 +3,7 @@ package ch.fritteli.labyrinth;
import io.vavr.collection.Stream; import io.vavr.collection.Stream;
import io.vavr.control.Option; import io.vavr.control.Option;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
@ -10,6 +11,8 @@ import lombok.experimental.FieldDefaults;
public class Tile { public class Tile {
final Walls walls = new Walls(); final Walls walls = new Walls();
boolean visited = false; boolean visited = false;
@Getter
boolean solution = false;
public Tile() { public Tile() {
this.walls.setAll(); this.walls.setAll();
@ -46,4 +49,8 @@ public class Tile {
public boolean hasWallAt(@NonNull final Direction direction) { public boolean hasWallAt(@NonNull final Direction direction) {
return this.walls.isSet(direction); return this.walls.isSet(direction);
} }
public void setSolution() {
this.solution = true;
}
} }