Gather data

This commit is contained in:
mike
2026-01-07 02:47:09 +01:00
parent 4593ccdc07
commit 1725b16dd1
2 changed files with 142 additions and 72 deletions

View File

@@ -41,6 +41,12 @@
<version>2.0.13</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -78,9 +78,11 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
int[] covV,
int[] cellCount,
int[] stack,
BitSet seen) {
BitSet seen,
char[] pattern,
IntList[] intListBuffer) {
public Context() { this(new int[256], new int[256], new int[256], new int[256], new BitSet(256)); }
public Context() { this(new int[256], new int[256], new int[256], new int[256], new BitSet(256), new char[32], new IntList[32]); }
}
static final ThreadLocal<Context> CTX = ThreadLocal.withInitial(Context::new);
@@ -278,28 +280,28 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
return Arrays.copyOf(buff, k);
}
CandidateInfo candidateInfoForPattern(DictEntry entry, char[] pattern) {
var lists = new ArrayList<IntList>();
for (var i = 0; i < pattern.length; i++) {
CandidateInfo candidateInfoForPattern(DictEntry entry, char[] pattern, int len) {
var ctx = CTX.get();
var listBuffer = ctx.intListBuffer;
int listCount = 0;
for (var i = 0; i < len; i++) {
var ch = pattern[i];
if (isLetter(ch)) {
lists.add(entry.pos[i][ch - 'A']);
listBuffer[listCount++] = entry.pos[i][ch - 'A'];
}
}
if (lists.isEmpty()) {
if (listCount == 0) {
return new CandidateInfo(null, entry.words.size());
}
var first = lists.get(0);
var cur = first.data();//Arrays.copyOf(first.data(), first.size());
var curLen = cur.length;
var first = listBuffer[0];
var cur = first.data();
var curLen = first.size();
for (var k = 1; k < lists.size(); k++) {
var nxt = lists.get(k);
var nextArr = nxt.data();
var nextLen = nxt.size();
cur = intersectSorted(buff, cur, curLen, nextArr, nextLen);
for (var k = 1; k < listCount; k++) {
var nxt = listBuffer[k];
cur = intersectSorted(buff, cur, curLen, nxt.data(), nxt.size());
curLen = cur.length;
if (curLen == 0) break;
}
@@ -312,13 +314,22 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
public int clueR() { return (key >> 8) & 15; }
public int clueC() { return (key >> 4) & 15; }
public int dir() { return key & 15; }
public boolean horiz() { return (dir() & 1) == 0; }
public int r(int i) { return (int) ((rs >> (i << 2)) & 15); }
public int c(int i) { return (int) ((cs >> (i << 2)) & 15); }
public boolean horiz() { return horiz(key); }
public int r(int i) { return r(rs, i); }
public int c(int i) { return c(cs, i); }
public static boolean horiz(int key) { return ((key & 15) & 1) == 0; }
public static int r(long rs, int i) { return (int) ((rs >> (i << 2)) & 15); }
public static int c(long cs, int i) { return (int) ((cs >> (i << 2)) & 15); }
}
ArrayList<Slot> extractSlots(Grid grid) {
var slots = new ArrayList<Slot>(64);
@FunctionalInterface
interface SlotVisitor {
void visit(int key, long rs, long cs, int len);
}
void forEachSlot(Grid grid, SlotVisitor visitor) {
for (var r = 0; r < H; r++) {
for (var c = 0; c < W; c++) {
if (!grid.isDigitAt(r, c)) continue;
@@ -343,9 +354,16 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
cc += dc;
if (n >= 12) break;
}
slots.add(new Slot((r << 8) | (c << 4) | d, packedRs, packedCs,n ));
if (n > 0) {
visitor.visit((r << 8) | (c << 4) | d, packedRs, packedCs, n);
}
}
}
}
ArrayList<Slot> extractSlots(Grid grid) {
var slots = new ArrayList<Slot>(64);
forEachSlot(grid, (key, rs, cs, len) -> slots.add(new Slot(key, rs, cs, len)));
return slots;
}
@@ -372,35 +390,59 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
var targetClues = (int) Math.round(SIZE * 0.25); // ~18
penalty += 8L * Math.abs(clueCount - targetClues);
var slots = extractSlots(grid);
if (slots.isEmpty()) return 1_000_000_000L;
var ctx = CTX.get();
var covH = ctx.covH;
var covV = ctx.covV;
Arrays.fill(covH, 0, SIZE, 0);
Arrays.fill(covV, 0, SIZE, 0);
for (var s : slots) {
if (s.len() < MIN_LEN) {
penalty += 8000;
}
/* else if (s.len > MAX_LEN) {
penalty += 8000 + (long) (s.len - MAX_LEN) * 500L;
throw new RuntimeException();
}*/
else {
if (lenCounts[s.len()] <= 0) penalty += 12000;
}
for (var i = 0; i < s.len(); i++) {
int r = s.r(i), c = s.c(i);
int idx = grid.offset(r, c);
if (s.horiz()) covH[idx] += 1;
else covV[idx] += 1;
boolean hasSlots = false;
for (var r = 0; r < H; r++) {
for (var c = 0; c < W; c++) {
if (!grid.isDigitAt(r, c)) continue;
var d = grid.digitAt(r, c);
int or = OFFSETS[d].x, oc = OFFSETS[d].y;
int dr = STEPS[d].x, dc = STEPS[d].y;
int rr = r + or, cc = c + oc;
if (rr < 0 || rr >= H || cc < 0 || cc >= W) continue;
if (grid.isDigitAt(rr, cc)) continue;
long packedRs = 0;
long packedCs = 0;
var n = 0;
while (rr >= 0 && rr < H && cc >= 0 && cc < W) {
if (grid.isDigitAt(rr, cc)) break;
packedRs |= (long) rr << (n << 2);
packedCs |= (long) cc << (n << 2);
n++;
rr += dr;
cc += dc;
if (n >= 12) break;
}
if (n == 0) continue;
hasSlots = true;
if (n < MIN_LEN) {
penalty += 8000;
} else {
if (lenCounts[n] <= 0) penalty += 12000;
}
boolean horiz = Slot.horiz((r << 8) | (c << 4) | d);
for (var i = 0; i < n; i++) {
int sr = Slot.r(packedRs, i);
int sc = Slot.c(packedCs, i);
int idx = grid.offset(sr, sc);
if (horiz) covH[idx] += 1;
else covV[idx] += 1;
}
}
}
if (!hasSlots) return 1_000_000_000L;
for (var r = 0; r < H; r++)
for (var c = 0; c < W; c++) {
if (grid.isDigitAt(r, c)) continue;
@@ -636,13 +678,12 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
}
}
static char[] patternForSlot(Grid grid, Slot s) {
var pat = new char[s.len()];
static int patternForSlot(Grid grid, Slot s, char[] pat) {
for (var i = 0; i < s.len(); i++) {
var ch = grid.getCharAt(s.r(i), s.c(i));
if (isLetter(ch)) pat[i] = ch;
pat[i] = isLetter(ch) ? ch : C_DASH;
}
return pat;
return s.len();
}
static int slotScore(int[] cellCount, Slot s, Grid grid) {
@@ -733,8 +774,8 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
return new Pick(null, null, false);
}
var pat = patternForSlot(grid, s);
var info = candidateInfoForPattern(entry, pat);
var patLen = patternForSlot(grid, s, ctx.pattern);
var info = candidateInfoForPattern(entry, ctx.pattern, patLen);
if (info.count == 0) {
return new Pick(null, null, false);
@@ -778,29 +819,8 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
var s = pick.slot;
var k = s.key();
var entry = dictIndex[s.len()];
var pat = patternForSlot(grid, s);
Predicate<Lemma> tryWord = (Lemma w) -> {
if (used.get(w.index())) return false;
for (var i = 0; i < pat.length; i++) {
// if ((pat[i] != w.charAt(i)) != (pat[i] != C_DASH)) throw new RuntimeException("word does not match pattern");
if (pat[i] != C_DASH && pat[i] != w.charAt(i)) return false;
}
var undo = placeWord(grid, s, w);
if (undo == null) return false;
used.set(w.index());
assigned.put(k, w);
if (backtrack()) return true;
assigned.remove(k);
used.set(w.index, false);
undoPlace(grid, undo);
return false;
};
var pat = new char[s.len()];
patternForSlot(grid, s, pat);
if (pick.info.indices != null && pick.info.indices.length > 0) {
var idxs = pick.info.indices;
@@ -815,7 +835,29 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
int idxInArray = (int) (r * r * r * L);
var idx = idxs[idxInArray];
var w = entry.words.get(idx);
if (tryWord.test(w)) return true;
if (used.get(w.index())) continue;
boolean match = true;
for (var i = 0; i < pat.length; i++) {
if (pat[i] != C_DASH && pat[i] != w.charAt(i)) {
match = false;
break;
}
}
if (!match) continue;
var undo = placeWord(grid, s, w);
if (undo == null) continue;
used.set(w.index());
assigned.put(k, w);
if (backtrack()) return true;
assigned.remove(k);
used.set(w.index, false);
undoPlace(grid, undo);
}
stats.backtracks++;
return false;
@@ -832,7 +874,29 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
double r = rng.nextFloat();
int idxInArray = (int) (r * r * r * N);
var w = entry.words.get(idxInArray);
if (tryWord.test(w)) return true;
if (used.get(w.index())) continue;
boolean match = true;
for (var i = 0; i < pat.length; i++) {
if (pat[i] != C_DASH && pat[i] != w.charAt(i)) {
match = false;
break;
}
}
if (!match) continue;
var undo = placeWord(grid, s, w);
if (undo == null) continue;
used.set(w.index());
assigned.put(k, w);
if (backtrack()) return true;
assigned.remove(k);
used.set(w.index, false);
undoPlace(grid, undo);
}
stats.backtracks++;