introduce bitloops
This commit is contained in:
@@ -194,7 +194,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
public Clues deepCopyGrid() { return new Clues(lo, hi, vlo, vhi, rlo, rhi); }
|
||||
boolean clueless(int idx) {
|
||||
if (!isClue(idx)) return false;
|
||||
clearClue(idx);
|
||||
if ((idx & 64) == 0) {
|
||||
clearClueLo(idx);
|
||||
}else{
|
||||
clearClueHi(idx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean hasRoomForClue(long packed) { return (packed) != X && notClue(packed & 0x7FL) && notClue((packed >>> 7) & 0x7FL); }
|
||||
@@ -216,6 +220,10 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
else rhi &= ~mask;
|
||||
}
|
||||
}
|
||||
public byte digitAtRevLo(int idx) { return (byte) (2 | ((vlo >>> idx) & 1L)); }
|
||||
public byte digitAtRevHi(int idx) { return (byte) (2 | ((vhi >>> (idx & 63)) & 1L)); }
|
||||
public byte digitAtDevLo(int idx) { return (byte) ((vlo >>> idx) & 1L); }
|
||||
public byte digitAtDevHi(int idx) { return (byte) ((vhi >>> (idx & 63)) & 1L); }
|
||||
public byte digitAt(int idx) {
|
||||
if ((idx & 64) == 0) {
|
||||
int v = (int) ((vlo >>> idx) & 1L);
|
||||
@@ -227,18 +235,17 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
return (byte) ((r << 1) | v);
|
||||
}
|
||||
}
|
||||
public void clearClue(int idx) {
|
||||
if ((idx & 64) == 0) {
|
||||
long mask = ~(1L << idx);
|
||||
lo &= mask;
|
||||
vlo &= mask;
|
||||
rlo &= mask;
|
||||
} else {
|
||||
long mask = ~(1L << (idx & 63));
|
||||
hi &= mask;
|
||||
vhi &= mask;
|
||||
rhi &= mask;
|
||||
}
|
||||
public void clearClueLo(int idx) {
|
||||
long mask = ~(1L << idx);
|
||||
lo &= mask;
|
||||
vlo &= mask;
|
||||
rlo &= mask;
|
||||
}
|
||||
public void clearClueHi(int idx) {
|
||||
long mask = ~(1L << (idx & 63));
|
||||
hi &= mask;
|
||||
vhi &= mask;
|
||||
rhi &= mask;
|
||||
}
|
||||
public boolean isClue(long index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) != X : ((hi >>> (index & 63)) & 1L) != X; }
|
||||
public boolean isClue(int index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) != X : ((hi >>> (index & 63)) & 1L) != X; }
|
||||
@@ -254,8 +261,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
|
||||
public void forEachSlot(SlotVisitor visitor) {
|
||||
for (var l = lo; l != X; l &= l - 1) processSlot(this, visitor, Long.numberOfTrailingZeros(l));
|
||||
for (var h = hi; h != X; h &= h - 1) processSlot(this, visitor, 64 | Long.numberOfTrailingZeros(h));
|
||||
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 1));
|
||||
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 0));
|
||||
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 2));
|
||||
for (var l = lo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 3));
|
||||
for (var h = hi & ~rhi & vlo; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | Long.numberOfTrailingZeros(h), 1));
|
||||
for (var h = hi & ~rhi & ~vlo; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | Long.numberOfTrailingZeros(h), 0));
|
||||
for (var h = hi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | Long.numberOfTrailingZeros(h)), 2));
|
||||
for (var h = hi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | Long.numberOfTrailingZeros(h)), 3));
|
||||
}
|
||||
public Clues from(Clues best) {
|
||||
lo = best.lo;
|
||||
@@ -275,17 +288,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
public long lo, hi;
|
||||
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]; }
|
||||
public boolean lisLetterAtLo(int pos) { return (lo & (1L << pos)) != X; }
|
||||
public boolean lisLetterAtHi(int pos) { return (hi & (1L << (pos & 63))) != X; }
|
||||
void setLetterLo(int idx, byte ch) {
|
||||
lo |= (1L << idx);
|
||||
|
||||
g[idx] = ch;
|
||||
}
|
||||
void setLetterHi(int idx, byte ch) {
|
||||
hi |= (1L << (idx & 63));
|
||||
|
||||
g[idx] = ch;
|
||||
}
|
||||
}
|
||||
@@ -382,43 +387,43 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
public static boolean horiz(int d) { return (d & 1) != 0; }
|
||||
public static int packSlotKey(int idx, int d) { return (idx << BIT_FOR_DIR) | d; }
|
||||
}
|
||||
|
||||
private static void processSlot(Clues grid, SlotVisitor visitor, int idx) {
|
||||
int key = Slot.packSlotKey(idx, grid.digitAt(idx)); // 0..3
|
||||
|
||||
// slice ray to stop before first clue, depending on direction monotonicity
|
||||
// right/down => increasing indices; up/left => decreasing indices
|
||||
// first clue is highest index among hits (hi first, then lo)
|
||||
private static void processSlotRev(Clues c, SlotVisitor visitor, int key) {
|
||||
long rayLo = PATH_LO[key];
|
||||
long rayHi = PATH_HI[key];
|
||||
|
||||
// only consider clue cells
|
||||
long hitsLo = rayLo & grid.lo;
|
||||
long hitsHi = rayHi & grid.hi;
|
||||
long hitsLo = rayLo & c.lo;
|
||||
long hitsHi = rayHi & c.hi;
|
||||
|
||||
// slice ray to stop before first clue, depending on direction monotonicity
|
||||
// right/down => increasing indices; up/left => decreasing indices
|
||||
if (hitsHi != X) {
|
||||
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 != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hitsLo);
|
||||
long stop = 1L << msb;
|
||||
rayLo &= ~((stop << 1) - 1);
|
||||
}
|
||||
|
||||
if (Slot.increasing(key)) {
|
||||
// first clue is lowest index among hits (lo first, then hi)
|
||||
if (hitsLo != X) {
|
||||
long stop = 1L << Long.numberOfTrailingZeros(hitsLo);
|
||||
rayLo &= (stop - 1);
|
||||
rayHi = 0; // any hi is beyond the stop
|
||||
} else if (hitsHi != X) {
|
||||
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 != X) {
|
||||
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 != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hitsLo);
|
||||
long stop = 1L << msb;
|
||||
rayLo &= ~((stop << 1) - 1);
|
||||
}
|
||||
visitor.visit(key, rayLo, rayHi);
|
||||
}
|
||||
private static void processSlot(Clues c, SwedishGenerator.SlotVisitor visitor, int key) {
|
||||
long rayLo = PATH_LO[key];
|
||||
long rayHi = PATH_HI[key];
|
||||
long hitsLo = rayLo & c.lo;
|
||||
long hitsHi = rayHi & c.hi;
|
||||
|
||||
if (hitsLo != X) {
|
||||
long stop = 1L << Long.numberOfTrailingZeros(hitsLo);
|
||||
rayLo &= (stop - 1);
|
||||
rayHi = 0; // any hi is beyond the stop
|
||||
} else if (hitsHi != X) {
|
||||
long stop = 1L << Long.numberOfTrailingZeros(hitsHi);
|
||||
// keep all lo (lo indices are < any hi index), but cut hi below stop
|
||||
rayHi &= (stop - 1);
|
||||
}
|
||||
|
||||
visitor.visit(key, rayLo, rayHi);
|
||||
@@ -646,11 +651,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
out.rlo = (out.rlo & ~maskLo) | (other.rlo & maskLo);
|
||||
out.rhi = (out.rhi & ~maskHi) | (other.rhi & maskHi);
|
||||
|
||||
for (var lo = out.lo; lo != X; lo &= lo - 1L) clearClues(out, Long.numberOfTrailingZeros(lo));
|
||||
for (var hi = out.hi; hi != X; hi &= hi - 1L) clearClues(out, 64 | Long.numberOfTrailingZeros(hi));
|
||||
for (var lo = out.lo; lo != X; lo &= lo - 1L) clearCluesLo(out, Long.numberOfTrailingZeros(lo));
|
||||
for (var hi = out.hi; hi != X; hi &= hi - 1L) clearCluesHi(out, 64 | Long.numberOfTrailingZeros(hi));
|
||||
return out;
|
||||
}
|
||||
public static void clearClues(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, out.digitAt(idx))])) out.clearClue(idx); }
|
||||
public static void clearCluesLo(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, out.digitAt(idx))])) out.clearClueLo(idx); }
|
||||
public static void clearCluesHi(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, out.digitAt(idx))])) out.clearClueHi(idx); }
|
||||
|
||||
Clues hillclimb(Clues start, int clue_size, int limit) {
|
||||
var best = start;
|
||||
|
||||
Reference in New Issue
Block a user