Gather data
This commit is contained in:
@@ -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) { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user