introduce bitloops

This commit is contained in:
mike
2026-01-12 09:42:13 +01:00
parent 84e832df40
commit 67eedb773b
3 changed files with 32 additions and 50 deletions

View File

@@ -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(

View File

@@ -31,7 +31,7 @@ public class ExportFormatTest {
var clueMap = new HashMap<Integer, Long>();
// 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');

View File

@@ -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);