introduce bitloops

This commit is contained in:
mike
2026-01-14 09:14:03 +01:00
parent bd52bd0ef0
commit afd4a7f53c
4 changed files with 45 additions and 45 deletions

View File

@@ -58,7 +58,6 @@ public record Export() {
record Gridded(@Delegate Grid grid) {
static boolean isLetter(byte b) { return (b & SwedishGenerator.B64) != SwedishGenerator.B0; }
public static IntStream walk(byte base, long lo, long hi) {
if (Slot.increasing(base)) {
return IntStream.concat(
@@ -109,7 +108,7 @@ public record Export() {
}
}
//public boolean isLetterSet(int idx) { return isLetter(g[idx]); }
char NOT_CLUE_NOT_LETTER_TO(byte b, char fallback) { return isLetter(b) ? (char) (64 | b) : fallback; }
char NOT_CLUE_NOT_LETTER_TO(byte b, char fallback) { return b == SwedishGenerator.DASH ? fallback : (char) (64 | b); }
String gridToString(Clues clues) {
var sb = new StringBuilder();
for (var r = 0; r < R; r++) {
@@ -166,10 +165,10 @@ public record Export() {
static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL };
public static final char HORIZONTAL = 'h';
static final char VERTICAL = 'v';
public int arrowCol() { return Grid.c(Slot.clueIndex(slotKey)); }
public int arrowRow() { return Grid.r(Slot.clueIndex(slotKey)); }
public int startRow() { return Grid.r(cells[0]); }
public int startCol() { return Grid.c(cells[0]); }
public int arrowCol() { return SwedishGenerator.IT[Slot.clueIndex(slotKey)].c(); }
public int arrowRow() { return SwedishGenerator.IT[Slot.clueIndex(slotKey)].r(); }
public int startRow() { return SwedishGenerator.IT[cells[0]].r(); }
public int startCol() { return SwedishGenerator.IT[cells[0]].c(); }
public boolean isReversed() { return !Slot.increasing(slotKey); }
public char direction() { return DIRECTION[Slot.dir(slotKey)]; }
}
@@ -214,10 +213,11 @@ public record Export() {
for (var rc : placed) {
for (var c : rc.cells) {
minR = Math.min(minR, Grid.r(c));
minC = Math.min(minC, Grid.c(c));
maxR = Math.max(maxR, Grid.r(c));
maxC = Math.max(maxC, Grid.c(c));
val it = SwedishGenerator.IT[c];
minR = Math.min(minR, it.r());
minC = Math.min(minC, it.c());
maxR = Math.max(maxR, it.r());
maxC = Math.max(maxC, it.c());
}
minR = Math.min(minR, rc.arrowRow());
minC = Math.min(minC, rc.arrowCol());

View File

@@ -99,9 +99,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
for (int dr1 = -2; dr1 <= 2; dr1++)
for (int dr2 = -2; dr2 <= 2; dr2++)
for (int dc1 = -2; dc1 <= 2; dc1++)
for (int dc2 = -2; dc2 <= 2; dc2++)
MUTATE_RI[i][k++] = Grid.offset(clamp(Grid.r(i) + dr1 + dr2, 0, R - 1),
clamp(Grid.c(i) + dc1 + dc2, 0, C - 1));
for (int dc2 = -2; dc2 <= 2; dc2++) {
val ti = IT[i];
MUTATE_RI[i][k++] = Grid.offset(clamp(ti.r() + dr1 + dr2, 0, R - 1),
clamp(ti.c() + dc1 + dc2, 0, C - 1));
}
}
}
@@ -280,14 +282,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
final byte[] g;
public long lo, hi;
public static int r(int offset) { return offset & 7; }
public static int c(int offset) { return offset >>> 3; }
static int offset(int r, int c) { return r | (c << 3); }
/// the pos will never target a clue
public byte letter32At(int pos) { return g[pos]; }
void setLetter(int idx, byte ch) { g[idx] = ch; }
void clearletter(int idx) { g[idx] = DASH; }
void setLetter(int idx, byte ch) { g[idx] = ch; }
private void clearletter(int idx) { g[idx] = DASH; }
void undoPlace(long maskLo, long maskHi) {
for (long b = maskLo; b != 0; b &= b - 1) clearletter(Long.numberOfTrailingZeros(b));
for (long b = maskHi; b != 0; b &= b - 1) clearletter(64 | Long.numberOfTrailingZeros(b));
@@ -305,12 +305,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
static long pack(int index, byte[] b) { return pack(b) | ((long) index << 40); }
static long pack(byte[] b) {
long w = 0;
for (var i = 0; i < b.length; i++) w |= ((long) b[i] & 63) << (i * 5);
for (var i = 0; i < b.length; i++) w |= ((long) b[i] & 31) << (i * 5);
return w;
}
static public long from(int index, String word) { return pack(index, 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 byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111); }
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) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
@@ -338,7 +337,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
entry.words().add(lemma);
for (var i = 0; i < L; i++) {
var letter = Lemma.intAt(lemma, i) - 1;
var letter = Lemma.byteAt(lemma, i) - 1;
if (letter < 0 || letter >= 26) throw new RuntimeException("Illegal letter: " + letter + " in word " + lemma);
entry.pos()[i][letter].add(idx);
}
@@ -724,12 +723,14 @@ 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) return 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) {
int idx = Long.numberOfTrailingZeros(b);
int val = grid.g[idx] & 31;
int val = grid.g[idx];
if (val != 0) {
int i = Long.bitCount(s.lo & ((1L << idx) - 1));
p |= ((long) (i * 26 + val)) << (i << 3);
@@ -738,7 +739,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
int offset = Long.bitCount(s.lo);
for (long b = s.hi & ~grid.hi; b != 0; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int val = grid.g[64 | idx] & 31;
int val = grid.g[64 | idx];
if (val != 0) {
int i = offset + Long.bitCount(s.hi & ((1L << idx) - 1));
p |= ((long) (i * 26 + val)) << (i << 3);
@@ -748,7 +749,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
int offset = Long.bitCount(s.hi);
for (long b = s.hi & ~grid.hi; b != 0; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int val = grid.g[64 | idx] & 31;
int val = grid.g[64 | idx];
if (val != 0) {
int i = Long.bitCount(s.hi & ~((1L << idx) | ((1L << idx) - 1)));
p |= ((long) (i * 26 + val)) << (i << 3);
@@ -756,7 +757,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
}
for (long b = s.lo & ~grid.lo; b != 0; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int val = grid.g[idx] & 31;
int val = grid.g[idx];
if (val != 0) {
int i = offset + Long.bitCount(s.lo & ~((1L << idx) | ((1L << idx) - 1)));
p |= ((long) (i * 26 + val)) << (i << 3);

View File

@@ -59,10 +59,10 @@ public class MainTest {
var s = slots[0];
assertEquals(8, s.length());
var cells = s.walk().toArray();
assertEquals(0, Grid.r(cells[0]));
assertEquals(1, Grid.c(cells[0]));
assertEquals(0, Grid.r(cells[1]));
assertEquals(2, Grid.c(cells[1]));
assertEquals(0, SwedishGenerator.IT[cells[0]].r());
assertEquals(1, SwedishGenerator.IT[cells[0]].c());
assertEquals(0, SwedishGenerator.IT[cells[1]].r());
assertEquals(2, SwedishGenerator.IT[cells[1]].c());
}
@Test
@@ -82,8 +82,8 @@ public class MainTest {
clues.forEachSlot((key, lo, hi) -> {
count.incrementAndGet();
assertEquals(8, Long.bitCount(lo) + Long.bitCount(hi));
assertEquals(0, Grid.r(Long.numberOfTrailingZeros(lo)));
assertEquals(1, Grid.c(Long.numberOfTrailingZeros(lo)));
assertEquals(0, SwedishGenerator.IT[Long.numberOfTrailingZeros(lo)].r());
assertEquals(1, SwedishGenerator.IT[Long.numberOfTrailingZeros(lo)].c());
});
assertEquals(1, count.get());
}

View File

@@ -53,11 +53,11 @@ public class SwedishGeneratorTest {
static final long ABC = Lemma.from(26, "ABC");
static final long ABD = Lemma.from(27, "ABD");
static final long AZ = Lemma.from(28, "AZ");
static final byte LETTER_A = (byte) 'A';
static final byte LETTER_B = (byte) 'B';
static final byte LETTER_C = (byte) 'C';
static final byte LETTER_X = (byte) 'X';
static final byte LETTER_Z = (byte) 'Z';
static final byte LETTER_A = ((byte) 'A') & 31;
static final byte LETTER_B = ((byte) 'B') & 31;
static final byte LETTER_C = ((byte) 'C') & 31;
static final byte LETTER_X = ((byte) 'X') & 31;
static final byte LETTER_Z = ((byte) 'Z') & 31;
static final byte CLUE_DOWN = 0;
static final byte CLUE_RIGHT = 1;
static final byte CLUE_UP = 2;
@@ -151,8 +151,7 @@ public class SwedishGeneratorTest {
void testLemmaAndDict() {
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));
assertEquals(LETTER_A, Lemma.byteAt(l1, 0));
var dict = new Dict(new long[]{ l1, l2, l2a, l4a, l6a, l7a, l8a });
@@ -192,12 +191,12 @@ public class SwedishGeneratorTest {
assertEquals(CLUE_DOWN, Slot.dir(s.key()));
assertFalse(s.horiz());
var cells = s.walk().toArray();
assertEquals(2, Grid.r(cells[0]));
assertEquals(3, Grid.r(cells[1]));
assertEquals(4, Grid.r(cells[2]));
assertEquals(5, Grid.c(cells[0]));
assertEquals(5, Grid.c(cells[1]));
assertEquals(5, Grid.c(cells[2]));
assertEquals(2, SwedishGenerator.IT[cells[0]].r());
assertEquals(3, SwedishGenerator.IT[cells[1]].r());
assertEquals(4, SwedishGenerator.IT[cells[2]].r());
assertEquals(5, SwedishGenerator.IT[cells[0]].c());
assertEquals(5, SwedishGenerator.IT[cells[1]].c());
assertEquals(5, SwedishGenerator.IT[cells[2]].c());
assertTrue(Slot.horiz(CLUE_RIGHT)); // right
assertFalse(Slot.horiz(CLUE_DOWN)); // down