diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 3d6b144..6452dd5 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -80,9 +80,10 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) int[] stack, BitSet seen, char[] pattern, - IntList[] intListBuffer) { + IntList[] intListBuffer, + long[] undoBuffer) { - public Context() { this(new int[256], new int[256], new int[256], new int[256], new BitSet(256), new char[32], new IntList[32]); } + public Context() { this(new int[256], new int[256], new int[256], new int[256], new BitSet(256), new char[32], new IntList[32], new long[2048]); } } static final ThreadLocal CTX = ThreadLocal.withInitial(Context::new); @@ -295,6 +296,17 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) return new CandidateInfo(null, entry.words.size()); } + // Sort constraints by size to optimize intersection + for (int i = 0; i < listCount - 1; i++) { + for (int j = i + 1; j < listCount; j++) { + if (listBuffer[j].size() < listBuffer[i].size()) { + var tmp = listBuffer[i]; + listBuffer[i] = listBuffer[j]; + listBuffer[j] = tmp; + } + } + } + var first = listBuffer[0]; var cur = first.data(); var curLen = first.size(); @@ -322,7 +334,12 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) 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); } } - + static void undoPlace(Grid grid, long[] undoBuffer, int offset, int n) { + for (var i = 0; i < n; i++) { + long v = undoBuffer[offset + i]; + grid.setCharAt((int) (v >> 16) & 0xFF, (int) (v >> 8) & 0xFF, (char) (v & 0xFF)); + } + } @FunctionalInterface interface SlotVisitor { @@ -352,7 +369,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) n++; rr += dr; cc += dc; - if (n >= 12) break; + if (n >= MAX_LEN) break; } if (n > 0) { visitor.visit((r << 8) | (c << 4) | d, packedRs, packedCs, n); @@ -419,7 +436,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) n++; rr += dr; cc += dc; - if (n >= 12) break; + if (n >= MAX_LEN) break; } if (n == 0) continue; hasSlots = true; @@ -646,7 +663,6 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) return pop.get(0); } record UndoPlace(int ur, int uc, char up) { } - // ---------------- Fill (CSP) ---------------- record Undo(UndoPlace[] ur, int n) { } @@ -692,10 +708,32 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) return cross * 10 + s.len(); } + static int placeWord(Grid grid, Slot s, Lemma w, long[] undoBuffer, int offset) { + int n = 0; + for (var i = 0; i < s.len(); i++) { + int r = s.r(i), c = s.c(i); + char cur = grid.getCharAt(r, c); + var ch = w.charAt(i); + if (cur == C_DASH) { + undoBuffer[offset + n] = ((long) r << 16) | ((long) c << 8) | (long) C_DASH; + n++; + grid.setCharAt(r, c, ch); + } else { + if (cur != ch) { + for (var j = 0; j < n; j++) { + long v = undoBuffer[offset + j]; + grid.setCharAt((int) (v >> 16) & 0xFF, (int) (v >> 8) & 0xFF, (char) (v & 0xFF)); + } + return -1; + } + } + } + return n; + } + /* static Undo placeWord(Grid grid, Slot s, Lemma w) { var ur = new UndoPlace[s.len()]; var n = 0; - for (var i = 0; i < s.len(); i++) { int r = s.r(i), c = s.c(i); char cur = grid.getCharAt(r, c); @@ -713,7 +751,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) } } return new Undo(ur, n); - } + }*/ static void undoPlace(Grid grid, Undo u) { for (var i = 0; i < u.n; i++) grid.setCharAt(u.ur[i]); @@ -796,11 +834,10 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) return new Pick(best, bestInfo, false); } }; - System.out.println("hit"); class Solver { - boolean backtrack() { + boolean backtrack(int depth) { if (Thread.currentThread().isInterrupted()) return false; stats.nodes++; @@ -815,13 +852,14 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) stats.lastMRV = pick.info.count; renderProgress.run(); + var s = pick.slot; var k = s.key(); var entry = dictIndex[s.len()]; var pat = new char[s.len()]; - patternForSlot(grid, s, pat); - + int patLen = patternForSlot(grid, s, pat); + int undoOffset = depth * SIZE; if (pick.info.indices != null && pick.info.indices.length > 0) { var idxs = pick.info.indices; var L = idxs.length; @@ -836,7 +874,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) if (used.get(w.index())) continue; boolean match = true; - for (var i = 0; i < pat.length; i++) { + for (var i = 0; i < patLen; i++) { if (pat[i] != C_DASH && pat[i] != w.charAt(i)) { match = false; break; @@ -844,17 +882,17 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) } if (!match) continue; - var undo = placeWord(grid, s, w); - if (undo == null) continue; + int nPlaced = placeWord(grid, s, w, ctx.undoBuffer, undoOffset); + if (nPlaced < 0) continue; used.set(w.index()); assigned.put(k, w); - if (backtrack()) return true; + if (backtrack(depth+1)) return true; assigned.remove(k); used.set(w.index, false); - undoPlace(grid, undo); + undoPlace(grid, ctx.undoBuffer, undoOffset, nPlaced); } stats.backtracks++; return false; @@ -875,7 +913,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) if (used.get(w.index())) continue; boolean match = true; - for (var i = 0; i < pat.length; i++) { + for (var i = 0; i < patLen; i++) { if (pat[i] != C_DASH && pat[i] != w.charAt(i)) { match = false; break; @@ -883,17 +921,17 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) } if (!match) continue; - var undo = placeWord(grid, s, w); - if (undo == null) continue; + int nPlaced = placeWord(grid, s, w, ctx.undoBuffer, undoOffset); + if (nPlaced < 0) continue; used.set(w.index()); assigned.put(k, w); - if (backtrack()) return true; + if (backtrack(depth+1)) return true; assigned.remove(k); used.set(w.index, false); - undoPlace(grid, undo); + undoPlace(grid, ctx.undoBuffer, undoOffset, nPlaced); } stats.backtracks++; @@ -903,7 +941,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) // initial render (same feel) renderProgress.run(); - var ok = new Solver().backtrack(); + var ok = new Solver().backtrack(0); // final progress line System.out.print("\r" + padRight("", 120) + "\r"); System.out.flush();