From 69af69a8b844129c642eee1a159b5d302b7ff9db Mon Sep 17 00:00:00 2001 From: mike Date: Wed, 14 Jan 2026 09:59:24 +0100 Subject: [PATCH] introduce bitloops --- src/main/java/puzzle/SwedishGenerator.java | 44 ++++++++----------- src/test/java/puzzle/MainTest.java | 10 ++++- .../java/puzzle/SwedishGeneratorTest.java | 14 ++++-- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index bba262e..c0ab69a 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -286,17 +286,17 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { /// the pos will never target a clue public byte letter32At(int pos) { return g[pos]; } void setLetterLo(int idx, byte ch) { - lo &= ~(1L << idx); + lo |= (1L << idx); g[idx] = ch; } void setLetterHi(int idx, byte ch) { - hi &= ~(1L << idx & 63); + hi |= (1L << (idx & 63)); g[idx] = ch; } void setLetter(int idx, byte ch) { - if ((idx & 64)==0) + if ((idx & 64) == 0) setLetterLo(idx, ch); else setLetterHi(idx, ch); @@ -305,12 +305,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { private void clearletterLo(int idx) { g[idx] = DASH; - lo |= (1L << idx); + lo &= ~(1L << idx); } private void clearletterHi(int idx) { g[idx] = DASH; - hi |= (1L << idx & 63); + hi &= ~(1L << (idx & 63)); } void undoPlace(long maskLo, long maskHi) { for (long b = maskLo; b != 0; b &= b - 1) clearletterLo(Long.numberOfTrailingZeros(b)); @@ -747,45 +747,37 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { } static long patternForSlot(Grid grid, Slot s) { - if ((s.lo & ~grid.lo) == 0 && (s.hi & ~grid.hi) == 0) { + if ((s.lo & grid.lo) == 0 && (s.hi & grid.hi) == 0) { return 0; } long p = 0; if (s.increasing()) { - for (long b = s.lo & ~grid.lo; b != 0; b &= b - 1) { + for (long b = s.lo & grid.lo; b != 0; b &= b - 1) { int idx = Long.numberOfTrailingZeros(b); byte val = grid.g[idx]; - if (val != DASH) { - int i = Long.bitCount(s.lo & ((1L << idx) - 1)); - p |= ((long) (i * 26 + val)) << (i << 3); - } + int i = Long.bitCount(s.lo & ((1L << idx) - 1)); + p |= ((long) (i * 26 + val)) << (i << 3); } int offset = Long.bitCount(s.lo); - for (long b = s.hi & ~grid.hi; b != 0; b &= b - 1) { + for (long b = s.hi & grid.hi; b != 0; b &= b - 1) { int idx = Long.numberOfTrailingZeros(b); byte val = grid.g[64 | idx]; - if (val != DASH) { - int i = offset + Long.bitCount(s.hi & ((1L << idx) - 1)); - p |= ((long) (i * 26 + val)) << (i << 3); - } + int i = offset + Long.bitCount(s.hi & ((1L << idx) - 1)); + p |= ((long) (i * 26 + val)) << (i << 3); } } else { int offset = Long.bitCount(s.hi); - for (long b = s.hi & ~grid.hi; b != 0; b &= b - 1) { + for (long b = s.hi & grid.hi; b != 0; b &= b - 1) { int idx = Long.numberOfTrailingZeros(b); byte val = grid.g[64 | idx]; - if (val != DASH) { - int i = Long.bitCount(s.hi & ~((1L << idx) | ((1L << idx) - 1))); - p |= ((long) (i * 26 + val)) << (i << 3); - } + int i = Long.bitCount(s.hi & ~((1L << idx) | ((1L << idx) - 1))); + p |= ((long) (i * 26 + val)) << (i << 3); } - for (long b = s.lo & ~grid.lo; b != 0; b &= b - 1) { + for (long b = s.lo & grid.lo; b != 0; b &= b - 1) { int idx = Long.numberOfTrailingZeros(b); byte val = grid.g[idx]; - if (val != DASH) { - int i = offset + Long.bitCount(s.lo & ~((1L << idx) | ((1L << idx) - 1))); - p |= ((long) (i * 26 + val)) << (i << 3); - } + int i = offset + Long.bitCount(s.lo & ~((1L << idx) | ((1L << idx) - 1))); + p |= ((long) (i * 26 + val)) << (i << 3); } } return p; diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index 0aa2e2e..eb6334f 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -109,6 +109,12 @@ public class MainTest { Assertions.assertEquals(LETTER_Z, grid.letter32At(OFF_2_3)); Assertions.assertEquals(DASH, grid.letter32At(OFF_1_1)); + // Verify letter mask + Assertions.assertTrue((grid.lo & (1L << OFF_0_0)) != 0); + Assertions.assertTrue((grid.lo & (1L << OFF_2_3)) != 0); + Assertions.assertTrue((grid.lo & (1L << OFF_1_2)) != 0); // Clue also in lo + Assertions.assertTrue((grid.lo & (1L << OFF_1_1)) == 0); // Empty letter cell + // Test isLetterAt Assertions.assertTrue(clues.notClue(OFF_0_0)); Assertions.assertFalse(clues.notClue(OFF_1_2)); @@ -181,8 +187,8 @@ public class MainTest { Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(18, filled.wordCount(), "Number of assigned words changed"); Assertions.assertEquals("SLEDE", Lemma.asWord(filled.clueMap()[282])); - Assertions.assertEquals(74732156493031040L, filled.grid().grid().lo); - Assertions.assertEquals(193L, filled.grid().grid().hi); + Assertions.assertEquals(-1L, filled.grid().grid().lo); + Assertions.assertEquals(255L, filled.grid().grid().hi); var aa = new PuzzleResult(new Clued(mask), filled).exportFormatFromFilled(1, new Rewards(1, 1, 1)); diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index 41a0fd7..a27b455 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -77,7 +77,10 @@ public class SwedishGeneratorTest { static final byte D_BYTE_2 = CLUE_RIGHT; @Test void testPatternForSlotAllLetters() { - var grid = new Grid(new byte[]{ LETTER_A, LETTER_B, LETTER_C }, 0, 0); + var grid = createEmpty(); + grid.setLetter(0, LETTER_A); + grid.setLetter(1, LETTER_B); + grid.setLetter(2, LETTER_C); var slot = Slot.from(18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L); var pattern = patternForSlot(grid, slot); @@ -86,7 +89,9 @@ public class SwedishGeneratorTest { @Test void testPatternForSlotMixed() { - var grid = new Grid(new byte[]{ LETTER_A, DASH, LETTER_C }, 0, 0); + var grid = createEmpty(); + grid.setLetter(0, LETTER_A); + grid.setLetter(2, LETTER_C); var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L); var pattern = patternForSlot(grid, slot); @@ -95,7 +100,7 @@ public class SwedishGeneratorTest { @Test void testPatternForSlotAllDashes() { - var grid = new Grid(new byte[]{ DASH, DASH, DASH }, 0, 0); // - - - + var grid = createEmpty(); var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L); var pattern = patternForSlot(grid, slot); @@ -104,7 +109,8 @@ public class SwedishGeneratorTest { @Test void testPatternForSlotSingleLetter() { - var grid = new Grid(new byte[]{ LETTER_A, DASH, DASH }, 0, 0); + var grid = createEmpty(); + grid.setLetter(0, LETTER_A); var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L); var pattern = patternForSlot(grid, slot);