From 1725b16dd1df3f3fc3c4fafdfcda44751d58ab8b Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 7 Jan 2026 02:47:09 +0100 Subject: [PATCH] Gather data --- pom.xml | 6 + src/main/java/puzzle/SwedishGenerator.java | 208 ++++++++++++++------- 2 files changed, 142 insertions(+), 72 deletions(-) diff --git a/pom.xml b/pom.xml index 55c38ee..189a633 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,12 @@ 2.0.13 runtime + + org.junit.jupiter + junit-jupiter + RELEASE + test + diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 67d6c9a..bc54662 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -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 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(); - 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 extractSlots(Grid grid) { - var slots = new ArrayList(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 extractSlots(Grid grid) { + var slots = new ArrayList(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 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++;