introduce bitloops
This commit is contained in:
@@ -127,27 +127,6 @@ public record Export() {
|
||||
}
|
||||
}
|
||||
|
||||
static class Bit {
|
||||
|
||||
long l1, l2;
|
||||
public boolean get(int bitIndex) {
|
||||
if ((bitIndex & 64) == 0) return (l1 & (1L << bitIndex)) != 0L;
|
||||
return (l2 & (1L << (bitIndex & 63))) != 0L;
|
||||
}
|
||||
public void set(int bitIndex) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
record Bit1029(long[] bits) {
|
||||
|
||||
public Bit1029() { this(new long[2048]); }
|
||||
|
||||
@@ -4,7 +4,6 @@ import lombok.Getter;
|
||||
import lombok.val;
|
||||
import precomp.Neighbors9x8;
|
||||
import precomp.Neighbors9x8.rci;
|
||||
import puzzle.Export.Bit;
|
||||
import puzzle.Export.Bit1029;
|
||||
import puzzle.Export.DictEntryDTO;
|
||||
import puzzle.Export.Gridded;
|
||||
@@ -53,7 +52,6 @@ public record SwedishGenerator(Rng rng) {
|
||||
static final int MAX_WORD_LENGTH = C <= R ? C : R;
|
||||
static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1;
|
||||
static final int MIN_LEN = Config.MIN_LEN;
|
||||
static final int MIN_LEN7 = Config.MIN_LEN * 7;
|
||||
static final int MAX_TRIES_PER_SLOT = Config.MAX_TRIES_PER_SLOT;
|
||||
static final char C_DASH = '\0';
|
||||
static final byte _1 = 49, _9 = 57, A = 65, Z = 90, DASH = (byte) C_DASH;
|
||||
@@ -66,15 +64,15 @@ public record SwedishGenerator(Rng rng) {
|
||||
// 0b01
|
||||
// 0b10
|
||||
|
||||
static final byte B0 = (byte) 0;
|
||||
static final byte B64 = (byte) 64;
|
||||
static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSET_D_IDX_0_BASE;
|
||||
static final rci[] IT = Neighbors9x8.IT;
|
||||
static final int[][] MUTATE_RI = new int[SIZE][625];
|
||||
static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO;
|
||||
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 final byte B0 = (byte) 0;
|
||||
static final byte B64 = (byte) 64;
|
||||
static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSET_D_IDX_0_BASE;
|
||||
static final rci[] IT = Neighbors9x8.IT;
|
||||
static final int[][] MUTATE_RI = new int[SIZE][625];
|
||||
static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO;
|
||||
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 {
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
@@ -116,11 +114,8 @@ public record SwedishGenerator(Rng rng) {
|
||||
|
||||
static final class Context {
|
||||
|
||||
final Bit covH2 = new Bit();
|
||||
final Bit covV2 = new Bit();
|
||||
final int[] cellCount = new int[SIZE];
|
||||
final int[] stack = new int[SIZE];
|
||||
final Bit seen = new Bit();
|
||||
long pattern;
|
||||
final long[] undo = new long[128];
|
||||
final long[] bitset = new long[2500];
|
||||
@@ -149,7 +144,8 @@ public record SwedishGenerator(Rng rng) {
|
||||
var range = (long) max - (long) min + 1L;
|
||||
return (byte) (min + (u % range));
|
||||
}
|
||||
int randint2bit() { return nextU32() & 3; }
|
||||
int randint2bit() { return nextU32() & 3; }
|
||||
byte randint2bitByte() { return (byte) (nextU32() & 3); }
|
||||
int randint(int min, int max) {
|
||||
var u = (nextU32() & 0xFFFFFFFFL);
|
||||
var range = (long) max - (long) min + 1L;
|
||||
@@ -227,7 +223,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
}
|
||||
|
||||
static record DictEntry(long[] words, long[][] posBitsets) { }
|
||||
static record DictEntry(long[] words, long[][] posBitsets, int numlong) { }
|
||||
|
||||
static int LEMMA_COUNTER = 0;
|
||||
|
||||
@@ -240,7 +236,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
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] & ~64) << (i * 5);
|
||||
for (var i = 0; i < b.length; i++) w |= ((long) b[i] & 63) << (i * 5);
|
||||
return w;
|
||||
}
|
||||
static public long from(String word) { return pack(LEMMA_COUNTER++, word.getBytes(US_ASCII)); }
|
||||
@@ -295,7 +291,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DictEntry(words, bitsets);
|
||||
return new DictEntry(words, bitsets, (words.length + 63) >>> 6);
|
||||
}).toArray(DictEntry[]::new),
|
||||
Arrays.stream(index).mapToInt(i -> i.words().size()).sum());
|
||||
}
|
||||
@@ -330,7 +326,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
|
||||
private static void processSlot(Grid grid, SlotVisitor visitor, int idx) {
|
||||
int d = grid.digitAt(idx); // 0..3
|
||||
int key = (idx << 2) | d;
|
||||
int key = Slot.packSlotDir(idx, d);
|
||||
|
||||
long rayLo = PATH_LO[key];
|
||||
long rayHi = PATH_HI[key];
|
||||
@@ -341,9 +337,8 @@ public record SwedishGenerator(Rng rng) {
|
||||
|
||||
// slice ray to stop before first clue, depending on direction monotonicity
|
||||
// right/down => increasing indices; up/left => decreasing indices
|
||||
boolean increasing = Slot.increasing(d);
|
||||
|
||||
if (increasing) {
|
||||
if (Slot.increasing(d)) {
|
||||
// first clue is lowest index among hits (lo first, then hi)
|
||||
if (hitsLo != 0) {
|
||||
long stop = 1L << Long.numberOfTrailingZeros(hitsLo);
|
||||
@@ -369,7 +364,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
|
||||
if ((rayLo | rayHi) != 0) {
|
||||
visitor.visit(Slot.packSlotDir(idx, d), rayLo, rayHi);
|
||||
visitor.visit(key, rayLo, rayHi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,11 +375,8 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
|
||||
long maskFitness(Grid grid) {
|
||||
var ctx = CTX.get();
|
||||
var covH = ctx.covH2;
|
||||
var covV = ctx.covV2;
|
||||
covH.clear();
|
||||
covV.clear();
|
||||
var ctx = CTX.get();
|
||||
long cHLo = 0L, cHHi = 0L, cVLo = 0L, cVHi = 0L;
|
||||
long lo_cl = grid.lo, hi_cl = grid.hi;
|
||||
long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) * 16000L);
|
||||
boolean hasSlots = false;
|
||||
@@ -413,8 +405,13 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
if ((rLo | rHi) != 0) {
|
||||
hasSlots = true;
|
||||
if (Slot.horiz(d)) covH.or(rLo, rHi);
|
||||
else covV.or(rLo, rHi);
|
||||
if (Slot.horiz(d)) {
|
||||
cHLo |= rLo;
|
||||
cHHi |= rHi;
|
||||
} else {
|
||||
cVLo |= rLo;
|
||||
cVHi |= rHi;
|
||||
}
|
||||
if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
||||
} else {
|
||||
penalty += 25000;
|
||||
@@ -485,18 +482,25 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 65; i += 64) {
|
||||
long bits = (i == 0 ? ~lo_cl : (~hi_cl & 0xFFL));
|
||||
for (; bits != X; bits &= bits - 1) {
|
||||
int clueIdx = i + Long.numberOfTrailingZeros(bits);
|
||||
var rci = IT[clueIdx];
|
||||
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
||||
var h = covH.get(clueIdx);
|
||||
var v = covV.get(clueIdx);
|
||||
if (!h && !v) penalty += 1500;
|
||||
else if (h && v) { /* ok */ } else if (h | v) penalty += 200;
|
||||
else penalty += 600;
|
||||
}
|
||||
for (long bits = ~lo_cl; bits != X; bits &= bits - 1) {
|
||||
int clueIdx = Long.numberOfTrailingZeros(bits);
|
||||
var rci = IT[clueIdx];
|
||||
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
||||
boolean h = (cHLo & (1L << clueIdx)) != 0;
|
||||
boolean v = (cVLo & (1L << clueIdx)) != 0;
|
||||
if (!h && !v) penalty += 1500;
|
||||
else if (h && v) { /* ok */ } else if (h | v) penalty += 200;
|
||||
else penalty += 600;
|
||||
}
|
||||
for (long bits = ~hi_cl & 0xFFL; bits != X; bits &= bits - 1) {
|
||||
int clueIdx = Long.numberOfTrailingZeros(bits);
|
||||
var rci = IT[64 | clueIdx];
|
||||
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
||||
boolean h = (cHHi & (1L << clueIdx)) != 0;
|
||||
boolean v = (cVHi & (1L << clueIdx)) != 0;
|
||||
if (!h && !v) penalty += 1500;
|
||||
else if (h && v) { /* ok */ } else if (h | v) penalty += 200;
|
||||
else penalty += 600;
|
||||
}
|
||||
|
||||
return penalty;
|
||||
@@ -507,9 +511,9 @@ public record SwedishGenerator(Rng rng) {
|
||||
for (int placed = 0, guard = 0, idx; placed < TARGET_CLUES && guard < 4000; guard++) {
|
||||
idx = rng.randint(0, SIZE_MIN_1);
|
||||
if (g.isClue(idx)) continue;
|
||||
int d_idx = rng.randint2bit();
|
||||
var d_idx = rng.randint2bitByte();
|
||||
if (g.hasRoomForClue(OFFSETS_D_IDX[d_idx | idx << 2])) {
|
||||
g.setClue(idx, (byte) d_idx);
|
||||
g.setClue(idx, d_idx);
|
||||
placed++;
|
||||
}
|
||||
}
|
||||
@@ -522,9 +526,9 @@ public record SwedishGenerator(Rng rng) {
|
||||
for (var k = 0; k < 4; k++) {
|
||||
ri = bytes[rng.randint(0, 624)];
|
||||
if (!g.clueless(ri)) {
|
||||
int d_idx = rng.randint2bit();
|
||||
var d_idx = rng.randint2bitByte();
|
||||
val packed = OFFSETS_D_IDX[d_idx | ri << 2];
|
||||
if (g.hasRoomForClue(packed)) g.setClue(ri, (byte) d_idx);
|
||||
if (g.hasRoomForClue(packed)) g.setClue(ri, d_idx);
|
||||
}
|
||||
}
|
||||
return g;
|
||||
@@ -555,7 +559,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
out.lo = bo0;
|
||||
out.hi = bo1;
|
||||
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 hi = out.hi; hi != X; hi &= hi - 1L) clearClues(out, 64 | Long.numberOfTrailingZeros(hi));
|
||||
return out;
|
||||
}
|
||||
public static void clearClues(Grid out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[(out.digitAt(idx)) | (idx << 2)])) out.clearClue(idx); }
|
||||
@@ -735,11 +739,11 @@ public record SwedishGenerator(Rng rng) {
|
||||
return new CandidateInfo(null, entry.words.length);
|
||||
}
|
||||
|
||||
int numLongs = (entry.words.length + 63) >>> 6;
|
||||
int numLongs = entry.numlong;
|
||||
long[] res = ctx.bitset;
|
||||
boolean first = true;
|
||||
|
||||
for (int i = 0, len = Lemma.usedCharsInPattern(pattern); i < len; i++) {
|
||||
for (int i = 0, len = lenb/*Lemma.usedCharsInPattern(pattern)*/; i < len; i++) {
|
||||
int val = (int) ((pattern >>> (i * 5)) & 31);
|
||||
if (val != 0) {
|
||||
long[] bs = entry.posBitsets[i * 26 + (val - 1)];
|
||||
@@ -771,15 +775,15 @@ public record SwedishGenerator(Rng rng) {
|
||||
return new CandidateInfo(indices, count);
|
||||
}
|
||||
|
||||
static int candidateCountForPattern(Context ctx, DictEntry entry) {
|
||||
static int candidateCountForPattern(Context ctx, DictEntry entry, int lenb) {
|
||||
long pattern = ctx.pattern;
|
||||
if (pattern == X) return entry.words.length;
|
||||
|
||||
int numLongs = (entry.words.length + 63) >>> 6;
|
||||
int numLongs = entry.numlong;
|
||||
long[] res = ctx.bitset;
|
||||
boolean first = true;
|
||||
|
||||
for (int i = 0, len = Lemma.usedCharsInPattern(pattern); i < len; i++) {
|
||||
for (int i = 0, len = lenb /*Lemma.usedCharsInPattern(pattern)*/; i < len; i++) {
|
||||
int val = (int) ((pattern >>> (i * 5)) & 31);
|
||||
if (val != 0) {
|
||||
long[] bs = entry.posBitsets[i * 26 + (val - 1)];
|
||||
@@ -859,7 +863,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
var entry = dictIndex[s.len()];
|
||||
if (entry == null) return PICK_NOT_DONE;
|
||||
ctx.pattern = patternForSlot(grid, s);
|
||||
int count = candidateCountForPattern(ctx, entry);
|
||||
int count = candidateCountForPattern(ctx, entry, s.len());
|
||||
|
||||
if (count == 0) return PICK_NOT_DONE;
|
||||
if (best == null
|
||||
|
||||
@@ -411,13 +411,13 @@ public class SwedishGeneratorTest {
|
||||
|
||||
var ctx = new Context();
|
||||
ctx.setPattern(Lemma.pack("APP".getBytes(StandardCharsets.US_ASCII)));
|
||||
assertEquals(2, candidateCountForPattern(ctx, entry5));
|
||||
assertEquals(2, candidateCountForPattern(ctx, entry5,3));
|
||||
|
||||
ctx.setPattern(Lemma.pack("BAN".getBytes(StandardCharsets.US_ASCII)));
|
||||
assertEquals(1, candidateCountForPattern(ctx, entry5));
|
||||
assertEquals(1, candidateCountForPattern(ctx, entry5,3));
|
||||
|
||||
ctx.setPattern(Lemma.pack("CAT".getBytes(StandardCharsets.US_ASCII)));
|
||||
assertEquals(0, candidateCountForPattern(ctx, entry5));
|
||||
assertEquals(0, candidateCountForPattern(ctx, entry5,3));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user