Gather data

This commit is contained in:
mike
2026-01-04 03:50:34 +01:00
parent 6bf83aa564
commit f031591105
5 changed files with 21 additions and 77 deletions

View File

@@ -111,7 +111,7 @@ public final class ExportFormat {
p.arrowRow - minR, p.arrowRow - minR,
p.arrowCol - minC, p.arrowCol - minC,
p.isReversed, p.isReversed,
puz.dict().words().get(p.word).cross() puz.dict().words().get(p.word).simpel()
)); ));
} }
@@ -168,7 +168,7 @@ public final class ExportFormat {
return new Placed( return new Placed(
word, word,
dict.words().get(word).clue(), // clue placeholder dict.words().get(word).clue().toArray( String[]::new), // clue placeholder
startRow, startRow,
startCol, startCol,
direction, direction,
@@ -187,13 +187,13 @@ public final class ExportFormat {
* @param direction "h" | "v" * @param direction "h" | "v"
* @param cells word cells * @param cells word cells
* @param arrow [arrowRow, arrowCol] */ * @param arrow [arrowRow, arrowCol] */
private record Placed(String word, String clue, int startRow, int startCol, String direction, String answer, int arrowRow, int arrowCol, List<int[]> cells, int[] arrow, private record Placed(String word, String[] clue, int startRow, int startCol, String direction, String answer, int arrowRow, int arrowCol, List<int[]> cells, int[] arrow,
boolean isReversed) { } boolean isReversed) { }
public record Rewards(int coins, int stars, int hints) { } public record Rewards(int coins, int stars, int hints) { }
/// @param direction "h" | "v" /// @param direction "h" | "v"
public record WordOut(String word, String clue, int startRow, int startCol, String direction, String answer, int arrowRow, int arrowCol, boolean isReversed, int complex) { } public record WordOut(String word, String[] clue, int startRow, int startCol, String direction, String answer, int arrowRow, int arrowCol, boolean isReversed, int complex) { }
public record ExportedPuzzle(List<String> gridv2, List<WordOut> words, int difficulty, Rewards rewards) { } public record ExportedPuzzle(List<String> gridv2, List<WordOut> words, int difficulty, Rewards rewards) { }
} }

View File

@@ -11,6 +11,7 @@ import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.stream.Collectors;
import static puzzle.SwedishGenerator.fillMask; import static puzzle.SwedishGenerator.fillMask;
import static puzzle.SwedishGenerator.generateMask; import static puzzle.SwedishGenerator.generateMask;
@@ -83,7 +84,6 @@ public class Main {
section("Clues"); section("Clues");
info("status : generating..."); info("status : generating...");
info("generatedFor : " + exported.words().size()); info("generatedFor : " + exported.words().size());
//exported = ClueGenerator.applyClues(exported);
info("status : done"); info("status : done");
section("Words"); section("Words");
@@ -92,10 +92,7 @@ public class Main {
section("Gridv2"); section("Gridv2");
for (var row : exported.gridv2()) System.out.println(" " + row); for (var row : exported.gridv2()) System.out.println(" " + row);
// Export to JSON file
var theme = "algemeen"; var theme = "algemeen";
section("Export"); section("Export");
info("file : " + OUTPUT_PATH); info("file : " + OUTPUT_PATH);
@@ -151,14 +148,14 @@ public class Main {
for (var w : words) { for (var w : words) {
System.out.printf( System.out.printf(
Locale.ROOT, Locale.ROOT,
" %-2d %-12s %-3s %-3s %-9s %-9s %s%n", " %-2d %-12s %-4s %-3s %-9s %-9s %s%n",
i++, i++,
safe(w.word(), 12), safe(w.word(), 12),
safe("" + w.complex(), 3), safe("" + w.complex(), 4),
safe(w.direction(), 3), safe(w.direction(), 3),
fmtPoint(w.startRow(), w.startCol()), fmtPoint(w.startRow(), w.startCol()),
fmtPoint(w.arrowRow(), w.arrowCol()), fmtPoint(w.arrowRow(), w.arrowCol()),
w.clue() == null ? "" : w.clue() w.clue() == null ? "" : Arrays.toString(w.clue())
); );
} }
} }
@@ -332,9 +329,10 @@ public class Main {
sb.append(" \"words\": [\n"); sb.append(" \"words\": [\n");
for (var i = 0; i < puzzle.words().size(); i++) { for (var i = 0; i < puzzle.words().size(); i++) {
var w = puzzle.words().get(i); var w = puzzle.words().get(i);
Arrays.sort(w.clue(), Comparator.comparingInt(String::length));
sb.append(" {\n"); sb.append(" {\n");
sb.append(" \"word\": \"").append(escapeJson(w.word())).append("\",\n"); sb.append(" \"word\": \"").append(escapeJson(w.word())).append("\",\n");
sb.append(" \"clue\": \"").append(escapeJson(w.clue())).append("\",\n"); sb.append(" \"clue\": [").append(Arrays.stream(w.clue()).map(ss -> "\"" + escapeJson(ss) + "\"").collect(Collectors.joining(","))).append("],\n");
sb.append(" \"startRow\": ").append(w.startRow()).append(",\n"); sb.append(" \"startRow\": ").append(w.startRow()).append(",\n");
sb.append(" \"startCol\": ").append(w.startCol()).append(",\n"); sb.append(" \"startCol\": ").append(w.startCol()).append(",\n");
sb.append(" \"direction\": \"").append(escapeJson(w.direction())).append("\",\n"); sb.append(" \"direction\": \"").append(escapeJson(w.direction())).append("\",\n");

View File

@@ -142,12 +142,14 @@ public class SwedishGenerator {
} }
} }
static record WordDifficulty(String word, int difficulty, int simpel, int score, int cross, String clue) { static record WordDifficulty(String word, int difficulty, int simpel, int score, int cross, ArrayList<String> clue) {
public WordDifficulty(String word, int simpel, int score, String clue) { public WordDifficulty(String word, int simpel, int score, String clue) {
var difficulty1 = 0 + ((8 - word.length()) * 30) + ((10 - score) * 15); var difficulty1 = 0 + ((8 - word.length()) * 30) + ((10 - score) * 15);
var crossScore = ThemePoolBuilderLength.crossabilityScore(word); var crossScore = ThemePoolBuilderLength.crossabilityScore(word);
this(word, difficulty1, simpel, score, (crossScore * 7) + ((score) * 30) + ((word.length()) * 15), clue); var list = new ArrayList<String>(10);
list.add(clue);
this(word, difficulty1, simpel, score, (crossScore * 7) + ((score) * 30) + ((word.length()) * 15), list);
// Prioritize simple words (high lScore) and long words. // Prioritize simple words (high lScore) and long words.
// lScore (1-10) adds up to 1000 points (weight 100). // lScore (1-10) adds up to 1000 points (weight 100).
@@ -194,8 +196,13 @@ public class SwedishGenerator {
if (rawClue.startsWith("\"") && rawClue.endsWith("\"")) { if (rawClue.startsWith("\"") && rawClue.endsWith("\"")) {
rawClue = rawClue.substring(1, rawClue.length() - 1).replace("\"\"", "\""); rawClue = rawClue.substring(1, rawClue.length() - 1).replace("\"\"", "\"");
} }
if (score >= 1) if (score >= 1) {
map.put(s, new WordDifficulty(s, simpel, score, rawClue)); if (map.containsKey(s)) {
map.get(s).clue.add(rawClue);
} else {
map.put(s, new WordDifficulty(s, simpel, score, rawClue));
}
}
} }
} }
var words = map.values().stream().collect(Collectors.toCollection(ArrayList::new)); var words = map.values().stream().collect(Collectors.toCollection(ArrayList::new));
@@ -853,65 +860,4 @@ public class SwedishGenerator {
// ---------------- Top-level generatePuzzle ---------------- // ---------------- Top-level generatePuzzle ----------------
public record PuzzleResult(Dict dict, char[][] mask, FillResult filled) { } public record PuzzleResult(Dict dict, char[][] mask, FillResult filled) { }
public static PuzzleResult generatePuzzle(Main.Opts opts) {
var tLoad0 = System.nanoTime();
var dict = loadWords(opts.wordsPath);
var tLoad1 = System.nanoTime();
System.out.printf(Locale.ROOT, "LOAD_WORDS: %.3fs%n %s words%n", (tLoad1 - tLoad0) / 1e9, dict.words.size());
if (opts.threads > 1) {
System.out.println("Running in multi-threaded mode with " + opts.threads + " threads...");
var executor = Executors.newFixedThreadPool(opts.threads);
try {
var tasks = new ArrayList<Callable<PuzzleResult>>();
for (int i = 1; i <= opts.tries; i++) {
final int attempt = i;
tasks.add(() -> {
var threadRng = new Rng(opts.seed + attempt);
var mask = generateMask(threadRng, dict.lenCounts, opts.pop, opts.gens, false);
var filled = fillMask(threadRng, mask, dict.index, dict.words, 200, 60000, false);
if (filled.ok && (opts.minSimplicity <= 0 || filled.simplicity >= opts.minSimplicity)) {
System.out.println("\nSolution found on attempt " + attempt);
return new PuzzleResult(dict, mask, filled);
}
throw new RuntimeException("No solution found in attempt " + attempt);
});
}
return executor.invokeAny(tasks);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
// all failed
} finally {
executor.shutdownNow();
}
return null;
} else {
var rng = new Rng(opts.seed);
for (var attempt = 1; attempt <= opts.tries; attempt++) {
System.out.println("\nAttempt " + attempt + "/" + opts.tries);
var tMask0 = System.nanoTime();
var mask = generateMask(rng, dict.lenCounts, opts.pop, opts.gens, true);
var tMask1 = System.nanoTime();
System.out.printf(Locale.ROOT, "MASK: %.3fs%n", (tMask1 - tMask0) / 1e9);
var tFill0 = System.nanoTime();
var filled = fillMask(rng, mask, dict.index, dict.words, 200, 60000, true);
var tFill1 = System.nanoTime();
System.out.printf(Locale.ROOT, "FILL: %.3fms | Simplicity: %.2f%n", (tFill1 - tFill0) / 1e6, filled.simplicity);
if (filled.ok && (opts.minSimplicity <= 0 || filled.simplicity >= opts.minSimplicity)) {
return new PuzzleResult(dict, mask, filled);
}
if (filled.ok) {
System.out.printf(Locale.ROOT, "Puzzle simplicity %.2f is below min %.2f, retrying...%n",
filled.simplicity, opts.minSimplicity);
}
}
}
return null;
}
} }