introduce bitloops
This commit is contained in:
@@ -67,6 +67,10 @@ public record Export() {
|
||||
if ((bitIndex & 64) == 0) this.l1 |= 1L << bitIndex;
|
||||
else this.l2 |= 1L << (bitIndex & 63);
|
||||
}
|
||||
public void or(long lo, long hi) {
|
||||
this.l1 |= lo;
|
||||
this.l2 |= hi;
|
||||
}
|
||||
public void clear() {
|
||||
l1 = 0L;
|
||||
l2 = 0L;
|
||||
@@ -142,10 +146,10 @@ public record Export() {
|
||||
var g = filled().grid();
|
||||
var placed = new ArrayList<Placed>();
|
||||
var clueMap = filled().clueMap();
|
||||
g.grid().forEachSlot((int key, long packedPos, int len) -> {
|
||||
g.grid().forEachSlot((int key, long lo, long hi) -> {
|
||||
var word = clueMap.get(key);
|
||||
if (word != null) {
|
||||
var p = extractPlacedFromSlot(Slot.from(key, packedPos, len), word);
|
||||
var p = extractPlacedFromSlot(Slot.from(key, lo, hi), word);
|
||||
if (p != null) placed.add(p);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
// static final CandidateInfo[] CANDIDATES = IntStream.range(0, 10192 << 2).mapToObj(CandidateInfo::new).toArray(CandidateInfo[]::new);
|
||||
|
||||
//@formatter:off
|
||||
@FunctionalInterface interface SlotVisitor { void visit(int key, long packedPos, int len); }
|
||||
@FunctionalInterface interface SlotVisitor { void visit(int key, long lo, long hi); }
|
||||
//@formatter:on
|
||||
static final long GT_1_OFFSET_53_BIT = 0x3E00000000000000L;
|
||||
static final long X = 0L;
|
||||
@@ -307,28 +307,68 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
}
|
||||
|
||||
static record Slot(int key, long packedPos, long packedPoslo, long packedPoshi) {
|
||||
static record Slot(int key, long lo, long hi) {
|
||||
|
||||
static final int BIT_FOR_DIR = 3;
|
||||
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)); }
|
||||
public int len() { return (int) (packedPos >>> 56); }
|
||||
static Slot from(int key, long lo, long hi) { return new Slot(key, lo, hi); }
|
||||
void undoPlace(Grid grid, int mask) {
|
||||
boolean increasing = (dir() == 2 || dir() == 3);
|
||||
int i = 0;
|
||||
if (increasing) {
|
||||
for (long b = lo; b != 0; b &= b - 1, i++) if ((mask & (1 << i)) != 0) grid.clearletter(Long.numberOfTrailingZeros(b));
|
||||
for (long b = hi; b != 0; b &= b - 1, i++) if ((mask & (1 << i)) != 0) grid.clearletter(64 | Long.numberOfTrailingZeros(b));
|
||||
} else {
|
||||
for (long b = hi; b != 0; i++) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(b);
|
||||
if ((mask & (1 << i)) != 0) grid.clearletter(64 | msb);
|
||||
b &= ~(1L << msb);
|
||||
}
|
||||
for (long b = lo; b != 0; i++) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(b);
|
||||
if ((mask & (1 << i)) != 0) grid.clearletter(msb);
|
||||
b &= ~(1L << msb);
|
||||
}
|
||||
}
|
||||
}
|
||||
public int len() { return Long.bitCount(lo) + Long.bitCount(hi); }
|
||||
public int clueR() { return Grid.r((key >>> BIT_FOR_DIR)); }
|
||||
public int clueIndex() { return key >>> BIT_FOR_DIR; }
|
||||
public int clueC() { return Grid.c((key >>> BIT_FOR_DIR)); }
|
||||
public int dir() { return key & 7; }
|
||||
public boolean horiz() { return horiz(key); }
|
||||
public int pos(int i) { return offset(packedPos, i); }
|
||||
public static boolean horiz(int key) { return (key & 1) == 0; }
|
||||
public static int offset(long packedPos, int i) { return (int) ((packedPos >>> (i * 7)) & 127); }
|
||||
public boolean horiz() { return horiz(dir()); }
|
||||
public int pos(int i) {
|
||||
boolean increasing = (dir() == 2 || dir() == 3);
|
||||
if (increasing) {
|
||||
int bcLo = Long.bitCount(lo);
|
||||
if (i < bcLo) {
|
||||
long temp = lo;
|
||||
for (int k = 0; k < i; k++) temp &= temp - 1;
|
||||
return Long.numberOfTrailingZeros(temp);
|
||||
} else {
|
||||
i -= bcLo;
|
||||
long temp = hi;
|
||||
for (int k = 0; k < i; k++) temp &= temp - 1;
|
||||
return 64 | Long.numberOfTrailingZeros(temp);
|
||||
}
|
||||
} else {
|
||||
int bcHi = Long.bitCount(hi);
|
||||
if (i < bcHi) {
|
||||
long temp = hi;
|
||||
for (int k = 0; k < i; k++) temp &= ~(1L << (63 - Long.numberOfLeadingZeros(temp)));
|
||||
return 64 | (63 - Long.numberOfLeadingZeros(temp));
|
||||
} else {
|
||||
i -= bcHi;
|
||||
long temp = lo;
|
||||
for (int k = 0; k < i; k++) temp &= ~(1L << (63 - Long.numberOfLeadingZeros(temp)));
|
||||
return 63 - Long.numberOfLeadingZeros(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static boolean horiz(int d) { return (d & 1) == 0; }
|
||||
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) {
|
||||
private static void processSlot(Grid grid, SlotVisitor visitor, int idx) {
|
||||
int d = grid.digitAt(idx); // 1..4
|
||||
int di = d - 1; // 0..3
|
||||
int key = (idx << 2) | di;
|
||||
@@ -370,28 +410,13 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
|
||||
if ((rayLo | rayHi) != 0) {
|
||||
visitor.visitMasks(Slot.packSlotDir(idx, d), rayLo, rayHi);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processSlot(Grid grid, SlotVisitor visitor, int idx) {
|
||||
var d = grid.digitAt(idx);
|
||||
var packed = OFFSETS_D_IDX[(d - 1) | (idx << 2)];
|
||||
long packedPos = 0L;
|
||||
int k = 0;
|
||||
for (long n = (packed >>> 56), offset = 0L, iidx; k < n; k++, offset += 7L) {
|
||||
iidx = ((packed >>> offset) & 0x7FL);
|
||||
if (grid.isClue(iidx)) break;
|
||||
packedPos |= iidx << offset;
|
||||
}
|
||||
if (k > 0) {
|
||||
visitor.visit(Slot.packSlotDir(idx, d), packedPos, k);
|
||||
visitor.visit(Slot.packSlotDir(idx, d), rayLo, rayHi);
|
||||
}
|
||||
}
|
||||
|
||||
static ArrayList<Slot> extractSlots(Grid grid) {
|
||||
var slots = new ArrayList<Slot>(32);
|
||||
grid.forEachSlot((key, packedPos, len) -> slots.add(Slot.from(key, packedPos, len)));
|
||||
grid.forEachSlot((key, lo, hi) -> slots.add(Slot.from(key, lo, hi)));
|
||||
return slots;
|
||||
}
|
||||
|
||||
@@ -409,20 +434,28 @@ public record SwedishGenerator(Rng rng) {
|
||||
|
||||
for (int i = 0; i < 65; i += 64) {
|
||||
for (long bits = (i == 0 ? lo_cl : hi_cl); bits != X; bits &= bits - 1) {
|
||||
int clueIdx = i | Long.numberOfTrailingZeros(bits);
|
||||
var d = grid.digitAt(clueIdx);
|
||||
long packed = OFFSETS_D_IDX[(d - 1) | (clueIdx << 2)];
|
||||
|
||||
int n = (int) (packed >>> 56) * 7, k, idx;
|
||||
var horiz = Slot.horiz(d) ? covH : covV;
|
||||
for (k = 0; k < n; k += 7) {
|
||||
idx = (int) ((packed >>> (k)) & 0x7F);
|
||||
if (grid.isClue(idx)) break;
|
||||
horiz.set(idx);
|
||||
int clueIdx = i | Long.numberOfTrailingZeros(bits);
|
||||
int d = grid.digitAt(clueIdx);
|
||||
int di = d - 1;
|
||||
int key = (clueIdx << 2) | di;
|
||||
long rLo = PATH_LO[key], rHi = PATH_HI[key];
|
||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
||||
if (d == 2 || d == 3) {
|
||||
if (hLo != 0) { rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1); rHi = 0; }
|
||||
else if (hHi != 0) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); }
|
||||
} else {
|
||||
if (hHi != 0) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hHi);
|
||||
rHi &= ~((1L << msb << 1) - 1); rLo = 0;
|
||||
} else if (hLo != 0) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hLo);
|
||||
rLo &= ~((1L << msb << 1) - 1);
|
||||
}
|
||||
}
|
||||
if (k > 0) {
|
||||
if ((rLo | rHi) != 0) {
|
||||
hasSlots = true;
|
||||
if (k < MIN_LEN7) penalty += 8000;
|
||||
if (Slot.horiz(d)) covH.or(rLo, rHi); else covV.or(rLo, rHi);
|
||||
if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
||||
} else {
|
||||
penalty += 25000;
|
||||
}
|
||||
@@ -644,37 +677,73 @@ public record SwedishGenerator(Rng rng) {
|
||||
|
||||
static long patternForSlot(Grid grid, Slot s) {
|
||||
long p = 0;
|
||||
for (int i = 0, len = s.len(); i < len; i++) {
|
||||
byte ch = grid.byteAt(s.pos(i));
|
||||
if (isLetter(ch)) {
|
||||
p |= ((long) (ch & 31)) << (i * 5);
|
||||
int i = 0;
|
||||
boolean increasing = (s.dir() == 2 || s.dir() == 3);
|
||||
if (increasing) {
|
||||
for (long b = s.lo; b != 0; b &= b - 1, i++) {
|
||||
byte ch = grid.byteAt(Long.numberOfTrailingZeros(b));
|
||||
if (isLetter(ch)) p |= ((long) (ch & 31)) << (i * 5);
|
||||
}
|
||||
for (long b = s.hi; b != 0; b &= b - 1, i++) {
|
||||
byte ch = grid.byteAt(64 | Long.numberOfTrailingZeros(b));
|
||||
if (isLetter(ch)) p |= ((long) (ch & 31)) << (i * 5);
|
||||
}
|
||||
} else {
|
||||
for (long b = s.hi; b != 0; i++) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(b);
|
||||
byte ch = grid.byteAt(64 | msb);
|
||||
if (isLetter(ch)) p |= ((long) (ch & 31)) << (i * 5);
|
||||
b &= ~(1L << msb);
|
||||
}
|
||||
for (long b = s.lo; b != 0; i++) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(b);
|
||||
byte ch = grid.byteAt(msb);
|
||||
if (isLetter(ch)) p |= ((long) (ch & 31)) << (i * 5);
|
||||
b &= ~(1L << msb);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static int slotScore(int[] count, Slot s) {
|
||||
int cross = 0, len = s.len();
|
||||
for (int i = 0; i < len; i++) cross += (count[s.pos(i)] - 1);
|
||||
return cross * 10 + len;
|
||||
int cross = 0;
|
||||
for (long b = s.lo; b != 0; b &= b - 1) cross += (count[Long.numberOfTrailingZeros(b)] - 1);
|
||||
for (long b = s.hi; b != 0; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
||||
return cross * 10 + s.len();
|
||||
}
|
||||
static boolean placeWord(Grid grid, Slot s, long w, int[] undoBuffer, int offset) {
|
||||
int mask = 0;
|
||||
byte cur, ch;
|
||||
for (int i = 0, leng = s.len(), idx; i < leng; i++) {
|
||||
idx = s.pos(i);
|
||||
cur = grid.byteAt(idx);
|
||||
ch = Lemma.byteAt(w, i);
|
||||
if (cur == DASH) {
|
||||
mask |= (1 << i);
|
||||
grid.setLetter(idx, ch);
|
||||
} else if (cur != ch) {
|
||||
for (var j = 0; j < i; j++) {
|
||||
if ((mask & (1 << j)) != 0) {
|
||||
grid.clearletter(s.pos(j));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
int mask = 0;
|
||||
boolean increasing = (s.dir() == 2 || s.dir() == 3);
|
||||
int i = 0;
|
||||
if (increasing) {
|
||||
for (long b = s.lo; b != 0; b &= b - 1, i++) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
byte cur = grid.byteAt(idx), ch = Lemma.byteAt(w, i);
|
||||
if (cur == DASH) { mask |= (1 << i); grid.setLetter(idx, ch); }
|
||||
else if (cur != ch) { s.undoPlace(grid, mask); return false; }
|
||||
}
|
||||
for (long b = s.hi; b != 0; b &= b - 1, i++) {
|
||||
int idx = 64 | Long.numberOfTrailingZeros(b);
|
||||
byte cur = grid.byteAt(idx), ch = Lemma.byteAt(w, i);
|
||||
if (cur == DASH) { mask |= (1 << i); grid.setLetter(idx, ch); }
|
||||
else if (cur != ch) { s.undoPlace(grid, mask); return false; }
|
||||
}
|
||||
} else {
|
||||
for (long b = s.hi; b != 0; i++) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(b);
|
||||
int idx = 64 | msb;
|
||||
byte cur = grid.byteAt(idx), ch = Lemma.byteAt(w, i);
|
||||
if (cur == DASH) { mask |= (1 << i); grid.setLetter(idx, ch); }
|
||||
else if (cur != ch) { s.undoPlace(grid, mask); return false; }
|
||||
b &= ~(1L << msb);
|
||||
}
|
||||
for (long b = s.lo; b != 0; i++) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(b);
|
||||
int idx = msb;
|
||||
byte cur = grid.byteAt(idx), ch = Lemma.byteAt(w, i);
|
||||
if (cur == DASH) { mask |= (1 << i); grid.setLetter(idx, ch); }
|
||||
else if (cur != ch) { s.undoPlace(grid, mask); return false; }
|
||||
b &= ~(1L << msb);
|
||||
}
|
||||
}
|
||||
undoBuffer[offset] = mask;
|
||||
@@ -764,7 +833,10 @@ public record SwedishGenerator(Rng rng) {
|
||||
Arrays.fill(count, 0, SIZE, 0);
|
||||
|
||||
val slots = extractSlots(grid);
|
||||
for (var s : slots) for (int i = 0, len = s.len(); i < len; i++) count[s.pos(i)]++;
|
||||
for (var s : slots) {
|
||||
for (long b = s.lo; b != 0; b &= b - 1) count[Long.numberOfTrailingZeros(b)]++;
|
||||
for (long b = s.hi; b != 0; b &= b - 1) count[64 | Long.numberOfTrailingZeros(b)]++;
|
||||
}
|
||||
|
||||
val slotScores = new int[slots.size()];
|
||||
for (int i = 0; i < slots.size(); i++) slotScores[i] = slotScore(count, slots.get(i));
|
||||
|
||||
Reference in New Issue
Block a user