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