From 67eedb773b5bf00031fd4f0815e8824759ef4f10 Mon Sep 17 00:00:00 2001 From: mike Date: Mon, 12 Jan 2026 09:42:13 +0100 Subject: [PATCH] introduce bitloops --- src/main/java/puzzle/SwedishGenerator.java | 42 ++++++------------- src/test/java/puzzle/ExportFormatTest.java | 2 +- .../java/puzzle/SwedishGeneratorTest.java | 38 ++++++++--------- 3 files changed, 32 insertions(+), 50 deletions(-) diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 39b7448..f4b9fcb 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -31,10 +31,7 @@ import static java.nio.charset.StandardCharsets.*; @SuppressWarnings("ALL") public record SwedishGenerator(Rng rng) { - record CandidateInfo(int[] indices, int count) { - - public CandidateInfo(int n) { this(null, n); } - } + record CandidateInfo(int[] indices, int count) { } // static final CandidateInfo[] CANDIDATES = IntStream.range(0, 10192 << 2).mapToObj(CandidateInfo::new).toArray(CandidateInfo[]::new); @@ -57,8 +54,6 @@ public record SwedishGenerator(Rng rng) { static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1; static final int MIN_LEN = Config.MIN_LEN; static final int MIN_LEN7 = Config.MIN_LEN * 7; - static final int CLUE_SIZE = Config.CLUE_SIZE; - static final int SIMPLICITY_DEFAULT_SCORE = 2; static final int MAX_TRIES_PER_SLOT = Config.MAX_TRIES_PER_SLOT; static final char C_DASH = '\0'; static final byte _1 = 49, _9 = 57, A = 65, Z = 90, DASH = (byte) C_DASH; @@ -70,11 +65,9 @@ public record SwedishGenerator(Rng rng) { static final byte B0 = (byte) 0; static final byte B64 = (byte) 64; static final byte B48 = (byte) 48; - // Directions for '1'..'6' static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSET_D_IDX; static final nbrs_16[] OFFSETS_FOUR = Neighbors9x8.OFFSETS_FOUR; static final rci[] IT = Neighbors9x8.IT; - static final long[] INBR8_PACKEDT = Neighbors9x8.NBR8_PACKED; static final int[][] MUTATE_RI = new int[SIZE][625]; static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO; static final long[] NBR8_PACKED_HI = Neighbors9x8.NBR8_PACKED_HI; @@ -233,11 +226,13 @@ public record SwedishGenerator(Rng rng) { static record DictEntry(long[] words, long[][] posBitsets) { } - public static record Lemma(long word) { + static int LEMMA_COUNTER = 0; + + public static interface Lemma { + + static final long LETTER_MASK = (1L << 40) - 1; // low 40 bits + static final long INDEX_MASK = (1L << 24) - 1; // 24 bits - static final long LETTER_MASK = (1L << 40) - 1; // low 40 bits - static final long INDEX_MASK = (1L << 24) - 1; // 24 bits - static int LEMMA_COUNTER = 0; static long pack(String word) { return pack(word.getBytes(US_ASCII)); } static long pack(int index, byte[] b) { return pack(b) | ((long) index << 40); } static long pack(byte[] b) { @@ -245,33 +240,20 @@ public record SwedishGenerator(Rng rng) { for (var i = 0; i < b.length; i++) w |= ((long) b[i] & ~64) << (i * 5); return w; } - public Lemma(int index, String word) { this(pack(index, word.getBytes(US_ASCII))); } - public Lemma(String word) { this(LEMMA_COUNTER++, word); } + static public long from(String word) { return pack(LEMMA_COUNTER++, word.getBytes(US_ASCII)); } static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111 | B64); }// word[]; } static int intAt(long word, int idx) { return (int) (((word >>> (idx * 5))) & 0b11111); }// word[]; } static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); } static int simpel(long w) { return CsvIndexService.simpel(unpackIndex(w)); } - static int length(long word) { - if (word == 0) return 0; - int highestBit = 63 - Long.numberOfLeadingZeros(word & LETTER_MASK); - return (highestBit / 5) + 1; - } - static int usedCharsInPattern(long p) { - if (p == 0) return 0; - int highestBit = 63 - Long.numberOfLeadingZeros(p & LETTER_MASK); // 0-based - return (highestBit / 5) + 1; - } + static int length(long word) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; } + static int usedCharsInPattern(long p) { return ((63 - Long.numberOfLeadingZeros(p & LETTER_MASK)) / 5) + 1; } public static String asWord(long word) { var b = new byte[Lemma.length(word)]; for (var i = 0; i < b.length; i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | B64); return new String(b, US_ASCII); } - static int unpackIndex(long w) { - return (int) (w >>> 40); - } - static int unpackLetters(long w) { - return (int) (w & LETTER_MASK); - } + static int unpackIndex(long w) { return (int) (w >>> 40); } + static int unpackLetters(long w) { return (int) (w & LETTER_MASK); } } public static record Dict( diff --git a/src/test/java/puzzle/ExportFormatTest.java b/src/test/java/puzzle/ExportFormatTest.java index ec32b1c..a11797c 100644 --- a/src/test/java/puzzle/ExportFormatTest.java +++ b/src/test/java/puzzle/ExportFormatTest.java @@ -31,7 +31,7 @@ public class ExportFormatTest { var clueMap = new HashMap(); // key = (cellIndex << 4) | direction var key = 2; - clueMap.put(key, new Lemma("TEST").word()); + clueMap.put(key, Lemma.from("TEST")); // Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4) grid.setLetter(Grid.offset(0, 1), (byte) 'T'); diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index cd0f196..02d499d 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -101,19 +101,19 @@ public class SwedishGeneratorTest { @Test void testLemmaAndDict() { - var l2a = new Lemma("IN").word(); - var l4a = new Lemma("INER").word(); - var l6a = new Lemma("INEREN").word(); - var l7a = new Lemma("INERENA").word(); - var l8a = new Lemma("INERENAE").word(); + var l2a = Lemma.from("IN"); + var l4a = Lemma.from("INER"); + var l6a = Lemma.from("INEREN"); + var l7a = Lemma.from("INERENA"); + var l8a = Lemma.from("INERENAE"); - var l1 = new Lemma("APPLE").word(); + var l1 = Lemma.from("APPLE"); Assertions.assertEquals(Lemma.pack("APPLE".getBytes(StandardCharsets.US_ASCII)), Lemma.unpackLetters(l1)); assertEquals(5, Lemma.length(l1)); assertEquals((byte) 'A', Lemma.byteAt(l1, 0)); assertEquals(1, Lemma.intAt(l1, 0)); - var l2 = new Lemma("AXE").word(); + var l2 = Lemma.from("AXE"); var dict = new Dict(new long[]{ l1, l2, l2a, l4a, l6a, l7a, l8a }); assertEquals(1, dict.index()[3].words().length); @@ -213,15 +213,15 @@ public class SwedishGeneratorTest { @Test void testCandidateInfoForPattern() { - var l0 = new Lemma("IN").word(); - var l3a = new Lemma("INE").word(); - var l4a = new Lemma("INER").word(); - var l6a = new Lemma("INEREN").word(); - var l7a = new Lemma("INERENA").word(); - var l8a = new Lemma("INERENAE").word(); - var l1 = new Lemma("APPLE").word(); - var l2 = new Lemma("APPLY").word(); - var l3 = new Lemma("BANAN").word(); + var l0 = Lemma.from("IN"); + var l3a = Lemma.from("INE"); + var l4a = Lemma.from("INER"); + var l6a = Lemma.from("INEREN"); + var l7a = Lemma.from("INERENA"); + var l8a = Lemma.from("INERENAE"); + var l1 = Lemma.from("APPLE"); + var l2 = Lemma.from("APPLY"); + var l3 = Lemma.from("BANAN"); var dict = new Dict(new long[]{ l0, l1, l2, l3, l3a, l4a, l6a, l7a, l8a }); // Pattern "APP--" for length 5 @@ -309,7 +309,7 @@ public class SwedishGeneratorTest { // r(i) and c(i) are used by placeWord. var packedPos = ((long) Grid.offset(0, 0)) | (((long) Grid.offset(0, 1)) << 7) | (((long) Grid.offset(0, 2)) << 14); var s = Slot.from(0, packedPos, 3); - var w1 = new Lemma("ABC").word(); + var w1 = Lemma.from("ABC"); var undoBuffer = new int[10]; // 1. Successful placement in empty grid @@ -324,7 +324,7 @@ public class SwedishGeneratorTest { assertEquals(0L, undoBuffer[1]); // 0 new characters placed // 3. Conflict: place "ABD" where "ABC" is - var w2 = new Lemma("ABD").word(); + var w2 = Lemma.from("ABD"); assertFalse(placeWord(grid, s, w2, undoBuffer, 2)); // Verify grid is unchanged (still "ABC") assertEquals('A', grid.byteAt(Grid.offset(0, 0))); @@ -347,7 +347,7 @@ public class SwedishGeneratorTest { // Slot at 0,1 length 2 var packedPos = ((long) Grid.offset(0, 1)) | (((long) Grid.offset(0, 2)) << 7); var s = Slot.from((0 << 8) | (1 << 4) | 2, packedPos, 2); - var w = new Lemma("AZ").word(); + var w = Lemma.from("AZ"); var undoBuffer = new int[10]; var placed = placeWord(grid, s, w, undoBuffer, 0);