introduce bitloops

This commit is contained in:
mike
2026-01-18 04:11:43 +01:00
parent b026ebfbd2
commit 948730d7be
5 changed files with 186 additions and 99 deletions

View File

@@ -51,7 +51,7 @@ public record Export() {
public record Clued(@Delegate Clues c) {
public Clued deepCopyGrid() { return new Clued(new Clues(c.lo, c.hi, c.vlo, c.vhi, c.rlo, c.rhi)); }
public Clued deepCopyGrid() { return new Clued(new Clues(c.lo, c.hi, c.vlo, c.vhi, c.rlo, c.rhi, c.xlo, c.xhi)); }
String gridToString() {
var sb = new StringBuilder(INIT);
forEachSlot((s, _, _) -> {
@@ -199,7 +199,7 @@ public record Export() {
record Placed(long lemma, int slotKey, int[] cells) {
static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL };
static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL };
public static final char HORIZONTAL = 'h';
static final char VERTICAL = 'v';
public int arrowCol() { return SwedishGenerator.IT[Slot.clueIndex(slotKey)].c(); }

View File

@@ -130,9 +130,8 @@ public final class Masker {
for (long bits = lo_cl; bits != X; bits &= bits - 1) {
long lsb = bits & -bits;
int clueIdx = numberOfTrailingZeros(lsb);
int v = (grid.vlo & lsb) != 0 ? 1 : 0;
int r = (grid.rlo & lsb) != 0 ? 1 : 0;
int key = Slot.packSlotKey(clueIdx, (r << 1) | v);
int dir = grid.getDir(clueIdx);
int key = Slot.packSlotKey(clueIdx, dir);
long rLo = PATH_LO[key], rHi = PATH_HI[key];
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
if (Slotinfo.increasing(key)) {
@@ -173,9 +172,8 @@ public final class Masker {
for (long bits = hi_cl; bits != X; bits &= bits - 1) {
long lsb = bits & -bits;
int clueIdx = numberOfTrailingZeros(lsb);
int v = (grid.vhi & lsb) != 0 ? 1 : 0;
int r = (grid.rhi & lsb) != 0 ? 1 : 0;
int key = Slot.packSlotKey(64 | clueIdx, (r << 1) | v);
int dir = grid.getDir(64 | clueIdx);
int key = Slot.packSlotKey(64 | clueIdx, dir);
long rLo = PATH_LO[key], rHi = PATH_HI[key];
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
if (Slotinfo.increasing(key)) {
@@ -226,15 +224,6 @@ public final class Masker {
// 1. Intersectie
if (((activeSLo[i] & activeSLo[j]) | (activeSHi[i] & activeSHi[j])) != 0) {
connected = true;
} else {
// 2. 8-naburigheid van clue cells
int ci = activeCIdx[i];
int cj = activeCIdx[j];
if (cj < 64) {
if ((NBR8_PACKED_LO[ci] & (1L << cj)) != 0) connected = true;
} else {
if ((NBR8_PACKED_HI[ci] & (1L << (cj & 63))) != 0) connected = true;
}
}
if (connected) {
@@ -282,7 +271,7 @@ public final class Masker {
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
boolean h = (cHLo & (1L << clueIdx)) != X;
boolean v = (cVLo & (1L << clueIdx)) != X;
if (!h && !v) penalty += 15000;
if (!h && !v) penalty += 5000;
else if (h && v) { /* ok */ } else if (((h ? cHLo2 : cVLo2) & (1L << clueIdx)) != X) penalty += 600;
else penalty += 200;
}
@@ -293,7 +282,7 @@ public final class Masker {
boolean h = (cHHi & (1L << clueIdx)) != X;
boolean v = (cVHi & (1L << clueIdx)) != X;
if (!h && !v)
penalty += 15000;
penalty += 5000;
else if (h && v) { /* ok */ } else if (((h ? cHHi2 : cVHi2) & (1L << clueIdx)) != X) penalty += 600;
else penalty += 200;
}
@@ -407,7 +396,9 @@ public final class Masker {
(a.vlo & ~maskLo) | (other.vlo & maskLo),
(a.vhi & ~maskHi) | (other.vhi & maskHi),
(a.rlo & ~maskLo) | (other.rlo & maskLo),
(a.rhi & ~maskHi) | (other.rhi & maskHi));
(a.rhi & ~maskHi) | (other.rhi & maskHi),
(a.xlo & ~maskLo) | (other.xlo & maskLo),
(a.xhi & ~maskHi) | (other.xhi & maskHi));
int guard = 0;
while (!c.isValid(MIN_LEN) && guard++ < 3) {
for (var l = c.lo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 0);
@@ -513,9 +504,9 @@ public final class Masker {
@AllArgsConstructor
public static class Clues {
long lo, hi, vlo, vhi, rlo, rhi;
long lo, hi, vlo, vhi, rlo, rhi, xlo, xhi;
public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0); }
public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0, 0, 0); }
public static Clued parse(String s) {
var c = createEmpty();
var lines = s.split("\n");
@@ -523,7 +514,7 @@ public final class Masker {
var line = lines[r];
for (int col = 0; col < Math.min(line.length(), C); col++) {
char ch = line.charAt(col);
if (ch >= '0' && ch <= '3') {
if (ch >= '0' && ch <= '4') {
int idx = Grid.offset(r, col);
byte dir = (byte) (ch - '0');
if ((idx & 64) == 0) c.setClueLo(1L << idx, dir);
@@ -557,6 +548,8 @@ public final class Masker {
else vlo &= ~mask;
if ((idx & 2) != 0) rlo |= mask;
else rlo &= ~mask;
if ((idx & 4) != 0) xlo |= mask;
else xlo &= ~mask;
}
public void setClueHi(long mask, byte idx) {
hi |= mask;
@@ -564,16 +557,20 @@ public final class Masker {
else vhi &= ~mask;
if ((idx & 2) != 0) rhi |= mask;
else rhi &= ~mask;
if ((idx & 4) != 0) xhi |= mask;
else xhi &= ~mask;
}
public void clearClueLo(long mask) {
lo &= mask;
vlo &= mask;
rlo &= mask;
xlo &= mask;
}
public void clearClueHi(long mask) {
hi &= mask;
vhi &= mask;
rhi &= mask;
xhi &= mask;
}
public boolean isClueLo(int index) { return ((lo >>> index) & 1L) != X; }
public boolean isClueHi(int index) { return ((hi >>> (index & 63)) & 1L) != X; }
@@ -582,8 +579,8 @@ public final class Masker {
public int clueCount() { return bitCount(lo) + bitCount(hi); }
public double similarity(Clues b) {
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 matchLo = (~(lo ^ b.lo)) & (~lo | (~(vlo ^ b.vlo) & ~(rlo ^ b.rlo) & ~(xlo ^ b.xlo)));
long matchHi = (~(hi ^ b.hi)) & (~hi | (~(vhi ^ b.vhi) & ~(rhi ^ b.rhi) & ~(xhi ^ b.xhi)));
return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED;
}
@@ -601,14 +598,17 @@ public final class Masker {
return v.ok;
}
public void forEachSlot(SlotVisitor visitor) {
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1));
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0));
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 2));
for (var l = lo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 3));
for (var h = hi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 1));
for (var h = hi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 0));
for (var h = hi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 2));
for (var h = hi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 3));
for (var l = lo & ~xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1));
for (var l = lo & ~xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0));
for (var l = lo & ~xlo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 2));
for (var l = lo & ~xlo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 3));
for (var l = lo & xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 4));
for (var h = hi & ~xhi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 1));
for (var h = hi & ~xhi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 0));
for (var h = hi & ~xhi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 2));
for (var h = hi & ~xhi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 3));
for (var h = hi & xhi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 4));
}
public Clues from(Clues best) {
lo = best.lo;
@@ -617,30 +617,34 @@ public final class Masker {
vhi = best.vhi;
rlo = best.rlo;
rhi = best.rhi;
xlo = best.xlo;
xhi = best.xhi;
return this;
}
public byte getDir(int index) {
if ((index & 64) == 0) {
int v = (vlo & (1L << index)) != 0 ? 1 : 0;
int r = (rlo & (1L << index)) != 0 ? 1 : 0;
return (byte) ((r << 1) | v);
int x = (xlo & (1L << index)) != 0 ? 1 : 0;
return (byte) ((x << 2) | (r << 1) | v);
} else {
int v = (vhi & (1L << (index & 63))) != 0 ? 1 : 0;
int r = (rhi & (1L << (index & 63))) != 0 ? 1 : 0;
return (byte) ((r << 1) | v);
int x = (xhi & (1L << (index & 63))) != 0 ? 1 : 0;
return (byte) ((x << 2) | (r << 1) | v);
}
}
}
public record Slot(int key, long lo, long hi, DictEntry entry) {
static final int BIT_FOR_DIR = 2;
static Slot from(int key, long lo, long hi, DictEntry entry) { return new Slot(key, lo, hi, entry); }
static final int BIT_FOR_DIR = 3;
public static Slot from(int key, long lo, long hi, DictEntry entry) { return new Slot(key, lo, hi, entry); }
public static int length(long lo, long hi) { return bitCount(lo) + bitCount(hi); }
public static int clueIndex(int key) { return key >>> BIT_FOR_DIR; }
public static int dir(int key) { return key & 3; }
public static int dir(int key) { return key & 7; }
public IntStream walk() { return Gridded.walk((byte) key, lo, hi); }
public static boolean horiz(int d) { return (d & 1) != 0; }
public static boolean horiz(int d) { return (d & 1) != 0 && (d & 4) == 0; }
public static int packSlotKey(int idx, int d) { return (idx << BIT_FOR_DIR) | d; }
}
}

View File

@@ -76,12 +76,45 @@ public record SwedishGenerator() {
public int count;
}
public static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSET_D_IDX_0_BASE;
public static final long[] OFFSETS_D_IDX;
public static final rci[] IT = Neighbors9x8.IT;
public static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO;
public static final long[] NBR8_PACKED_HI = Neighbors9x8.NBR8_PACKED_HI;
public static final long[] PATH_LO = Neighbors9x8.PATH_LO;
public static final long[] PATH_HI = Neighbors9x8.PATH_HI;
public static final long[] PATH_LO;
public static final long[] PATH_HI;
static {
final int NEW_SIZE = SIZE << Masker.Slot.BIT_FOR_DIR;
PATH_LO = new long[NEW_SIZE];
PATH_HI = new long[NEW_SIZE];
OFFSETS_D_IDX = new long[NEW_SIZE];
for (int i = 0; i < SIZE; i++) {
for (int d = 0; d < 4; d++) {
int oldKey = (i << 2) | d;
int newKey = (i << Masker.Slot.BIT_FOR_DIR) | d;
PATH_LO[newKey] = Neighbors9x8.PATH_LO[oldKey];
PATH_HI[newKey] = Neighbors9x8.PATH_HI[oldKey];
OFFSETS_D_IDX[newKey] = Neighbors9x8.OFFSET_D_IDX_0_BASE[oldKey];
}
// Richting 4: Corner Down (Clue op r,c -> Woord op r,c+1 naar beneden)
int r = IT[i].r();
int c = IT[i].c();
int newKey4 = (i << Masker.Slot.BIT_FOR_DIR) | 4;
if (c + 1 < C) {
long mLo = 0, mHi = 0;
for (int ri = r; ri < R; ri++) {
int target = Grid.offset(ri, c + 1);
if (isLo(target)) mLo |= (1L << target);
else mHi |= (1L << (target & 63));
}
PATH_LO[newKey4] = mLo;
PATH_HI[newKey4] = mHi;
int first = Grid.offset(r, c + 1);
int last = Grid.offset(R - 1, c + 1);
OFFSETS_D_IDX[newKey4] = (long)first | ((long)last << 7);
}
}
}
public static final Pick PICK_DONE = null;//new Pick(null, null, 0, true);
public static final Pick PICK_NOT_DONE = new Pick(null, null, 0);
@@ -112,13 +145,10 @@ public record SwedishGenerator() {
return y;
}
public byte randint2bitByte() {
var b = (byte) (nextU32() & 3);
if (b == 3) {
return 1;
}if (b == 4) {
return 2;
}
return b;
int r = nextU32() & 7;
if (r < 4) return (byte) r;
if (r == 4) return (byte) 4;
return (byte) (r % 4);
}
public <T> T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length /*- 0L*/ /*+ 1L*/)))]; }
public <T> T rand(List<T> p) { return p.get((int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.size() /*- 0L*/ /*+ 1L*/)))); }