168 lines
7.5 KiB
Java
168 lines
7.5 KiB
Java
package ch.fritteli.maze.generator.renderer.html;
|
|
|
|
import ch.fritteli.maze.generator.model.Maze;
|
|
import ch.fritteli.maze.generator.renderer.Renderer;
|
|
import lombok.NonNull;
|
|
|
|
public class HTMLRenderer implements Renderer<String> {
|
|
|
|
private static final String POSTAMBLE = "<script>"
|
|
+ "let userPath = [];"
|
|
+ "const DIR_UNDEF = -1;"
|
|
+ "const DIR_SAME = 0;"
|
|
+ "const DIR_UP = 1;"
|
|
+ "const DIR_RIGHT = 2;"
|
|
+ "const DIR_DOWN = 3;"
|
|
+ "const DIR_LEFT = 4;"
|
|
+ "function getCoords(cell) {"
|
|
+ " return {"
|
|
+ " x: cell.cellIndex,"
|
|
+ " y: cell.parentElement.rowIndex"
|
|
+ " };"
|
|
+ "}"
|
|
+ "function distance(prev, next) {"
|
|
+ " return Math.abs(prev.x - next.x) + Math.abs(prev.y - next.y);"
|
|
+ "}"
|
|
+ "function direction(prev, next) {"
|
|
+ " const dist = distance(prev, next);"
|
|
+ " if (dist === 0) {"
|
|
+ " return DIR_SAME;"
|
|
+ " }"
|
|
+ " if (dist !== 1) {"
|
|
+ " return DIR_UNDEF;"
|
|
+ " }"
|
|
+ " if (next.x === prev.x) {"
|
|
+ " if (next.y === prev.y + 1) {"
|
|
+ " return DIR_DOWN;"
|
|
+ " }"
|
|
+ " return DIR_UP;"
|
|
+ " }"
|
|
+ " if (next.x === prev.x + 1) {"
|
|
+ " return DIR_RIGHT;"
|
|
+ " }"
|
|
+ " return DIR_LEFT;"
|
|
+ "}"
|
|
+ "(function () {"
|
|
+ " const labyrinthTable = document.getElementById(\"labyrinth\");"
|
|
+ " const labyrinthCells = labyrinthTable.getElementsByTagName(\"td\");"
|
|
+ " const start = {x: 0, y: 0};"
|
|
+ " const end = {"
|
|
+ " x: labyrinthTable.getElementsByTagName(\"tr\")[0].getElementsByTagName(\"td\").length - 1,"
|
|
+ " y: labyrinthTable.getElementsByTagName(\"tr\").length - 1"
|
|
+ " };"
|
|
+ " for (let i = 0; i < labyrinthCells.length; i++) {"
|
|
+ " let cell = labyrinthCells.item(i);"
|
|
+ " cell.onclick = (event) => {"
|
|
+ " let target = event.target;"
|
|
+ " const coords = getCoords(target);"
|
|
+ " if (coords.x === end.x && coords.y === end.y) {"
|
|
+ " alert(\"HOORAY! You did it! Congratulations!\")"
|
|
+ " }"
|
|
+ " if (userPath.length === 0) {"
|
|
+ " if (coords.x === start.x && coords.y === start.y) {"
|
|
+ " userPath.push(coords);"
|
|
+ " target.classList.toggle(\"user\");"
|
|
+ " }"
|
|
+ " } else {"
|
|
+ " const dir = direction(userPath[userPath.length - 1], coords);"
|
|
+ " switch (dir) {"
|
|
+ " case DIR_UNDEF:"
|
|
+ " return;"
|
|
+ " case DIR_SAME:"
|
|
+ " userPath.pop();"
|
|
+ " target.classList.toggle(\"user\");"
|
|
+ " return;"
|
|
+ " default:"
|
|
+ " if (userPath.find(value => value.x === coords.x && value.y === coords.y)) {"
|
|
+ " return;"
|
|
+ " } else {"
|
|
+ " switch (dir) {"
|
|
+ " case DIR_UP:"
|
|
+ " if (target.classList.contains(\"bottom\")) {"
|
|
+ " return;"
|
|
+ " }"
|
|
+ " break;"
|
|
+ " case DIR_RIGHT:"
|
|
+ " if (target.classList.contains(\"left\")) {"
|
|
+ " return;"
|
|
+ " }"
|
|
+ " break;"
|
|
+ " case DIR_DOWN:"
|
|
+ " if (target.classList.contains(\"top\")) {"
|
|
+ " return;"
|
|
+ " }"
|
|
+ " break;"
|
|
+ " case DIR_LEFT:"
|
|
+ " if (target.classList.contains(\"right\")) {"
|
|
+ " return;"
|
|
+ " }"
|
|
+ " break;"
|
|
+ " }"
|
|
+ " userPath.push(coords);"
|
|
+ " target.classList.toggle(\"user\");"
|
|
+ " return;"
|
|
+ " }"
|
|
+ " }"
|
|
+ " }"
|
|
+ " };"
|
|
+ " }"
|
|
+ "})();"
|
|
+ "</script></body></html>";
|
|
|
|
private HTMLRenderer() {
|
|
}
|
|
|
|
@NonNull
|
|
public static HTMLRenderer newInstance() {
|
|
return new HTMLRenderer();
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public String render(@NonNull final Maze maze) {
|
|
if (maze.getWidth() == 0 || maze.getHeight() == 0) {
|
|
return this.getPreamble(maze) + POSTAMBLE;
|
|
}
|
|
final Generator generator = new Generator(maze);
|
|
final StringBuilder sb = new StringBuilder(this.getPreamble(maze));
|
|
sb.append("<table id=\"labyrinth\">");
|
|
while (generator.hasNext()) {
|
|
sb.append(generator.next());
|
|
}
|
|
sb.append("</table>");
|
|
sb.append(POSTAMBLE);
|
|
return sb.toString();
|
|
}
|
|
|
|
private String getPreamble(@NonNull final Maze maze) {
|
|
return "<!DOCTYPE html><html lang=\"en\">" +
|
|
"<head>" +
|
|
"<title>Maze " + maze.getWidth() + "x" + maze.getHeight() + ", ID " + maze.getRandomSeed() + "</title>" +
|
|
"<meta charset=\"utf-8\">" +
|
|
"<style>" +
|
|
"table{border-collapse:collapse;}" +
|
|
"td{border:0 solid black;height:1em;width:1em;cursor:pointer;}" +
|
|
"td.top{border-top-width:1px;}" +
|
|
"td.right{border-right-width:1px;}" +
|
|
"td.bottom{border-bottom-width:1px;}" +
|
|
"td.left{border-left-width:1px;}" +
|
|
"td.user{background:hotpink;}" +
|
|
"</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 id=\"solutionbox\" type=\"checkbox\" onclick=\"toggleSolution()\"/><label for=\"solutionbox\">show solution</label>";
|
|
}
|
|
}
|