redo
This commit is contained in:
@@ -38,12 +38,6 @@ public class Main {
|
|||||||
final static String OUT_DIR = envOrDefault("OUT_DIR", "/data/puzzle");
|
final static String OUT_DIR = envOrDefault("OUT_DIR", "/data/puzzle");
|
||||||
final static Path PUZZLE_DIR = Paths.get(OUT_DIR, "puzzles");
|
final static Path PUZZLE_DIR = Paths.get(OUT_DIR, "puzzles");
|
||||||
static final Path INDEX_FILE = PUZZLE_DIR.resolve("index.json");
|
static final Path INDEX_FILE = PUZZLE_DIR.resolve("index.json");
|
||||||
static final OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
|
|
||||||
static final String CREATED_AT = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));
|
|
||||||
static final String FILE_ID = CREATED_AT.replace(":", "-") + "_" + System.currentTimeMillis() / 1000;
|
|
||||||
static final String FILE_NAME = FILE_ID + ".json";
|
|
||||||
static final Path OUTPUT_PATH = PUZZLE_DIR.resolve(FILE_NAME);
|
|
||||||
static final String DATE_STRING = now.toLocalDate().toString();
|
|
||||||
static final boolean VERBOSE = false;
|
static final boolean VERBOSE = false;
|
||||||
static final AtomicLong TOTAL_NODES = new AtomicLong(0);
|
static final AtomicLong TOTAL_NODES = new AtomicLong(0);
|
||||||
static final AtomicLong TOTAL_BACKTRACKS = new AtomicLong(0);
|
static final AtomicLong TOTAL_BACKTRACKS = new AtomicLong(0);
|
||||||
@@ -64,6 +58,7 @@ public class Main {
|
|||||||
public double minSimplicity = 0; // 0 means no limit
|
public double minSimplicity = 0; // 0 means no limit
|
||||||
public int threads = Math.max(1, Runtime.getRuntime().availableProcessors());
|
public int threads = Math.max(1, Runtime.getRuntime().availableProcessors());
|
||||||
public int tries = threads;
|
public int tries = threads;
|
||||||
|
public int count = 2;
|
||||||
public boolean reindex = false;
|
public boolean reindex = false;
|
||||||
public boolean verbose = true;
|
public boolean verbose = true;
|
||||||
|
|
||||||
@@ -89,56 +84,71 @@ public class Main {
|
|||||||
section("Settings");
|
section("Settings");
|
||||||
printSettings(opts);
|
printSettings(opts);
|
||||||
|
|
||||||
var res = generatePuzzle(opts);
|
for (int count = 0; count < opts.count; count++) {
|
||||||
if (res == null) {
|
if (opts.count > 1) {
|
||||||
err("Search status : UNSOLVED");
|
section("Generation " + (count + 1) + " / " + opts.count);
|
||||||
err("Reason : No solution found within tries.");
|
}
|
||||||
System.exit(1);
|
var res = generatePuzzle(opts);
|
||||||
return;
|
opts.seed++; // Ensure different seed for next puzzle
|
||||||
}
|
|
||||||
|
|
||||||
section("Mask");
|
if (res == null) {
|
||||||
System.out.print(indentLines(res.cluesGridToString()));
|
err("Search status : UNSOLVED");
|
||||||
|
err("Reason : No solution found within tries.");
|
||||||
|
if (opts.count == 1) System.exit(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
section("Grid (raw)");
|
section("Mask");
|
||||||
System.out.print(indentLines(res.gridGridToString()));
|
System.out.print(indentLines(res.cluesGridToString()));
|
||||||
|
|
||||||
section("Grid (human)");
|
section("Grid (raw)");
|
||||||
System.out.print(indentLines(res.gridRenderHuman()));
|
System.out.print(indentLines(res.gridGridToString()));
|
||||||
|
|
||||||
var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1));
|
section("Grid (human)");
|
||||||
|
System.out.print(indentLines(res.gridRenderHuman()));
|
||||||
|
|
||||||
section("Clues");
|
var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1));
|
||||||
info("status : generating...");
|
|
||||||
info("generatedFor : " + exported.words().length);
|
|
||||||
info("status : done");
|
|
||||||
info("simpel : " + exported.difficulty());
|
|
||||||
|
|
||||||
section("Words");
|
section("Clues");
|
||||||
printWordsTable(exported.words());
|
info("status : generating...");
|
||||||
|
info("generatedFor : " + exported.words().length);
|
||||||
|
info("status : done");
|
||||||
|
info("simpel : " + exported.difficulty());
|
||||||
|
|
||||||
section("Grid");
|
section("Words");
|
||||||
for (var row : exported.grid()) System.out.println(" " + row);
|
printWordsTable(exported.words());
|
||||||
|
|
||||||
var theme = "algemeen";
|
section("Grid");
|
||||||
section("Export");
|
for (var row : exported.grid()) System.out.println(" " + row);
|
||||||
info("file : " + OUTPUT_PATH);
|
|
||||||
|
|
||||||
try {
|
var theme = "algemeen";
|
||||||
Files.createDirectories(PUZZLE_DIR);
|
|
||||||
var json = toJson(exported, DATE_STRING, theme);
|
|
||||||
Files.writeString(OUTPUT_PATH, json, StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
// Update index.json
|
var now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
var pathInIndex = "/puzzles/" + FILE_NAME;
|
var createdAt = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));
|
||||||
var indexRecord = toIndexRecordJson(FILE_ID, pathInIndex, DATE_STRING, theme, exported.difficulty(), CREATED_AT);
|
var dateString = now.toLocalDate().toString();
|
||||||
if (1 != 1) updateIndex(PUZZLE_DIR.toString(), indexRecord);
|
var fileId = createdAt.replace(":", "-") + "_" + System.currentTimeMillis() / 1000 + "_" + count;
|
||||||
else rebuildIndex();
|
var fileName = fileId + ".json";
|
||||||
info("indexUpdated : " + INDEX_FILE);
|
var outputPath = PUZZLE_DIR.resolve(fileName);
|
||||||
} catch (IOException e) {
|
|
||||||
err("Failed to write: " + FILE_NAME);
|
section("Export");
|
||||||
err("Reason : " + e.getMessage());
|
info("file : " + outputPath);
|
||||||
System.exit(2);
|
|
||||||
|
try {
|
||||||
|
Files.createDirectories(PUZZLE_DIR);
|
||||||
|
var json = toJson(exported, dateString, theme);
|
||||||
|
Files.writeString(outputPath, json, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// Update index.json
|
||||||
|
var pathInIndex = "/puzzles/" + fileName;
|
||||||
|
var indexRecord = toIndexRecordJson(fileId, pathInIndex, dateString, theme, exported.difficulty(), createdAt);
|
||||||
|
if (1 != 1) updateIndex(PUZZLE_DIR.toString(), indexRecord);
|
||||||
|
else rebuildIndex();
|
||||||
|
info("indexUpdated : " + INDEX_FILE);
|
||||||
|
} catch (IOException e) {
|
||||||
|
err("Failed to write: " + fileName);
|
||||||
|
err("Reason : " + e.getMessage());
|
||||||
|
if (opts.count == 1) System.exit(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +176,7 @@ public class Main {
|
|||||||
System.out.printf(Locale.ROOT, " %-14s: %d%n", "generations", o.gens);
|
System.out.printf(Locale.ROOT, " %-14s: %d%n", "generations", o.gens);
|
||||||
System.out.printf(Locale.ROOT, " %-14s: %.2f%n", "minSimplicity", o.minSimplicity);
|
System.out.printf(Locale.ROOT, " %-14s: %.2f%n", "minSimplicity", o.minSimplicity);
|
||||||
System.out.printf(Locale.ROOT, " %-14s: %d%n", "threads", o.threads);
|
System.out.printf(Locale.ROOT, " %-14s: %d%n", "threads", o.threads);
|
||||||
|
System.out.printf(Locale.ROOT, " %-14s: %d%n", "count", o.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String fmtPoint(int r, int c) { return String.format(Locale.ROOT, "(%d,%d)", r, c); }
|
private static String fmtPoint(int r, int c) { return String.format(Locale.ROOT, "(%d,%d)", r, c); }
|
||||||
@@ -204,7 +215,7 @@ public class Main {
|
|||||||
static void usage() {
|
static void usage() {
|
||||||
System.out.printf("""
|
System.out.printf("""
|
||||||
Usage:
|
Usage:
|
||||||
java puzzle.Main [--seed N] [--clues N] [--pop N] [--offspring N] [--gens N] [--tries N] [--words FILE] [--min-simplicity N.N] [--threads N] [--reindex]
|
java puzzle.Main [--seed N] [--clues N] [--pop N] [--offspring N] [--gens N] [--tries N] [--words FILE] [--min-simplicity N.N] [--threads N] [--count N] [--reindex]
|
||||||
|
|
||||||
Defaults:
|
Defaults:
|
||||||
--clues 18
|
--clues 18
|
||||||
@@ -214,7 +225,8 @@ public class Main {
|
|||||||
--words nl_score_hints.csv
|
--words nl_score_hints.csv
|
||||||
--min-simplicity 0 (no limit)
|
--min-simplicity 0 (no limit)
|
||||||
--threads %d
|
--threads %d
|
||||||
%n""", Math.max(1, Runtime.getRuntime().availableProcessors()));
|
--count 1
|
||||||
|
%n""", Math.max(1, Runtime.getRuntime().availableProcessors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Opts parseArgs(String[] argv) {
|
static Opts parseArgs(String[] argv) {
|
||||||
@@ -252,6 +264,9 @@ public class Main {
|
|||||||
} else if (a.equals("--threads")) {
|
} else if (a.equals("--threads")) {
|
||||||
out.threads = Integer.parseInt(v);
|
out.threads = Integer.parseInt(v);
|
||||||
i++;
|
i++;
|
||||||
|
} else if (a.equals("--count")) {
|
||||||
|
out.count = Integer.parseInt(v);
|
||||||
|
i++;
|
||||||
} else if (a.equals("--reindex")) {
|
} else if (a.equals("--reindex")) {
|
||||||
out.reindex = true;
|
out.reindex = true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -55,77 +55,8 @@ public final class Masker {
|
|||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
}
|
}
|
||||||
public Clues cache(Clues clues) {
|
public Clues cache(Clues clues) { return cache.from(clues); }
|
||||||
return cache.from(clues);
|
|
||||||
}
|
|
||||||
public static boolean isLo(int n) { return (n & 64) == 0; }
|
public static boolean isLo(int n) { return (n & 64) == 0; }
|
||||||
public static double similarity(Clues a, Clues b) {
|
|
||||||
var matchLo = (~(a.lo ^ b.lo)) & (~a.lo | (~(a.vlo ^ b.vlo) & ~(a.rlo ^ b.rlo) & ~(a.xlo ^ b.xlo)));
|
|
||||||
var matchHi = (~(a.hi ^ b.hi)) & (~a.hi | (~(a.vhi ^ b.vhi) & ~(a.rhi ^ b.rhi) & ~(a.xhi ^ b.xhi)));
|
|
||||||
|
|
||||||
return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED;
|
|
||||||
}
|
|
||||||
public static Grid grid(Slotinfo[] slots) {
|
|
||||||
long lo = X, hi = X;
|
|
||||||
for (var slot : slots) {
|
|
||||||
lo |= slot.lo();
|
|
||||||
hi |= slot.hi();
|
|
||||||
}
|
|
||||||
return new Grid(new byte[SIZE], ~lo & MASK_LO, ~hi & MASK_HI);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isValid(Clues c) {
|
|
||||||
return findOffendingClue(c) == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int findOffendingClue(Clues c) {
|
|
||||||
//if (((c.xlo & c.rlo) & c.lo) != X) return numberOfTrailingZeros((c.xlo & c.rlo) & c.lo);
|
|
||||||
// if (((c.xhi & c.rhi) & c.hi) != X) return 64 | numberOfTrailingZeros((c.xhi & c.rhi) & c.hi);
|
|
||||||
|
|
||||||
var num = 0;
|
|
||||||
for (var bits = c.lo; bits != X; bits &= bits - 1) activeCIdx[num++] = numberOfTrailingZeros(bits);
|
|
||||||
for (var bits = c.hi; bits != X; bits &= bits - 1) activeCIdx[num++] = 64 | numberOfTrailingZeros(bits);
|
|
||||||
|
|
||||||
if (num == 0) return -1;
|
|
||||||
|
|
||||||
var start = rng.randint0_SIZE(RANGE_0_SIZE) % num;
|
|
||||||
var n = 0;
|
|
||||||
for (var i = 0; i < num; i++) {
|
|
||||||
var idx = activeCIdx[(start + i) % num];
|
|
||||||
int dir = c.getDir(idx);
|
|
||||||
var key = Slot.packSlotKey(idx, dir);
|
|
||||||
long sLo = PATH_LO[key], sHi = PATH_HI[key];
|
|
||||||
long hLo = sLo & c.lo, hHi = sHi & c.hi;
|
|
||||||
if (Slotinfo.increasing(key)) {
|
|
||||||
if (hLo != X) {
|
|
||||||
sLo &= (1L << numberOfTrailingZeros(hLo)) - 1;
|
|
||||||
sHi = 0;
|
|
||||||
} else if (hHi != X) { sHi &= (1L << numberOfTrailingZeros(hHi)) - 1; }
|
|
||||||
} else {
|
|
||||||
if (hHi != X) {
|
|
||||||
sHi &= -(1L << (63 - numberOfLeadingZeros(hHi)) << 1);
|
|
||||||
sLo = 0;
|
|
||||||
} else if (hLo != X) { sLo &= -(1L << (63 - numberOfLeadingZeros(hLo)) << 1); }
|
|
||||||
}
|
|
||||||
if (bitCount(sLo) + bitCount(sHi) < MIN_LEN) return idx;
|
|
||||||
for (var j = 0; j < n; j++) if (bitCount(sLo & activeSLo[j]) + bitCount(sHi & activeSHi[j]) > 1) return idx;
|
|
||||||
activeSLo[n] = sLo;
|
|
||||||
activeSHi[n] = sHi;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
public static Grid toGrid(Clues c) { return new Grid(new byte[SIZE], c.lo, c.hi); }
|
|
||||||
public void cleanup(Clues c) {
|
|
||||||
var guard = 0;
|
|
||||||
while (guard++ < 50) {
|
|
||||||
var offending = findOffendingClue(c);
|
|
||||||
if (offending == -1) break;
|
|
||||||
if ((offending & 64) == 0) c.clearClueLo(~(1L << offending));
|
|
||||||
else c.clearClueHi(~(1L << (offending & 63)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (var i = 0; i < SIZE; i++) {
|
for (var i = 0; i < SIZE; i++) {
|
||||||
var k = 0;
|
var k = 0;
|
||||||
@@ -139,6 +70,148 @@ public final class Masker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static double similarity(Clues a, Clues b) {
|
||||||
|
long diffLo = a.lo ^ b.lo;
|
||||||
|
long diffHi = a.hi ^ b.hi;
|
||||||
|
int diffPos = bitCount(diffLo) + bitCount(diffHi);
|
||||||
|
|
||||||
|
long commonLo = a.lo & b.lo;
|
||||||
|
long commonHi = a.hi & b.hi;
|
||||||
|
int diffDir = bitCount(commonLo & (a.vlo ^ b.vlo | a.rlo ^ b.rlo | a.xlo ^ b.xlo))
|
||||||
|
+ bitCount(commonHi & (a.vhi ^ b.vhi | a.rhi ^ b.rhi | a.xhi ^ b.xhi));
|
||||||
|
|
||||||
|
return (SIZED - (diffPos + diffDir)) / SIZED;
|
||||||
|
}
|
||||||
|
public static Grid grid(Slotinfo[] slots) {
|
||||||
|
long lo = X, hi = X;
|
||||||
|
for (var slot : slots) {
|
||||||
|
lo |= slot.lo();
|
||||||
|
hi |= slot.hi();
|
||||||
|
}
|
||||||
|
return new Grid(new byte[SIZE], ~lo & MASK_LO, ~hi & MASK_HI);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getWordPathLo(Clues c, int idx, int dir) {
|
||||||
|
int key = (idx << 3) | dir;
|
||||||
|
long sLo = PATH_LO[key], sHi = PATH_HI[key];
|
||||||
|
long hLo = sLo & c.lo, hHi = sHi & c.hi;
|
||||||
|
if ((dir & 2) == 0) { // Increasing
|
||||||
|
if (hLo != X) return sLo & ((hLo & -hLo) - 1);
|
||||||
|
if (hHi != X) return sLo;
|
||||||
|
return sLo;
|
||||||
|
} else {
|
||||||
|
if (hHi != X) return 0;
|
||||||
|
if (hLo != X) return sLo & -(Long.highestOneBit(hLo) << 1);
|
||||||
|
return sLo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getWordPathHi(Clues c, int idx, int dir) {
|
||||||
|
int key = (idx << 3) | dir;
|
||||||
|
long sLo = PATH_LO[key], sHi = PATH_HI[key];
|
||||||
|
long hLo = sLo & c.lo, hHi = sHi & c.hi;
|
||||||
|
if ((dir & 2) == 0) { // Increasing
|
||||||
|
if (hLo != X) return 0;
|
||||||
|
if (hHi != X) return sHi & ((hHi & -hHi) - 1);
|
||||||
|
return sHi;
|
||||||
|
} else {
|
||||||
|
if (hHi != X) return sHi & -(Long.highestOneBit(hHi) << 1);
|
||||||
|
if (hLo != X) return sHi;
|
||||||
|
return sHi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid(Clues c) {
|
||||||
|
return findOffendingClue(c, -1) == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid(Clues c, int ri) {
|
||||||
|
return findOffendingClue(c, ri) == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDeadCell(Clues c, int idx) {
|
||||||
|
var rci = IT[idx];
|
||||||
|
return (4 - rci.nbrCount()) + bitCount(rci.n1() & c.lo) + bitCount(rci.n2() & c.hi) >= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findAdjacentClue(Clues c, int ri) {
|
||||||
|
var rci = IT[ri];
|
||||||
|
long nLo = rci.n1() & c.lo;
|
||||||
|
if (nLo != 0) return numberOfTrailingZeros(nLo);
|
||||||
|
long nHi = rci.n2() & c.hi;
|
||||||
|
if (nHi != 0) return 64 | numberOfTrailingZeros(nHi);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int findOffendingClue(Clues c) {
|
||||||
|
return findOffendingClue(c, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int findOffendingClue(Clues c, int ri) {
|
||||||
|
int num = 0;
|
||||||
|
for (long bits = c.lo; bits != X; bits &= bits - 1) activeCIdx[num++] = numberOfTrailingZeros(bits);
|
||||||
|
for (long bits = c.hi; bits != X; bits &= bits - 1) activeCIdx[num++] = 64 | numberOfTrailingZeros(bits);
|
||||||
|
if (num == 0) return -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
int idx = activeCIdx[i];
|
||||||
|
int dir = c.getDir(idx);
|
||||||
|
activeSLo[i] = getWordPathLo(c, idx, dir);
|
||||||
|
activeSHi[i] = getWordPathHi(c, idx, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
long ri_lo = (ri != -1 && ri < 64) ? (1L << ri) : 0;
|
||||||
|
long ri_hi = (ri != -1 && ri >= 64) ? (1L << (ri - 64)) : 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
int idx = activeCIdx[i];
|
||||||
|
int dir = c.getDir(idx);
|
||||||
|
boolean affected = (ri == -1) || (idx == ri) || ((PATH_LO[(idx << 3) | dir] & ri_lo) != 0) || ((PATH_HI[(idx << 3) | dir] & ri_hi) != 0);
|
||||||
|
|
||||||
|
if (affected) {
|
||||||
|
long sLo = activeSLo[i], sHi = activeSHi[i];
|
||||||
|
if (bitCount(sLo) + bitCount(sHi) < MIN_LEN) return idx;
|
||||||
|
for (int j = 0; j < num; j++) {
|
||||||
|
if (i == j) continue;
|
||||||
|
long combined = (sLo & activeSLo[j]) | (sHi & activeSHi[j]);
|
||||||
|
if (combined != 0 && (combined & (combined - 1)) != 0) return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ri == -1) {
|
||||||
|
for (long bits = ~c.lo & MASK_LO; bits != X; bits &= bits - 1) {
|
||||||
|
int clueIdx = numberOfTrailingZeros(bits);
|
||||||
|
if (isDeadCell(c, clueIdx)) return findAdjacentClue(c, clueIdx);
|
||||||
|
}
|
||||||
|
for (long bits = ~c.hi & MASK_HI; bits != X; bits &= bits - 1) {
|
||||||
|
int clueIdx = numberOfTrailingZeros(bits);
|
||||||
|
if (isDeadCell(c, 64 | clueIdx)) return findAdjacentClue(c, 64 | clueIdx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (c.notClue(ri) && isDeadCell(c, ri)) return findAdjacentClue(c, ri);
|
||||||
|
var rci = IT[ri];
|
||||||
|
for (long bits = rci.n1(); bits != X; bits &= bits - 1) {
|
||||||
|
int nIdx = numberOfTrailingZeros(bits);
|
||||||
|
if (c.notClue(nIdx) && isDeadCell(c, nIdx)) return findAdjacentClue(c, nIdx);
|
||||||
|
}
|
||||||
|
for (long bits = rci.n2(); bits != X; bits &= bits - 1) {
|
||||||
|
int nIdx = numberOfTrailingZeros(bits);
|
||||||
|
if (c.notClue(64 | nIdx) && isDeadCell(c, 64 | nIdx)) return findAdjacentClue(c, 64 | nIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
public void cleanup(Clues c) {
|
||||||
|
var guard = 0;
|
||||||
|
while (guard++ < 50) {
|
||||||
|
var offending = findOffendingClue(c);
|
||||||
|
if (offending == -1) break;
|
||||||
|
if ((offending & 64) == 0) c.clearClueLo(~(1L << offending));
|
||||||
|
else c.clearClueHi(~(1L << (offending & 63)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// slice ray to stop before first clue, depending on direction monotonicity
|
// slice ray to stop before first clue, depending on direction monotonicity
|
||||||
// right/down => increasing indices; up/left => decreasing indices
|
// right/down => increasing indices; up/left => decreasing indices
|
||||||
// first clue is highest index among hits (hi first, then lo)
|
// first clue is highest index among hits (hi first, then lo)
|
||||||
@@ -250,171 +323,119 @@ public final class Masker {
|
|||||||
public static int offset(int r, int c) { return r | (c << 3); }
|
public static int offset(int r, int c) { return r | (c << 3); }
|
||||||
|
|
||||||
public long maskFitness(final Clues grid, int clueSize) {
|
public long maskFitness(final Clues grid, int clueSize) {
|
||||||
|
long cHLo = 0L, cHHi = 0L, cVLo = 0L, cVHi = 0L;
|
||||||
|
long cHLo2 = 0L, cHHi2 = 0L, cVLo2 = 0L, cVHi2 = 0L;
|
||||||
|
final long lo_cl = grid.lo, hi_cl = grid.hi;
|
||||||
|
final int numCluesTotal = bitCount(lo_cl) + bitCount(hi_cl);
|
||||||
|
if (numCluesTotal == 0) return 1_000_000_000L;
|
||||||
|
|
||||||
long cHLo = 0L, cHHi = 0L, cVLo = 0L, cVHi = 0L;
|
long penalty = Math.abs(numCluesTotal - clueSize) * 16000L;
|
||||||
long cHLo2 = 0L, cHHi2 = 0L, cVLo2 = 0L, cVHi2 = 0L;
|
boolean hasSlots = false;
|
||||||
long lo_cl = grid.lo, hi_cl = grid.hi;
|
int numClues = 0;
|
||||||
var penalty = (((long) Math.abs(grid.clueCount() - clueSize)) * 16000L);
|
|
||||||
var hasSlots = false;
|
|
||||||
|
|
||||||
var numClues = 0;
|
for (int part = 0; part < 2; part++) {
|
||||||
for (var bits = lo_cl; bits != X; bits &= bits - 1) {
|
long bits = (part == 0) ? lo_cl : hi_cl;
|
||||||
var lsb = bits & -bits;
|
long vlo = (part == 0) ? grid.vlo : grid.vhi;
|
||||||
var clueIdx = numberOfTrailingZeros(lsb);
|
long rlo = (part == 0) ? grid.rlo : grid.rhi;
|
||||||
int dir = grid.getDir(clueIdx);
|
long xlo = (part == 0) ? grid.xlo : grid.xhi;
|
||||||
var key = Slot.packSlotKey(clueIdx, dir);
|
int base = (part == 0) ? 0 : 64;
|
||||||
long rLo = PATH_LO[key], rHi = PATH_HI[key];
|
while (bits != X) {
|
||||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
long lsb = bits & -bits;
|
||||||
if (Slotinfo.increasing(key)) {
|
int clueIdx = base | numberOfTrailingZeros(lsb);
|
||||||
if (hLo != X) {
|
int dir = (vlo & lsb) != 0 ? 1 : 0;
|
||||||
rLo &= ((1L << numberOfTrailingZeros(hLo)) - 1);
|
if ((rlo & lsb) != 0) dir |= 2;
|
||||||
rHi = 0;
|
if ((xlo & lsb) != 0) dir |= 4;
|
||||||
} else if (hHi != X) rHi &= ((1L << numberOfTrailingZeros(hHi)) - 1);
|
int key = (clueIdx << 3) | dir;
|
||||||
} else if (hHi != X) {
|
long rLo = PATH_LO[key], rHi = PATH_HI[key];
|
||||||
var msb = 63 - numberOfLeadingZeros(hHi);
|
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
||||||
rHi &= -(1L << msb << 1);
|
if ((dir & 2) == 0) { // Increasing
|
||||||
rLo = 0;
|
if (hLo != X) {
|
||||||
} else if (hLo != X) {
|
rLo &= (hLo & -hLo) - 1;
|
||||||
var msb = 63 - numberOfLeadingZeros(hLo);
|
rHi = 0;
|
||||||
rLo &= -(1L << msb << 1);
|
} else if (hHi != X) rHi &= (hHi & -hHi) - 1;
|
||||||
|
} else if (hHi != X) {
|
||||||
|
rHi &= -(Long.highestOneBit(hHi) << 1);
|
||||||
|
rLo = 0;
|
||||||
|
} else if (hLo != X) { rLo &= -(Long.highestOneBit(hLo) << 1); }
|
||||||
|
|
||||||
|
activeCIdx[numClues] = clueIdx;
|
||||||
|
activeSLo[numClues] = rLo;
|
||||||
|
activeSHi[numClues] = rHi;
|
||||||
|
numClues++;
|
||||||
|
|
||||||
|
long combined = rLo | rHi;
|
||||||
|
if (combined != X) {
|
||||||
|
hasSlots = true;
|
||||||
|
if (Slot.horiz(dir)) {
|
||||||
|
cHLo2 |= (cHLo & rLo);
|
||||||
|
cHHi2 |= (cHHi & rHi);
|
||||||
|
cHLo |= rLo;
|
||||||
|
cHHi |= rHi;
|
||||||
|
} else {
|
||||||
|
cVLo2 |= (cVLo & rLo);
|
||||||
|
cVHi2 |= (cVHi & rHi);
|
||||||
|
cVLo |= rLo;
|
||||||
|
cVHi |= rHi;
|
||||||
|
}
|
||||||
|
int wordLen = bitCount(combined);
|
||||||
|
if (wordLen < MIN_LEN) penalty += 8000;
|
||||||
|
if (wordLen > 6) penalty += (wordLen - 6) * 1000L;
|
||||||
|
} else penalty += 25000;
|
||||||
|
bits &= ~lsb;
|
||||||
}
|
}
|
||||||
|
|
||||||
activeCIdx[numClues] = clueIdx;
|
|
||||||
activeSLo[numClues] = rLo;
|
|
||||||
activeSHi[numClues] = rHi;
|
|
||||||
numClues++;
|
|
||||||
|
|
||||||
if ((rLo | rHi) != X) {
|
|
||||||
hasSlots = true;
|
|
||||||
if (Slot.horiz(key)) {
|
|
||||||
cHLo2 |= (cHLo & rLo);
|
|
||||||
cHHi2 |= (cHHi & rHi);
|
|
||||||
cHLo |= rLo;
|
|
||||||
cHHi |= rHi;
|
|
||||||
} else {
|
|
||||||
cVLo2 |= (cVLo & rLo);
|
|
||||||
cVHi2 |= (cVHi & rHi);
|
|
||||||
cVLo |= rLo;
|
|
||||||
cVHi |= rHi;
|
|
||||||
}
|
|
||||||
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
|
||||||
var wordLen = bitCount(rLo) + bitCount(rHi);
|
|
||||||
if (wordLen > 6) penalty += (wordLen - 6) * 1000L;
|
|
||||||
} else penalty += 25000;
|
|
||||||
}
|
|
||||||
for (var bits = hi_cl; bits != X; bits &= bits - 1) {
|
|
||||||
var lsb = bits & -bits;
|
|
||||||
var clueIdx = numberOfTrailingZeros(lsb);
|
|
||||||
int dir = grid.getDir(64 | clueIdx);
|
|
||||||
var key = Slot.packSlotKey(64 | clueIdx, dir);
|
|
||||||
long rLo = PATH_LO[key], rHi = PATH_HI[key];
|
|
||||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
|
||||||
if (Slotinfo.increasing(key)) {
|
|
||||||
if (hLo != X) {
|
|
||||||
rLo &= ((1L << numberOfTrailingZeros(hLo)) - 1);
|
|
||||||
rHi = 0;
|
|
||||||
} else if (hHi != X) rHi &= ((1L << numberOfTrailingZeros(hHi)) - 1);
|
|
||||||
} else if (hHi != X) {
|
|
||||||
var msb = 63 - numberOfLeadingZeros(hHi);
|
|
||||||
rHi &= -(1L << msb << 1);
|
|
||||||
rLo = 0;
|
|
||||||
} else if (hLo != X) {
|
|
||||||
var msb = 63 - numberOfLeadingZeros(hLo);
|
|
||||||
rLo &= -(1L << msb << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
activeCIdx[numClues] = 64 | clueIdx;
|
|
||||||
activeSLo[numClues] = rLo;
|
|
||||||
activeSHi[numClues] = rHi;
|
|
||||||
numClues++;
|
|
||||||
|
|
||||||
if ((rLo | rHi) != X) {
|
|
||||||
hasSlots = true;
|
|
||||||
if (Slot.horiz(key)) {
|
|
||||||
cHLo2 |= (cHLo & rLo);
|
|
||||||
cHHi2 |= (cHHi & rHi);
|
|
||||||
cHLo |= rLo;
|
|
||||||
cHHi |= rHi;
|
|
||||||
} else {
|
|
||||||
cVLo2 |= (cVLo & rLo);
|
|
||||||
cVHi2 |= (cVHi & rHi);
|
|
||||||
cVLo |= rLo;
|
|
||||||
cVHi |= rHi;
|
|
||||||
}
|
|
||||||
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
|
||||||
var wordLen = bitCount(rLo) + bitCount(rHi);
|
|
||||||
if (wordLen > 6) penalty += (wordLen - 6) * 1000L;
|
|
||||||
} else penalty += 25000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSlots) return 1_000_000_000L;
|
if (!hasSlots) return 1_000_000_000L;
|
||||||
|
penalty += (bitCount(cHLo2) + bitCount(cHHi2) + bitCount(cVLo2) + bitCount(cVHi2)) * 10000L;
|
||||||
|
|
||||||
Arrays.fill(rCount, 0);
|
Arrays.fill(rCount, 0);
|
||||||
Arrays.fill(cCount, 0);
|
Arrays.fill(cCount, 0);
|
||||||
for (var i = 0; i < numClues; i++) {
|
for (int i = 0; i < numClues; i++) {
|
||||||
var idx = activeCIdx[i];
|
int idx = activeCIdx[i];
|
||||||
rCount[idx & 7]++;
|
rCount[idx & 7]++;
|
||||||
cCount[idx >> 3]++;
|
cCount[idx >> 3]++;
|
||||||
}
|
}
|
||||||
for (var rc : rCount) if (rc < 2) penalty += (2 - rc) * 4000L;
|
for (int rc : rCount) {
|
||||||
for (var cc : cCount) if (cc < 2) penalty += (2 - cc) * 4000L;
|
if (rc < 2) penalty += (2 - rc) * 4000L;
|
||||||
|
if (rc > 4) penalty += (rc - 4) * 4000L;
|
||||||
// Connectiviteitscheck
|
}
|
||||||
for (var i = 0; i < numClues; i++) {
|
for (int cc : cCount) {
|
||||||
adjLo[i] = 0;
|
if (cc < 2) penalty += (2 - cc) * 4000L;
|
||||||
adjHi[i] = 0;
|
if (cc > 4) penalty += (cc - 4) * 4000L;
|
||||||
}
|
}
|
||||||
for (var i = 0; i < numClues; i++) {
|
|
||||||
for (var j = i + 1; j < numClues; j++) {
|
|
||||||
var connected = false;
|
|
||||||
// 1. Intersectie
|
|
||||||
if (((activeSLo[i] & activeSLo[j]) | (activeSHi[i] & activeSHi[j])) != 0) {
|
|
||||||
connected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connected) {
|
// Connectivity check
|
||||||
if (j < 64) adjLo[i] |= (1L << j);
|
for (int i = 0; i < numClues; i++) adjLo[i] = 0;
|
||||||
else adjHi[i] |= (1L << (j - 64));
|
for (int i = 0; i < numClues; i++) {
|
||||||
if (i < 64) adjLo[j] |= (1L << i);
|
for (int j = i + 1; j < numClues; j++) {
|
||||||
else adjHi[j] |= (1L << (i - 64));
|
if (((activeSLo[i] & activeSLo[j]) | (activeSHi[i] & activeSHi[j])) != 0) {
|
||||||
|
adjLo[i] |= (1L << j);
|
||||||
|
adjLo[j] |= (1L << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numClues > 0) {
|
if (numClues > 0) {
|
||||||
var maxReached = 0;
|
int maxReached = 0;
|
||||||
long totalReachedLo = 0, totalReachedHi = 0;
|
long totalReached = 0;
|
||||||
for (var i = 0; i < numClues; i++) {
|
for (int i = 0; i < numClues; i++) {
|
||||||
if (i < 64) { if ((totalReachedLo & (1L << i)) != 0) continue; } else { if ((totalReachedHi & (1L << (i - 64))) != 0) continue; }
|
if ((totalReached & (1L << i)) != 0) continue;
|
||||||
|
long currentReached = (1L << i);
|
||||||
var currentReachedLo = (i < 64) ? (1L << i) : 0;
|
|
||||||
var currentReachedHi = (i >= 64) ? (1L << (i - 64)) : 0;
|
|
||||||
stack[0] = i;
|
stack[0] = i;
|
||||||
var sp = 1;
|
int sp = 1, count = 0;
|
||||||
var count = 0;
|
|
||||||
while (sp > 0) {
|
while (sp > 0) {
|
||||||
var cur = stack[--sp];
|
int cur = stack[--sp];
|
||||||
count++;
|
count++;
|
||||||
var nLo = adjLo[cur] & ~currentReachedLo;
|
long neighbors = adjLo[cur] & ~currentReached;
|
||||||
var nHi = adjHi[cur] & ~currentReachedHi;
|
while (neighbors != 0) {
|
||||||
while (nLo != 0) {
|
long lsb = neighbors & -neighbors;
|
||||||
var lsb = nLo & -nLo;
|
currentReached |= lsb;
|
||||||
var idx = numberOfTrailingZeros(lsb);
|
stack[sp++] = numberOfTrailingZeros(lsb);
|
||||||
currentReachedLo |= lsb;
|
neighbors &= ~lsb;
|
||||||
stack[sp++] = idx;
|
|
||||||
nLo &= ~lsb;
|
|
||||||
}
|
|
||||||
while (nHi != 0) {
|
|
||||||
var lsb = nHi & -nHi;
|
|
||||||
var idx = 64 | numberOfTrailingZeros(lsb);
|
|
||||||
currentReachedHi |= lsb;
|
|
||||||
stack[sp++] = idx;
|
|
||||||
nHi &= ~lsb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count > maxReached) maxReached = count;
|
if (count > maxReached) maxReached = count;
|
||||||
totalReachedLo |= currentReachedLo;
|
totalReached |= currentReached;
|
||||||
totalReachedHi |= currentReachedHi;
|
|
||||||
}
|
}
|
||||||
if (maxReached < numClues) {
|
if (maxReached < numClues) {
|
||||||
penalty += (numClues - maxReached) * 4000L;
|
penalty += (numClues - maxReached) * 4000L;
|
||||||
@@ -422,57 +443,52 @@ public final class Masker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var bits = ~lo_cl & MASK_LO; bits != X; bits &= bits - 1) {
|
for (long bits = ~lo_cl & MASK_LO; bits != X; bits &= bits - 1) {
|
||||||
var clueIdx = numberOfTrailingZeros(bits);
|
int clueIdx = numberOfTrailingZeros(bits);
|
||||||
var rci = IT[clueIdx];
|
var rci = IT[clueIdx];
|
||||||
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 3000;
|
||||||
var h = (cHLo & (1L << clueIdx)) != X;
|
boolean h = (cHLo & (1L << clueIdx)) != X, v = (cVLo & (1L << clueIdx)) != X;
|
||||||
var v = (cVLo & (1L << clueIdx)) != X;
|
if (!h && !v) penalty += 4000;
|
||||||
if (!h && !v) penalty += 2000;
|
else if (h && v) { /* ok */ } else penalty += 1500;
|
||||||
else if (h && v) { /* ok */ } else if (((h ? cHLo2 : cVLo2) & (1L << clueIdx)) != X) penalty += 1000;
|
|
||||||
else penalty += 1000;
|
|
||||||
}
|
}
|
||||||
for (var bits = ~hi_cl & MASK_HI; bits != X; bits &= bits - 1) {
|
for (long bits = ~hi_cl & MASK_HI; bits != X; bits &= bits - 1) {
|
||||||
var clueIdx = numberOfTrailingZeros(bits);
|
int clueIdx = numberOfTrailingZeros(bits);
|
||||||
var rci = IT[64 | clueIdx];
|
var rci = IT[64 | clueIdx];
|
||||||
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 3000;
|
||||||
var h = (cHHi & (1L << clueIdx)) != X;
|
boolean h = (cHHi & (1L << clueIdx)) != X, v = (cVHi & (1L << clueIdx)) != X;
|
||||||
var v = (cVHi & (1L << clueIdx)) != X;
|
if (!h && !v) penalty += 4000;
|
||||||
if (!h && !v)
|
else if (h && v) { /* ok */ } else penalty += 1500;
|
||||||
penalty += 2000;
|
|
||||||
else if (h && v) { /* ok */ } else if (((h ? cHHi2 : cVHi2) & (1L << clueIdx)) != X) penalty += 1000;
|
|
||||||
else penalty += 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long remLo = lo_cl, remHi = hi_cl;
|
long remLo = lo_cl, remHi = hi_cl;
|
||||||
while ((remLo | remHi) != X) {
|
while ((remLo | remHi) != X) {
|
||||||
long compLo = 0, compHi = 0;
|
int start = (remLo != X) ? numberOfTrailingZeros(remLo) : (64 | numberOfTrailingZeros(remHi));
|
||||||
if (remLo != X) compLo = lowestOneBit(remLo);
|
stack[0] = start;
|
||||||
else compHi = lowestOneBit(remHi);
|
long currentCompLo = (start < 64) ? (1L << start) : 0;
|
||||||
long lastLo, lastHi;
|
long currentCompHi = (start >= 64) ? (1L << (start - 64)) : 0;
|
||||||
do {
|
int sp = 1, s = 0;
|
||||||
lastLo = compLo;
|
while (sp > 0) {
|
||||||
lastHi = compHi;
|
int cur = stack[--sp];
|
||||||
long expandedLo = 0, expandedHi = 0;
|
s++;
|
||||||
for (var bits = compLo; bits != X; bits &= bits - 1) {
|
long nLo = NBR_LO[cur] & lo_cl & ~currentCompLo;
|
||||||
var idx = numberOfTrailingZeros(bits);
|
long nHi = NBR_HI[cur] & hi_cl & ~currentCompHi;
|
||||||
expandedLo |= NBR_LO[idx];
|
while (nLo != 0) {
|
||||||
expandedHi |= NBR_HI[idx];
|
long lsb = nLo & -nLo;
|
||||||
|
currentCompLo |= lsb;
|
||||||
|
stack[sp++] = numberOfTrailingZeros(lsb);
|
||||||
|
nLo &= ~lsb;
|
||||||
}
|
}
|
||||||
for (var bits = compHi; bits != X; bits &= bits - 1) {
|
while (nHi != 0) {
|
||||||
var idx = 64 | numberOfTrailingZeros(bits);
|
long lsb = nHi & -nHi;
|
||||||
expandedLo |= NBR_LO[idx];
|
currentCompHi |= lsb;
|
||||||
expandedHi |= NBR_HI[idx];
|
stack[sp++] = 64 | numberOfTrailingZeros(lsb);
|
||||||
|
nHi &= ~lsb;
|
||||||
}
|
}
|
||||||
compLo |= expandedLo & lo_cl;
|
}
|
||||||
compHi |= expandedHi & hi_cl;
|
if (s >= 2) penalty += (long) (s - 1) * 3000;
|
||||||
} while (compLo != lastLo || compHi != lastHi);
|
remLo &= ~currentCompLo;
|
||||||
var s = bitCount(compLo) + bitCount(compHi);
|
remHi &= ~currentCompHi;
|
||||||
if (s >= 2) penalty += (long) (s - 1) * 720;
|
|
||||||
remLo &= ~compLo;
|
|
||||||
remHi &= ~compHi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
public static boolean hasRoomForClue(Clues c, int key) {
|
public static boolean hasRoomForClue(Clues c, int key) {
|
||||||
@@ -490,7 +506,7 @@ public final class Masker {
|
|||||||
var key = Slot.packSlotKey(ri, d_idx);
|
var key = Slot.packSlotKey(ri, d_idx);
|
||||||
if (hasRoomForClue(g, key)) {
|
if (hasRoomForClue(g, key)) {
|
||||||
g.setClueLo(1L << ri, d_idx);
|
g.setClueLo(1L << ri, d_idx);
|
||||||
if (isValid(g)) placed++;
|
if (isValid(g, ri)) placed++;
|
||||||
else g.clearClueLo(~(1L << ri));
|
else g.clearClueLo(~(1L << ri));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -499,7 +515,7 @@ public final class Masker {
|
|||||||
var key = Slot.packSlotKey(ri, d_idx);
|
var key = Slot.packSlotKey(ri, d_idx);
|
||||||
if (hasRoomForClue(g, key)) {
|
if (hasRoomForClue(g, key)) {
|
||||||
g.setClueHi(1L << (ri & 63), d_idx);
|
g.setClueHi(1L << (ri & 63), d_idx);
|
||||||
if (isValid(g)) placed++;
|
if (isValid(g, ri)) placed++;
|
||||||
else g.clearClueHi(~(1L << (ri & 63)));
|
else g.clearClueHi(~(1L << (ri & 63)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,11 +534,11 @@ public final class Masker {
|
|||||||
if (hasRoomForClue(c, key)) {
|
if (hasRoomForClue(c, key)) {
|
||||||
if (isLo(ri)) {
|
if (isLo(ri)) {
|
||||||
c.setClueLo(1L << ri, d);
|
c.setClueLo(1L << ri, d);
|
||||||
if (!isValid(c)) c.clearClueLo(~(1L << ri));
|
if (!isValid(c, ri)) c.clearClueLo(~(1L << ri));
|
||||||
else continue;
|
else continue;
|
||||||
} else {
|
} else {
|
||||||
c.setClueHi(1L << (ri & 63), d);
|
c.setClueHi(1L << (ri & 63), d);
|
||||||
if (!isValid(c)) c.clearClueHi(~(1L << (ri & 63)));
|
if (!isValid(c, ri)) c.clearClueHi(~(1L << (ri & 63)));
|
||||||
else continue;
|
else continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,11 +548,11 @@ public final class Masker {
|
|||||||
var oldD = c.getDir(ri);
|
var oldD = c.getDir(ri);
|
||||||
if (isLo(ri)) {
|
if (isLo(ri)) {
|
||||||
c.clearClueLo(~(1L << ri));
|
c.clearClueLo(~(1L << ri));
|
||||||
if (!isValid(c)) c.setClueLo(1L << ri, oldD);
|
if (!isValid(c, ri)) c.setClueLo(1L << ri, oldD);
|
||||||
else continue;
|
else continue;
|
||||||
} else {
|
} else {
|
||||||
c.clearClueHi(~(1L << (ri & 63)));
|
c.clearClueHi(~(1L << (ri & 63)));
|
||||||
if (!isValid(c)) c.setClueHi(1L << (ri & 63), oldD);
|
if (!isValid(c, ri)) c.setClueHi(1L << (ri & 63), oldD);
|
||||||
else continue;
|
else continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,11 +563,11 @@ public final class Masker {
|
|||||||
var oldD = c.getDir(ri);
|
var oldD = c.getDir(ri);
|
||||||
if (isLo(ri)) {
|
if (isLo(ri)) {
|
||||||
c.setClueLo(1L << ri, d);
|
c.setClueLo(1L << ri, d);
|
||||||
if (!isValid(c)) c.setClueLo(1L << ri, oldD);
|
if (!isValid(c, ri)) c.setClueLo(1L << ri, oldD);
|
||||||
else continue;
|
else continue;
|
||||||
} else {
|
} else {
|
||||||
c.setClueHi(1L << (ri & 63), d);
|
c.setClueHi(1L << (ri & 63), d);
|
||||||
if (!isValid(c)) c.setClueHi(1L << (ri & 63), oldD);
|
if (!isValid(c, ri)) c.setClueHi(1L << (ri & 63), oldD);
|
||||||
else continue;
|
else continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,7 +581,7 @@ public final class Masker {
|
|||||||
else c.clearClueHi(~(1L << (ri & 63)));
|
else c.clearClueHi(~(1L << (ri & 63)));
|
||||||
if (isLo(nri)) c.setClueLo(1L << nri, d);
|
if (isLo(nri)) c.setClueLo(1L << nri, d);
|
||||||
else c.setClueHi(1L << (nri & 63), d);
|
else c.setClueHi(1L << (nri & 63), d);
|
||||||
if (!isValid(c)) {
|
if (!isValid(c, -1)) { // For MOVE, it's easier to check full grid or we'd need to check both ri and nri
|
||||||
if (isLo(nri)) c.clearClueLo(~(1L << nri));
|
if (isLo(nri)) c.clearClueLo(~(1L << nri));
|
||||||
else c.clearClueHi(~(1L << (nri & 63)));
|
else c.clearClueHi(~(1L << (nri & 63)));
|
||||||
if (isLo(ri)) c.setClueLo(1L << ri, d);
|
if (isLo(ri)) c.setClueLo(1L << ri, d);
|
||||||
@@ -644,11 +660,11 @@ public final class Masker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var gen = 0; gen < gens; gen++) {
|
for (var gen = 0; gen < gens; gen++) {
|
||||||
if (Thread.currentThread().isInterrupted()) break;
|
if (Thread.currentThread().isInterrupted()) return null;
|
||||||
var children = new GridAndFit[offspring];
|
var children = new GridAndFit[offspring];
|
||||||
var childCount = 0;
|
var childCount = 0;
|
||||||
for (var k = 0; k < offspring; k++) {
|
for (var k = 0; k < offspring; k++) {
|
||||||
if (Thread.currentThread().isInterrupted()) break;
|
if (Thread.currentThread().isInterrupted()) return null;
|
||||||
var p1 = rng.rand(pop);
|
var p1 = rng.rand(pop);
|
||||||
var p2 = rng.rand(pop);
|
var p2 = rng.rand(pop);
|
||||||
var child = crossover(p1.grid, p2.grid);
|
var child = crossover(p1.grid, p2.grid);
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ public class Riddle {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val rec = Meta.lookupSilent(w);
|
val rec = Meta.lookupSilent(w);
|
||||||
System.out.println("\nQuery: w=" + w + " -> i=" + rec.mmap());
|
if (Main.VERBOSE) System.out.println("\nQuery: w=" + w + " -> i=" + rec.mmap());
|
||||||
var word1 = Lemma.asWord(w, bytes);
|
var word1 = Lemma.asWord(w, bytes);
|
||||||
System.out.println(" word=" + word1 + "\n" + " simpel=" + rec.simpel() + "\n" + " clues=" + Arrays.toString(rec.clues()));
|
if (Main.VERBOSE) System.out.println(" word=" + word1 + "\n" + " simpel=" + rec.simpel() + "\n" + " clues=" + Arrays.toString(rec.clues()));
|
||||||
return new ShaLemma(word1, rec);
|
return new ShaLemma(word1, rec);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|||||||
Reference in New Issue
Block a user