introduce bitloops

This commit is contained in:
mike
2026-01-12 11:46:38 +01:00
parent 6ef007522c
commit b6351a6fb2

View File

@@ -62,14 +62,16 @@ public record SwedishGenerator(Rng rng) {
static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); } static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
record Pick(Slot slot, CandidateInfo info, boolean done) { } record Pick(Slot slot, CandidateInfo info, boolean done) { }
static final byte B0 = (byte) 0; static final byte B0 = (byte) 0;
static final byte B64 = (byte) 64; static final byte B64 = (byte) 64;
static final byte B48 = (byte) 48; static final byte B48 = (byte) 48;
static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSET_D_IDX; static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSET_D_IDX;
static final rci[] IT = Neighbors9x8.IT; static final rci[] IT = Neighbors9x8.IT;
static final int[][] MUTATE_RI = new int[SIZE][625]; static final int[][] MUTATE_RI = new int[SIZE][625];
static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO; static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO;
static final long[] NBR8_PACKED_HI = Neighbors9x8.NBR8_PACKED_HI; static final long[] NBR8_PACKED_HI = Neighbors9x8.NBR8_PACKED_HI;
static final long[] PATH_LO = Neighbors9x8.PATH_LO;
static final long[] PATH_HI = Neighbors9x8.PATH_HI;
static { static {
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
@@ -305,10 +307,10 @@ public record SwedishGenerator(Rng rng) {
} }
} }
static record Slot(int key, long packedPos) { static record Slot(int key, long packedPos, long packedPoslo, long packedPoshi) {
static final int BIT_FOR_DIR = 3; static final int BIT_FOR_DIR = 3;
static Slot from(int key, long packedPos, int len) { return new Slot(key, packedPos | ((long) len << 56)); } static Slot from(int key, long packedPos, int len) { return new Slot(key, packedPos | ((long) len << 56), 0L, 0L); }
void undoPlace(Grid grid, int mask) { for (int i = 0, len = len(); i < len; i++) if ((mask & (1L << i)) != 0) grid.clearletter(pos(i)); } void undoPlace(Grid grid, int mask) { for (int i = 0, len = len(); i < len; i++) if ((mask & (1L << i)) != 0) grid.clearletter(pos(i)); }
public int len() { return (int) (packedPos >>> 56); } public int len() { return (int) (packedPos >>> 56); }
public int clueR() { return Grid.r((key >>> BIT_FOR_DIR)); } public int clueR() { return Grid.r((key >>> BIT_FOR_DIR)); }
@@ -322,6 +324,56 @@ public record SwedishGenerator(Rng rng) {
public static int packSlotDir(int idx, int d) { return (idx << BIT_FOR_DIR) | d; } public static int packSlotDir(int idx, int d) { return (idx << BIT_FOR_DIR) | d; }
} }
interface SlotVisitor2 {
void visitMasks(int slotDir, long loMask, long hiMask);
}
private static void processSlot(Grid grid, SlotVisitor2 visitor, int idx) {
int d = grid.digitAt(idx); // 1..4
int di = d - 1; // 0..3
int key = (idx << 2) | di;
long rayLo = PATH_LO[key];
long rayHi = PATH_HI[key];
// only consider clue cells
long hitsLo = rayLo & grid.lo;
long hitsHi = rayHi & grid.hi;
// slice ray to stop before first clue, depending on direction monotonicity
// right/down => increasing indices; up/left => decreasing indices
boolean increasing = (d == 2 || d == 3);
if (increasing) {
// first clue is lowest index among hits (lo first, then hi)
if (hitsLo != 0) {
long stop = 1L << Long.numberOfTrailingZeros(hitsLo);
rayLo &= (stop - 1);
rayHi = 0; // any hi is beyond the stop
} else if (hitsHi != 0) {
long stop = 1L << Long.numberOfTrailingZeros(hitsHi);
// keep all lo (lo indices are < any hi index), but cut hi below stop
rayHi &= (stop - 1);
}
} else {
// first clue is highest index among hits (hi first, then lo)
if (hitsHi != 0) {
int msb = 63 - Long.numberOfLeadingZeros(hitsHi);
long stop = 1L << msb;
rayHi &= ~((stop << 1) - 1); // keep bits > stop
rayLo = 0; // lo indices are below stop
} else if (hitsLo != 0) {
int msb = 63 - Long.numberOfLeadingZeros(hitsLo);
long stop = 1L << msb;
rayLo &= ~((stop << 1) - 1);
}
}
if ((rayLo | rayHi) != 0) {
visitor.visitMasks(Slot.packSlotDir(idx, d), rayLo, rayHi);
}
}
private static void processSlot(Grid grid, SlotVisitor visitor, int idx) { private static void processSlot(Grid grid, SlotVisitor visitor, int idx) {
var d = grid.digitAt(idx); var d = grid.digitAt(idx);
var packed = OFFSETS_D_IDX[(d - 1) | (idx << 2)]; var packed = OFFSETS_D_IDX[(d - 1) | (idx << 2)];
@@ -462,7 +514,7 @@ public record SwedishGenerator(Rng rng) {
for (int placed = 0, guard = 0, idx; placed < TARGET_CLUES && guard < 4000; guard++) { for (int placed = 0, guard = 0, idx; placed < TARGET_CLUES && guard < 4000; guard++) {
idx = rng.randint(0, SIZE_MIN_1); idx = rng.randint(0, SIZE_MIN_1);
if (g.isClue(idx)) continue; if (g.isClue(idx)) continue;
int d_idx = rng.randint2bit(); int d_idx = rng.randint2bit();
val packed = OFFSETS_D_IDX[d_idx | idx << 2]; val packed = OFFSETS_D_IDX[d_idx | idx << 2];
if (g.hasRoomForClue(packed)) { if (g.hasRoomForClue(packed)) {
g.setClue(idx, (byte) (1 + (d_idx | 48))); g.setClue(idx, (byte) (1 + (d_idx | 48)));
@@ -472,13 +524,13 @@ public record SwedishGenerator(Rng rng) {
return g; return g;
} }
Grid mutate(Grid grid) { Grid mutate(Grid grid) {
var g = grid.deepCopyGrid(); var g = grid.deepCopyGrid();
int ri; int ri;
var bytes = MUTATE_RI[rng.randint(0, SIZE_MIN_1)]; var bytes = MUTATE_RI[rng.randint(0, SIZE_MIN_1)];
for (var k = 0; k < 4; k++) { for (var k = 0; k < 4; k++) {
ri = bytes[rng.randint(0, 624)]; ri = bytes[rng.randint(0, 624)];
if (!g.clueless(ri)) { if (!g.clueless(ri)) {
int d_idx = rng.randint2bit(); int d_idx = rng.randint2bit();
val packed = OFFSETS_D_IDX[d_idx | ri << 2]; val packed = OFFSETS_D_IDX[d_idx | ri << 2];
if (g.hasRoomForClue(packed)) g.setClue(ri, (byte) (1 + (d_idx | 48))); if (g.hasRoomForClue(packed)) g.setClue(ri, (byte) (1 + (d_idx | 48)));
} }
@@ -587,8 +639,6 @@ public record SwedishGenerator(Rng rng) {
var x = pop.get(i); var x = pop.get(i);
if (x.fit() < best.fit()) best = x; if (x.fit() < best.fit()) best = x;
} }
//pop.sort(Comparator.comparingLong(GridAndFit::fit));
//return pop.get(0).grid;
return best.grid; return best.grid;
} }