From 948ba91467fa448e2916fcfd0b08f9e67acad206 Mon Sep 17 00:00:00 2001 From: mike Date: Sat, 10 Jan 2026 09:32:46 +0100 Subject: [PATCH] introduce bitloops --- src/main/java/puzzle/SwedishGenerator.java | 106 +++++++++------------ 1 file changed, 43 insertions(+), 63 deletions(-) diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index ccfb8fe..93a6d7d 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -395,76 +395,49 @@ public record SwedishGenerator(Rng rng) { long maskFitness(Grid grid) { - var clueCount = grid.clueCount(); - long penalty = ((long) Math.abs(clueCount - TARGET_CLUES)) << 3; - var ctx = CTX.get(); var covH = ctx.covH; var covV = ctx.covV; Arrays.fill(covH, 0, SIZE, 0); Arrays.fill(covV, 0, SIZE, 0); - boolean hasSlots = false; - long lo_cl = grid.bo[0], hi_cl = grid.bo[1]; - while (lo_cl != 0L) { - int clueIdx = Long.numberOfTrailingZeros(lo_cl); - lo_cl &= (lo_cl - 1); - var d = grid.digitAt(clueIdx); - var nbrs16 = OFFSETS[d]; - long packed = nbrs16.path()[clueIdx]; - int n = (int) (packed >>> 56), k, idx; - var horiz = Slot.horiz(d) ? covH : covV; - for (k = 0; k < n && k < MAX_WORD_LENGTH; k++) { - idx = (int) ((packed >>> (k * 7)) & 0x7F); - if (grid.isClue(idx)) break; - horiz[idx] += 1; - } - if (k == 0) continue; - hasSlots = true; - if (k < MIN_LEN) penalty += 8000; - } - while (hi_cl != 0L) { - int clueIdx = 64 + Long.numberOfTrailingZeros(hi_cl); - hi_cl &= (hi_cl - 1); - var d = grid.digitAt(clueIdx); - var nbrs16 = OFFSETS[d]; - long packed = nbrs16.path()[clueIdx]; - int n = (int) (packed >>> 56), k, idx; - var horiz = Slot.horiz(d) ? covH : covV; - for (k = 0; k < n && k < MAX_WORD_LENGTH; k++) { - idx = (int) ((packed >>> (k * 7)) & 0x7F); - if (grid.isClue(idx)) break; - horiz[idx] += 1; - } - if (k == 0) continue; - hasSlots = true; - if (k < MIN_LEN) penalty += 8000; - } - - if (!hasSlots) return 1_000_000_000L; + long lo_cl = grid.bo[0], hi_cl = grid.bo[1]; // clue clustering (8-connected) - var seen = ctx.seen; - seen.clear(); + var seen = ctx.seen; var stack = ctx.stack; class Mask { - long penalty; - Mask(long pen) { this.penalty = pen; } + long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) << 3); + boolean hasSlots = false; + void space(int clueIdx) { + var d = grid.digitAt(clueIdx); + var nbrs16 = OFFSETS[d]; + long packed = nbrs16.path()[clueIdx]; + int n = (int) (packed >>> 56), k, idx; + var horiz = Slot.horiz(d) ? covH : covV; + for (k = 0; k < n && k < MAX_WORD_LENGTH; k++) { + idx = (int) ((packed >>> (k * 7)) & 0x7F); + if (grid.isClue(idx)) break; + horiz[idx] += 1; + } + if (k == 0) return; + hasSlots = true; + if (k < MIN_LEN) penalty += 8000; + } + void clueStackPenalty(int clueIdx) { - if (seen.get(clueIdx)) ; - var sp = 0; - stack[sp++] = clueIdx; + if (seen.get(clueIdx)) return; + int size = 0; + long packed; + stack[0] = clueIdx; seen.set(clueIdx); - var size = 0; - while (sp > 0) { - var p = stack[--sp]; - size++; - long packed = Neighbors9x8.NBR8_PACKED[p]; - int n = (int) (packed >>> 56); - for (int k = 0; k < n; k++) { - int nidx = (int) ((packed >>> (k * 7)) & 0x7F); + for (int sp = 1, n, nidx, k; sp > 0; size++) { + packed = Neighbors9x8.NBR8_PACKED[stack[--sp]]; + n = (int) (packed >>> 56); + for (k = 0; k < n; k++) { + nidx = (int) ((packed >>> (k * 7)) & 0x7F); if (seen.get(nidx) || grid.notClue(nidx)) continue; seen.set(nidx); stack[sp++] = nidx; @@ -473,7 +446,7 @@ public record SwedishGenerator(Rng rng) { if (size >= 2) this.penalty += ((size - 1L) * 120L); } void wall(rci rci) { - if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & grid.bo[0]) + Long.bitCount(rci.n2() & grid.bo[1]) >= 3) this.penalty += 400; + if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) this.penalty += 400; var h = covH[rci.i()]; var v = covV[rci.i()]; if (h == 0 && v == 0) this.penalty += 1500; @@ -482,12 +455,19 @@ public record SwedishGenerator(Rng rng) { } } - val mask = new Mask(penalty); - for (var lo = grid.bo[0]; lo != 0; lo &= lo - 1) mask.clueStackPenalty(Long.numberOfTrailingZeros(lo)); - for (var hi = grid.bo[1]; hi != 0; hi &= hi - 1) mask.clueStackPenalty(64 + Long.numberOfTrailingZeros(hi)); + val space = new Mask(); + for (var lo = lo_cl; lo != 0L; lo &= lo - 1) space.space(Long.numberOfTrailingZeros(lo)); + for (var hi = hi_cl; hi != 0L; hi &= hi - 1) space.space(64 + Long.numberOfTrailingZeros(hi)); + if (!space.hasSlots) return 1_000_000_000L; + seen.clear(); + for (var lo = lo_cl; lo != 0L; lo &= lo - 1) space.clueStackPenalty(Long.numberOfTrailingZeros(lo)); + for (var hi = hi_cl; hi != 0L; hi &= hi - 1) space.clueStackPenalty(64 + Long.numberOfTrailingZeros(hi)); + for (var lo = ~lo_cl; lo != 0L; lo &= lo - 1) space.wall(IT[Long.numberOfTrailingZeros(lo)]); + for (var hi = ~hi_cl & 0xFFL; hi != 0L; hi &= hi - 1) space.wall(IT[64 + Long.numberOfTrailingZeros(hi)]); + //for (var rci : IT) if (grid.notClue(rci.i())) space.wall(rci); // dead-end-ish letter cell (3+ walls) - int walls, wc, wr; + // int walls, wc, wr; /* for (var rci : IT) { if (grid.isDigitAt(rci.i())) continue; walls = 0; @@ -498,8 +478,8 @@ public record SwedishGenerator(Rng rng) { } if (walls >= 3) penalty[0] += 400; }*/ - for (var rci : IT) if (grid.notClue(rci.i())) mask.wall(rci); - return mask.penalty; + + return space.penalty; } Grid randomMask() {