From b1f54c2cae844593abb8e4fdd0de0912ba99719a Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 14 Jan 2026 13:12:21 +0100 Subject: [PATCH] introduce bitloops --- src/main/java/puzzle/SwedishGenerator.java | 155 +++++++++++---------- src/test/java/puzzle/MainTest.java | 16 +-- 2 files changed, 90 insertions(+), 81 deletions(-) diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 8b21a6c..15273c6 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -57,6 +57,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { static final int SIZE = C * R;// ~18 static final int SIZE_MIN_1 = SIZE - 1;// ~18 static final double SIZED = (double) SIZE;// ~18 + static final long MASK_LO = (SIZE >= 64) ? -1L : (1L << SIZE) - 1; + static final long MASK_HI = (SIZE <= 64) ? 0L : (SIZE >= 128 ? -1L : (1L << (SIZE - 64)) - 1); static final int TARGET_CLUES = SIZE >>> 2; static final int MAX_WORD_LENGTH = C <= R ? C : R; static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1; @@ -249,15 +251,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { long matchLo = (~(lo ^ b.lo)) & (~lo | (~(vlo ^ b.vlo) & ~(rlo ^ b.rlo))); long matchHi = (~(hi ^ b.hi)) & (~hi | (~(vhi ^ b.vhi) & ~(rhi ^ b.rhi))); - long maskLo = (SIZE >= 64) ? -1L : (1L << SIZE) - 1; - long maskHi = (SIZE <= 64) ? 0L : (1L << (SIZE - 64)) - 1; - - return (Long.bitCount(matchLo & maskLo) + Long.bitCount(matchHi & maskHi)) / SIZED; - - - /* var same = 0; - for (int i = 0; i < SIZE; i++) if (digitAt(i) == b.digitAt(i)) same++; - return same / SIZED;*/ + return (Long.bitCount(matchLo & MASK_LO) + Long.bitCount(matchHi & MASK_HI)) / SIZED; } public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); } public void forEachSlot(SlotVisitor visitor) { @@ -452,49 +446,78 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) * 16000L); boolean hasSlots = false; - for (int i = 0; i < 65; i += 64) { - for (long bits = (i == 0 ? lo_cl : hi_cl); bits != X; bits &= bits - 1) { - int clueIdx = i | Long.numberOfTrailingZeros(bits); - int key = Slot.packSlotDir(clueIdx, grid.digitAt(clueIdx)); - /// long clueBits = (i == 0 ? lo_cl : hi_cl); - /// long vBits = (i == 0 ? grid.vlo : grid.vhi); - /// long rBits = (i == 0 ? grid.rlo : grid.rhi); - /// for (long bits = clueBits; bits != X; bits &= bits - 1) { - /// long lsb = bits & -bits; - /// int clueIdx = i | Long.numberOfTrailingZeros(lsb); - /// int v = (vBits & lsb) != 0 ? 1 : 0; - /// int r = (rBits & lsb) != 0 ? 1 : 0; - /// int key = Slot.packSlotDir(clueIdx, (r << 1) | v); - long rLo = PATH_LO[key], rHi = PATH_HI[key]; - long hLo = rLo & lo_cl, hHi = rHi & hi_cl; - if (Slot.increasing(key)) { - if (hLo != X) { - rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1); - rHi = 0; - } else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); } - } else { - if (hHi != X) { - int msb = 63 - Long.numberOfLeadingZeros(hHi); - rHi &= ~((1L << msb << 1) - 1); - rLo = 0; - } else if (hLo != X) { - int msb = 63 - Long.numberOfLeadingZeros(hLo); - rLo &= ~((1L << msb << 1) - 1); - } + for (long bits = lo_cl; bits != X; bits &= bits - 1) { + long lsb = bits & -bits; + int clueIdx = Long.numberOfTrailingZeros(lsb); + int v = (grid.vlo & lsb) != 0 ? 1 : 0; + int r = (grid.rlo & lsb) != 0 ? 1 : 0; + int key = Slot.packSlotDir(clueIdx, (r << 1) | v); + long rLo = PATH_LO[key], rHi = PATH_HI[key]; + long hLo = rLo & lo_cl, hHi = rHi & hi_cl; + if (Slot.increasing(key)) { + if (hLo != X) { + rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1); + rHi = 0; + } else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); } + } else { + if (hHi != X) { + int msb = 63 - Long.numberOfLeadingZeros(hHi); + rHi &= ~((1L << msb << 1) - 1); + rLo = 0; + } else if (hLo != X) { + int msb = 63 - Long.numberOfLeadingZeros(hLo); + rLo &= ~((1L << msb << 1) - 1); } - if ((rLo | rHi) != X) { - hasSlots = true; - if (Slot.horiz(key)) { - cHLo |= rLo; - cHHi |= rHi; - } else { - cVLo |= rLo; - cVHi |= rHi; - } - if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000; + } + if ((rLo | rHi) != X) { + hasSlots = true; + if (Slot.horiz(key)) { + cHLo |= rLo; + cHHi |= rHi; } else { - penalty += 25000; + cVLo |= rLo; + cVHi |= rHi; } + if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000; + } else { + penalty += 25000; + } + } + for (long bits = hi_cl; bits != X; bits &= bits - 1) { + long lsb = bits & -bits; + int clueIdx = Long.numberOfTrailingZeros(lsb); + int v = (grid.vhi & lsb) != 0 ? 1 : 0; + int r = (grid.rhi & lsb) != 0 ? 1 : 0; + int key = Slot.packSlotDir(64 | clueIdx, (r << 1) | v); + long rLo = PATH_LO[key], rHi = PATH_HI[key]; + long hLo = rLo & lo_cl, hHi = rHi & hi_cl; + if (Slot.increasing(key)) { + if (hLo != X) { + rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1); + rHi = 0; + } else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); } + } else { + if (hHi != X) { + int msb = 63 - Long.numberOfLeadingZeros(hHi); + rHi &= ~((1L << msb << 1) - 1); + rLo = 0; + } else if (hLo != X) { + int msb = 63 - Long.numberOfLeadingZeros(hLo); + rLo &= ~((1L << msb << 1) - 1); + } + } + if ((rLo | rHi) != X) { + hasSlots = true; + if (Slot.horiz(key)) { + cHLo |= rLo; + cHHi |= rHi; + } else { + cVLo |= rLo; + cVHi |= rHi; + } + if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000; + } else { + penalty += 25000; } } @@ -614,35 +637,21 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { var nc = Math.cos(theta); var nr = Math.sin(theta); + long maskLo = 0, maskHi = 0; for (var rci : IT) { - int i = rci.i(); if ((rci.cross_r()) * nc + (rci.cross_c()) * nr < 0) { - var ch = other.digitAt(i); - if (out.digitAt(i) != ch) { - if (other.isClue(i)) { - out.setClue(i, ch); - } else { - out.clearClue(i); - } - } + int i = rci.i(); + if ((i & 64) == 0) maskLo |= (1L << i); + else maskHi |= (1L << (i - 64)); } } - // long maskLo = 0, maskHi = 0; - // for (var rci : IT) { - // if ((rci.cross_r()) * nc + (rci.cross_c()) * nr < 0) { - // int i = rci.i(); - // if (i < 64) maskLo |= (1L << i); - // else maskHi |= (1L << (i - 64)); - // } - // } - // - // out.lo = (out.lo & ~maskLo) | (other.lo & maskLo); - // out.hi = (out.hi & ~maskHi) | (other.hi & maskHi); - // out.vlo = (out.vlo & ~maskLo) | (other.vlo & maskLo); - // out.vhi = (out.vhi & ~maskHi) | (other.vhi & maskHi); - // out.rlo = (out.rlo & ~maskLo) | (other.rlo & maskLo); - // out.rhi = (out.rhi & ~maskHi) | (other.rhi & maskHi); + out.lo = (out.lo & ~maskLo) | (other.lo & maskLo); + out.hi = (out.hi & ~maskHi) | (other.hi & maskHi); + out.vlo = (out.vlo & ~maskLo) | (other.vlo & maskLo); + out.vhi = (out.vhi & ~maskHi) | (other.vhi & maskHi); + out.rlo = (out.rlo & ~maskLo) | (other.rlo & maskLo); + out.rhi = (out.rhi & ~maskHi) | (other.rhi & maskHi); for (var lo = out.lo; lo != X; lo &= lo - 1L) clearClues(out, Long.numberOfTrailingZeros(lo)); for (var hi = out.hi; hi != X; hi &= hi - 1L) clearClues(out, 64 | Long.numberOfTrailingZeros(hi)); diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index def2413..d03d6e4 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -162,14 +162,14 @@ public class MainTest { var mask = swe.generateMask(opts.pop, opts.gens, Math.max(opts.pop, (int) Math.floor(opts.pop * 1.5))); val clued = new Clued(mask); val test = clued.gridToString(); - val RESULT = " 3 300\n" + - " 1 \n" + - " 1 \n" + - " 3 0 \n" + - " 31 \n" + - " 1 \n" + - " 1 2\n" + - "21 22 3"; + val RESULT = "001 \n" + + " 3 3\n" + + " 3\n" + + " 3\n" + + " 21 1 \n" + + " 3 \n" + + "221 1 \n" + + "1 22"; Assertions.assertEquals(18, clued.clueCount(), "Found seed changed"); Assertions.assertEquals(RESULT, test, "Found seed changed");