Gather data
This commit is contained in:
@@ -32,7 +32,7 @@ public final class ExportFormat {
|
||||
|
||||
// 1) extract "placed" list from all clue digits in the filled grid
|
||||
var placed = new ArrayList<Placed>();
|
||||
var allSlots = extractSlots(g);
|
||||
var allSlots = puz.swe().extractSlots(g);
|
||||
var clueMap = puz.filled().clueMap();
|
||||
|
||||
for (var s : allSlots) {
|
||||
|
||||
@@ -14,7 +14,6 @@ import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static puzzle.SwedishGenerator.*;
|
||||
import static puzzle.SwedishGenerator.fillMask;
|
||||
import static puzzle.SwedishGenerator.loadWords;
|
||||
|
||||
public class Main {
|
||||
@@ -41,6 +40,8 @@ public class Main {
|
||||
public boolean reindex = false;
|
||||
public int fillTimeout = 20_000;
|
||||
public boolean verbose = false;
|
||||
public int W = 9;
|
||||
public int H = 8;
|
||||
}
|
||||
|
||||
public void main(String[] args) {
|
||||
@@ -73,13 +74,13 @@ public class Main {
|
||||
info(String.format(Locale.ROOT, "simplicity : %.2f", res.filled().simplicity()));
|
||||
|
||||
section("Mask");
|
||||
System.out.print(indentLines(gridToString(res.mask()), " "));
|
||||
System.out.print(indentLines(res.swe().gridToString(res.mask()), " "));
|
||||
|
||||
section("Grid (raw)");
|
||||
System.out.print(indentLines(gridToString(res.filled().grid()), " "));
|
||||
System.out.print(indentLines(res.swe().gridToString(res.filled().grid()), " "));
|
||||
|
||||
section("Grid (human)");
|
||||
System.out.print(indentLines(renderHuman(res.filled().grid()), " "));
|
||||
System.out.print(indentLines(res.swe().renderHuman(res.filled().grid()), " "));
|
||||
|
||||
var exported = ExportFormat.exportFormatFromFilled(res, 1, new ExportFormat.Rewards(50, 2, 1));
|
||||
|
||||
@@ -167,7 +168,7 @@ public class Main {
|
||||
return s.substring(0, Math.max(0, max - 1)) + "…";
|
||||
}
|
||||
|
||||
private static String indentLines(String s, String indent) {
|
||||
static String indentLines(String s, String indent) {
|
||||
if (s == null || s.isEmpty()) return "";
|
||||
var lines = s.split("\\R", -1);
|
||||
var sb = new StringBuilder();
|
||||
@@ -245,8 +246,7 @@ public class Main {
|
||||
|
||||
section("Search");
|
||||
|
||||
var deadline = System.currentTimeMillis() + 40_000;
|
||||
|
||||
var deadline = System.currentTimeMillis() + 40_000;
|
||||
|
||||
if (opts.threads > 1) {
|
||||
info("mode : multi-threaded (" + opts.threads + ")");
|
||||
@@ -258,7 +258,7 @@ public class Main {
|
||||
// Keep at least some tasks in flight
|
||||
for (int i = 0; i < opts.threads; i++) {
|
||||
final int attempt = ++submitted;
|
||||
completionService.submit(() -> attempt(new Rng(opts.seed + attempt), dict, opts ));
|
||||
completionService.submit(() -> attempt(new Rng(opts.seed + attempt), dict, opts));
|
||||
}
|
||||
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
@@ -274,7 +274,7 @@ public class Main {
|
||||
// Submit another task if we still have time
|
||||
if (System.currentTimeMillis() < deadline) {
|
||||
final int attempt = ++submitted;
|
||||
completionService.submit(() -> attempt(new Rng(opts.seed + attempt), dict, opts ));
|
||||
completionService.submit(() -> attempt(new Rng(opts.seed + attempt), dict, opts));
|
||||
}
|
||||
}
|
||||
warn("status : UNSOLVED (timeout)");
|
||||
@@ -310,12 +310,13 @@ public class Main {
|
||||
}
|
||||
}
|
||||
|
||||
static PuzzleResult attempt(Rng rng, Dict dict, Opts opts ) {
|
||||
var mask = SwedishGenerator.generateMask(rng, dict.lenCounts(), opts.pop, opts.gens, opts.verbose);
|
||||
var filled = fillMask(rng, mask, dict.index(), 200, opts.fillTimeout, opts.verbose);
|
||||
static PuzzleResult attempt(Rng rng, Dict dict, Opts opts) {
|
||||
var swe = new SwedishGenerator(opts.W, opts.H);
|
||||
var mask = swe.generateMask(rng, dict.lenCounts(), opts.pop, opts.gens, opts.verbose);
|
||||
var filled = swe.fillMask(rng, mask, dict.index(), 200, opts.fillTimeout, opts.verbose);
|
||||
|
||||
if (filled.ok() && (opts.minSimplicity <= 0 || filled.simplicity() >= opts.minSimplicity)) {
|
||||
return new PuzzleResult(dict, mask, filled);
|
||||
return new PuzzleResult(swe, dict, mask, filled);
|
||||
}
|
||||
|
||||
if (opts.verbose && filled.ok()) {
|
||||
|
||||
@@ -15,13 +15,14 @@ import java.util.function.Predicate;
|
||||
* java SwedishGenerator [--seed N] [--pop N] [--gens N] [--tries N] [--words word-list.txt]
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public class SwedishGenerator {
|
||||
public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) {
|
||||
|
||||
static final int W = 9, H = 8,
|
||||
SIZE = W * H,
|
||||
CLUE_SIZE = 4,
|
||||
public SwedishGenerator(int W,int H) { this(W, H, W * H, Math.min(W, H)); }
|
||||
public SwedishGenerator() { this(9, 8); }
|
||||
|
||||
static final int CLUE_SIZE = 4,
|
||||
SIMPLICITY_DEFAULT_SCORE = 2;
|
||||
static final int MIN_LEN = 2, MAX_LEN = 8;
|
||||
static final int MIN_LEN = 2;
|
||||
// Directions for '1'..'6'
|
||||
static final int[][] OFFSETS = new int[7][2];
|
||||
static final int[][] STEPS = new int[7][2];
|
||||
@@ -81,19 +82,19 @@ public class SwedishGenerator {
|
||||
static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
|
||||
|
||||
// ---------------- Grid helpers ----------------
|
||||
static char[][] makeEmptyGrid() {
|
||||
char[][] makeEmptyGrid() {
|
||||
var g = new char[H][W];
|
||||
for (var r = 0; r < H; r++) Arrays.fill(g[r], '#');
|
||||
return g;
|
||||
}
|
||||
|
||||
static char[][] deepCopyGrid(char[][] g) {
|
||||
char[][] deepCopyGrid(char[][] g) {
|
||||
var out = new char[H][W];
|
||||
for (var r = 0; r < H; r++) out[r] = Arrays.copyOf(g[r], W);
|
||||
return out;
|
||||
}
|
||||
|
||||
static String gridToString(char[][] g) {
|
||||
String gridToString(char[][] g) {
|
||||
var sb = new StringBuilder();
|
||||
for (var r = 0; r < H; r++) {
|
||||
if (r > 0) sb.append('\n');
|
||||
@@ -102,7 +103,7 @@ public class SwedishGenerator {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static String renderHuman(char[][] g) {
|
||||
public String renderHuman(char[][] g) {
|
||||
var sb = new StringBuilder();
|
||||
for (var r = 0; r < H; r++) {
|
||||
if (r > 0) sb.append('\n');
|
||||
@@ -295,7 +296,7 @@ public class SwedishGenerator {
|
||||
public Slot(int clueR, int clueC, char dir, int[] rs, int[] cs) { this(clueR + "," + clueC + ":" + dir, clueR, clueC, dir, rs, cs, rs.length); }
|
||||
}
|
||||
|
||||
static ArrayList<Slot> extractSlots(char[][] grid) {
|
||||
ArrayList<Slot> extractSlots(char[][] grid) {
|
||||
var slots = new ArrayList<Slot>();
|
||||
for (var r = 0; r < H; r++) {
|
||||
for (var c = 0; c < W; c++) {
|
||||
@@ -332,7 +333,7 @@ public class SwedishGenerator {
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
static boolean hasRoomForClue(char[][] grid, int r, int c, char d) {
|
||||
boolean hasRoomForClue(char[][] grid, int r, int c, char d) {
|
||||
var di = d - '0';
|
||||
int or = OFFSETS[di][0], oc = OFFSETS[di][1];
|
||||
int dr = STEPS[di][0], dc = STEPS[di][1];
|
||||
@@ -353,7 +354,7 @@ public class SwedishGenerator {
|
||||
{ 1, -1 }, { 1, 0 }, { 1, 1 }
|
||||
};
|
||||
static final int[][] nbrs4 = new int[][]{ { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
|
||||
static long maskFitness(char[][] grid, int[] lenCounts) {
|
||||
long maskFitness(char[][] grid, int[] lenCounts) {
|
||||
long penalty = 0;
|
||||
|
||||
var clueCount = 0;
|
||||
@@ -447,7 +448,7 @@ public class SwedishGenerator {
|
||||
|
||||
// ---------------- Mask generation ----------------
|
||||
|
||||
static char[][] randomMask(Rng rng) {
|
||||
char[][] randomMask(Rng rng) {
|
||||
var g = makeEmptyGrid();
|
||||
var targetClues = (int) Math.round(SIZE * 0.25);
|
||||
int placed = 0, guard = 0;
|
||||
@@ -468,7 +469,7 @@ public class SwedishGenerator {
|
||||
return g;
|
||||
}
|
||||
|
||||
static char[][] mutate(Rng rng, char[][] grid) {
|
||||
char[][] mutate(Rng rng, char[][] grid) {
|
||||
var g = deepCopyGrid(grid);
|
||||
var cx = rng.randint(0, H - 1);
|
||||
var cy = rng.randint(0, W - 1);
|
||||
@@ -490,7 +491,7 @@ public class SwedishGenerator {
|
||||
return g;
|
||||
}
|
||||
|
||||
static char[][] crossover(Rng rng, char[][] a, char[][] b) {
|
||||
char[][] crossover(Rng rng, char[][] a, char[][] b) {
|
||||
var out = makeEmptyGrid();
|
||||
var cx = (H - 1) / 2.0;
|
||||
var cy = (W - 1) / 2.0;
|
||||
@@ -513,7 +514,7 @@ public class SwedishGenerator {
|
||||
return out;
|
||||
}
|
||||
|
||||
static char[][] hillclimb(Rng rng, char[][] start, int[] lenCounts, int limit) {
|
||||
char[][] hillclimb(Rng rng, char[][] start, int[] lenCounts, int limit) {
|
||||
var best = deepCopyGrid(start);
|
||||
var bestF = maskFitness(best, lenCounts);
|
||||
var fails = 0;
|
||||
@@ -532,13 +533,13 @@ public class SwedishGenerator {
|
||||
return best;
|
||||
}
|
||||
|
||||
static double similarity(char[][] a, char[][] b) {
|
||||
double similarity(char[][] a, char[][] b) {
|
||||
var same = 0;
|
||||
for (var r = 0; r < H; r++) for (var c = 0; c < W; c++) if (a[r][c] == b[r][c]) same++;
|
||||
return same / (double) (W * H);
|
||||
}
|
||||
|
||||
static char[][] generateMask(Rng rng, int[] lenCounts, int popSize, int gens, boolean verbose) {
|
||||
public char[][] generateMask(Rng rng, int[] lenCounts, int popSize, int gens, boolean verbose) {
|
||||
if (verbose) System.out.println("generateMask init pop: " + popSize);
|
||||
var pop = new ArrayList<char[][]>();
|
||||
|
||||
@@ -660,7 +661,7 @@ public class SwedishGenerator {
|
||||
record Pick(Slot slot,
|
||||
CandidateInfo info,
|
||||
boolean done) { }
|
||||
static FillResult fillMask(Rng rng, char[][] mask, DictEntry[] dictIndex,
|
||||
public FillResult fillMask(Rng rng, char[][] mask, DictEntry[] dictIndex,
|
||||
int logEveryMs, int timeLimitMs, boolean verbose) {
|
||||
|
||||
var grid = deepCopyGrid(mask);
|
||||
@@ -854,6 +855,6 @@ public class SwedishGenerator {
|
||||
}
|
||||
|
||||
// ---------------- Top-level generatePuzzle ----------------
|
||||
public record PuzzleResult(Dict dict, char[][] mask, FillResult filled) { }
|
||||
public record PuzzleResult(SwedishGenerator swe, Dict dict, char[][] mask, FillResult filled) { }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user