151 lines
6.0 KiB
Java
151 lines
6.0 KiB
Java
package puzzle;
|
|
import java.io.IOException;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.time.LocalDate;
|
|
import java.util.Date;
|
|
import java.util.Locale;
|
|
|
|
public class Main {
|
|
// ---------------- CLI ----------------
|
|
|
|
public static class Opts {
|
|
public int seed = 1;
|
|
public int pop = 18;
|
|
public int gens = 100;
|
|
public int tries = 5;
|
|
public String wordsPath = "./out/pool.txt";
|
|
public double minSimplicity = 0; // 0 means no limit
|
|
}
|
|
|
|
static void usage() {
|
|
System.out.println("""
|
|
Usage:
|
|
java SwedishGenerator [--seed N] [--pop N] [--gens N] [--tries N] [--words word-list.txt] [--min-simplicity N.N]
|
|
|
|
Defaults:
|
|
--seed 1
|
|
--pop 18
|
|
--gens 100
|
|
--tries 50
|
|
--words ./out/pool.txt
|
|
--min-simplicity 0 (no limit)
|
|
""");
|
|
}
|
|
|
|
static Opts parseArgs(String[] argv) {
|
|
var out = new Opts();
|
|
for (int i = 0; i < argv.length; i++) {
|
|
String a = argv[i];
|
|
String v = (i + 1 < argv.length) ? argv[i + 1] : null;
|
|
if (a.equals("--help") || a.equals("-h")) {
|
|
usage();
|
|
System.exit(0);
|
|
}
|
|
if (a.equals("--seed")) { out.seed = Integer.parseInt(v); i++; }
|
|
else if (a.equals("--pop")) { out.pop = Integer.parseInt(v); i++; }
|
|
else if (a.equals("--gens")) { out.gens = Integer.parseInt(v); i++; }
|
|
else if (a.equals("--tries")) { out.tries = Integer.parseInt(v); i++; }
|
|
else if (a.equals("--words")) { out.wordsPath = v; i++; }
|
|
else if (a.equals("--min-simplicity")) { out.minSimplicity = Double.parseDouble(v); i++; }
|
|
else throw new IllegalArgumentException("Unknown arg: " + a);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
var opts = parseArgs(args);
|
|
var res = SwedishGenerator.generatePuzzle(opts);
|
|
if (res == null) {
|
|
System.out.println("No solution found within tries.");
|
|
System.exit(1);
|
|
}
|
|
|
|
System.out.println("\n=== GENERATED MASK ===");
|
|
System.out.println(SwedishGenerator.gridToString(res.mask()));
|
|
|
|
System.out.println("\n=== FILLED PUZZLE (RAW) ===");
|
|
System.out.println(SwedishGenerator.gridToString(res.filled().grid));
|
|
|
|
System.out.println("\n=== FILLED PUZZLE (HUMAN) ===");
|
|
System.out.println(SwedishGenerator.renderHuman(res.filled().grid));
|
|
System.out.printf(Locale.ROOT, "Puzzle Simplicity: %.2f%n", res.filled().simplicity);
|
|
var out = ExportFormat.exportFormatFromFilled(res, 1, new ExportFormat.Rewards(50, 2, 1));
|
|
System.out.println("gridv2:");
|
|
for (String row : out.gridv2()) System.out.println(row);
|
|
System.out.println("words: " + out.words().size());
|
|
for (var w : out.words()) {
|
|
var simplicityOfWord =
|
|
System.out.printf("%s %s start=(%d,%d) arrow=(%d,%d)%n",
|
|
w.word(), w.direction(), w.startRow(), w.startCol(), w.arrowRow(), w.arrowCol());
|
|
}
|
|
|
|
// Export to JSON file
|
|
var dateStr = LocalDate.now().toString();
|
|
var theme = "algemeen-" + new Date().getTime();
|
|
var filename = String.format("crossword_%s_%02d_%s.json", dateStr, 1, safeSlug(theme));
|
|
var outDir = "data";
|
|
var outputPath = Paths.get(outDir, filename);
|
|
|
|
try {
|
|
Files.createDirectories(Paths.get(outDir));
|
|
var json = toJson(out, dateStr, theme);
|
|
Files.writeString(outputPath, json, StandardCharsets.UTF_8);
|
|
System.out.println("\nSaved to: " + outputPath);
|
|
} catch (IOException e) {
|
|
System.err.println("Failed to write " + filename + ": " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
private static String toJson(ExportFormat.ExportedPuzzle puzzle, String date, String theme) {
|
|
var sb = new StringBuilder();
|
|
sb.append("{\n");
|
|
sb.append(" \"date\": \"").append(escapeJson(date)).append("\",\n");
|
|
sb.append(" \"theme\": \"").append(escapeJson(theme)).append("\",\n");
|
|
sb.append(" \"difficulty\": ").append(puzzle.difficulty()).append(",\n");
|
|
sb.append(" \"rewards\": {\n");
|
|
sb.append(" \"coins\": ").append(puzzle.rewards().coins()).append(",\n");
|
|
sb.append(" \"stars\": ").append(puzzle.rewards().stars()).append(",\n");
|
|
sb.append(" \"hints\": ").append(puzzle.rewards().hints()).append("\n");
|
|
sb.append(" },\n");
|
|
sb.append(" \"gridv2\": [\n");
|
|
for (var i = 0; i < puzzle.gridv2().size(); i++) {
|
|
sb.append(" \"").append(escapeJson(puzzle.gridv2().get(i))).append("\"");
|
|
if (i < puzzle.gridv2().size() - 1) sb.append(",");
|
|
sb.append("\n");
|
|
}
|
|
sb.append(" ],\n");
|
|
sb.append(" \"words\": [\n");
|
|
for (var i = 0; i < puzzle.words().size(); i++) {
|
|
var w = puzzle.words().get(i);
|
|
sb.append(" {\n");
|
|
sb.append(" \"word\": \"").append(escapeJson(w.word())).append("\",\n");
|
|
sb.append(" \"clue\": \"").append(escapeJson(w.clue())).append("\",\n");
|
|
sb.append(" \"startRow\": ").append(w.startRow()).append(",\n");
|
|
sb.append(" \"startCol\": ").append(w.startCol()).append(",\n");
|
|
sb.append(" \"direction\": \"").append(escapeJson(w.direction())).append("\",\n");
|
|
sb.append(" \"answer\": \"").append(escapeJson(w.answer())).append("\",\n");
|
|
sb.append(" \"arrowRow\": ").append(w.arrowRow()).append(",\n");
|
|
sb.append(" \"arrowCol\": ").append(w.arrowCol()).append("\n");
|
|
sb.append(" }");
|
|
if (i < puzzle.words().size() - 1) sb.append(",");
|
|
sb.append("\n");
|
|
}
|
|
sb.append(" ]\n");
|
|
sb.append("}\n");
|
|
return sb.toString();
|
|
}
|
|
|
|
private static String escapeJson(String s) {
|
|
return s.replace("\\", "\\\\")
|
|
.replace("\"", "\\\"")
|
|
.replace("\n", "\\n")
|
|
.replace("\r", "\\r")
|
|
.replace("\t", "\\t");
|
|
}
|
|
|
|
private static String safeSlug(String s) {
|
|
return s.toLowerCase().replaceAll("[^a-z0-9]+", "-").replaceAll("^-|-$", "");
|
|
}
|
|
} |