introduce bitloops
This commit is contained in:
@@ -20,7 +20,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.IntConsumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SwedishGenerator.java
|
* SwedishGenerator.java
|
||||||
@@ -37,6 +36,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
//@formatter:off
|
//@formatter:off
|
||||||
@FunctionalInterface interface SlotVisitor { void visit(int key, long packedPos, int len); }
|
@FunctionalInterface interface SlotVisitor { void visit(int key, long packedPos, int len); }
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
static final long X = 0L;
|
||||||
static final int LOG_EVERY_MS = 200;
|
static final int LOG_EVERY_MS = 200;
|
||||||
static final int BAR_LEN = 22;
|
static final int BAR_LEN = 22;
|
||||||
static final int C = Config.PUZZLE_COLS;
|
static final int C = Config.PUZZLE_COLS;
|
||||||
@@ -44,6 +44,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
static final int R = Config.PUZZLE_ROWS;
|
static final int R = Config.PUZZLE_ROWS;
|
||||||
static final double CROSS_C = (R - 1) / 2.0;
|
static final double CROSS_C = (R - 1) / 2.0;
|
||||||
static final int SIZE = C * R;// ~18
|
static final int SIZE = C * R;// ~18
|
||||||
|
static final int SIZE_MIN_1 = SIZE - 1;// ~18
|
||||||
static final double SIZED = (double) SIZE;// ~18
|
static final double SIZED = (double) SIZE;// ~18
|
||||||
static final int TARGET_CLUES = SIZE >> 2;
|
static final int TARGET_CLUES = SIZE >> 2;
|
||||||
static final int MAX_WORD_LENGTH = C <= R ? C : R;
|
static final int MAX_WORD_LENGTH = C <= R ? C : R;
|
||||||
@@ -63,6 +64,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
|
|
||||||
// Directions for '1'..'6'
|
// Directions for '1'..'6'
|
||||||
static final nbrs_16[] OFFSETS = Neighbors9x8.OFFSETS;
|
static final nbrs_16[] OFFSETS = Neighbors9x8.OFFSETS;
|
||||||
|
static final nbrs_16[] OFFSETS_FOUR = Neighbors9x8.OFFSETS_FOUR;
|
||||||
static final nbrs_8[] nbrs8 = Neighbors9x8.nbrs8;
|
static final nbrs_8[] nbrs8 = Neighbors9x8.nbrs8;
|
||||||
static final nbrs_8[] nbrs4 = Neighbors9x8.nbrs4;
|
static final nbrs_8[] nbrs4 = Neighbors9x8.nbrs4;
|
||||||
static final rci[] IT = Neighbors9x8.IT;
|
static final rci[] IT = Neighbors9x8.IT;
|
||||||
@@ -80,6 +82,28 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
clamp(Grid.c(i) + dc1 + dc2, 0, C - 1));
|
clamp(Grid.c(i) + dc1 + dc2, 0, C - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*static {
|
||||||
|
Rng trng = new Rng(1);
|
||||||
|
for (int i = 0; i < SIZE; i++) {
|
||||||
|
int[] neighborhood = new int[625];
|
||||||
|
int k = 0;
|
||||||
|
for (int dr1 = -2; dr1 <= 2; dr1++)
|
||||||
|
for (int dr2 = -2; dr2 <= 2; dr2++)
|
||||||
|
for (int dc1 = -2; dc1 <= 2; dc1++)
|
||||||
|
for (int dc2 = -2; dc2 <= 2; dc2++)
|
||||||
|
neighborhood[k++] = Grid.offset(clamp(Grid.r(i) + dr1 + dr2, 0, R - 1),
|
||||||
|
clamp(Grid.c(i) + dc1 + dc2, 0, C - 1));
|
||||||
|
for (k = 0; k < 625; k++) {
|
||||||
|
long packed = 0;
|
||||||
|
for (int s = 0; s < 4; s++) {
|
||||||
|
int ri = neighborhood[trng.randint(0, 624)];
|
||||||
|
int d = trng.randint(1, 4);
|
||||||
|
packed |= ((long) ri | ((long) d << 8)) << (s << 4);
|
||||||
|
}
|
||||||
|
MUTATE_RI[i][k] = packed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
static final Pick PICK_DONE = new Pick(null, null, true);
|
static final Pick PICK_DONE = new Pick(null, null, true);
|
||||||
static final Pick PICK_NOT_DONE = new Pick(null, null, false);
|
static final Pick PICK_NOT_DONE = new Pick(null, null, false);
|
||||||
@@ -145,6 +169,7 @@ 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 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;
|
||||||
@@ -154,59 +179,69 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class Grid {
|
static class Grid {
|
||||||
|
|
||||||
final byte[] g;
|
final byte[] g;
|
||||||
long bo0, bo1;
|
long lo, hi;
|
||||||
|
|
||||||
public Grid(byte[] g) { this(g, 0, 0); }
|
public Grid(byte[] g) { this(g, 0, 0); }
|
||||||
public Grid(byte[] g, long bo0, long bo1) { this.g = g; this.bo0 = bo0; this.bo1 = bo1; }
|
public Grid(byte[] g, long lo, long hi) {
|
||||||
static Grid createEmpty() { return new Grid(new byte[SIZE], 0L, 0L); }
|
this.g = g;
|
||||||
|
this.lo = lo;
|
||||||
|
this.hi = hi;
|
||||||
|
}
|
||||||
|
static Grid createEmpty() { return new Grid(new byte[SIZE], X, X); }
|
||||||
int digitAt(int index) { return g[index] - 48; }
|
int digitAt(int index) { return g[index] - 48; }
|
||||||
public static int r(int offset) { return offset & 7; }
|
public static int r(int offset) { return offset & 7; }
|
||||||
public static int c(int offset) { return offset >>> 3; }
|
public static int c(int offset) { return offset >>> 3; }
|
||||||
static int offset(int r, int c) { return r | (c << 3); }
|
static int offset(int r, int c) { return r | (c << 3); }
|
||||||
Grid deepCopyGrid() { return new Grid(g.clone(), bo0, bo1); }
|
Grid deepCopyGrid() { return new Grid(g.clone(), lo, hi); }
|
||||||
public byte byteAt(int pos) { return g[pos]; }
|
public byte byteAt(int pos) { return g[pos]; }
|
||||||
void setByteAt(int idx, byte ch) { g[idx] = ch; }
|
void setByteAt(int idx, byte ch) { g[idx] = ch; }
|
||||||
void setClue(int idx, byte ch) {
|
void setClue(int idx, byte ch) {
|
||||||
g[idx] = ch;
|
g[idx] = ch;
|
||||||
if (idx < 64) bo0 |= (1L << idx);
|
if (idx < 64) lo |= (1L << idx);
|
||||||
else bo1 |= (1L << (idx & 63));
|
else hi |= (1L << (idx & 63));
|
||||||
}
|
}
|
||||||
void clear(int idx) { g[idx] = DASH; }
|
void clear(int idx) { g[idx] = DASH; }
|
||||||
void clearClue(int idx) {
|
void clearClue(int idx) {
|
||||||
g[idx] = DASH;
|
g[idx] = DASH;
|
||||||
if (idx < 64) bo0 &= ~(1L << idx);
|
if (idx < 64) lo &= ~(1L << idx);
|
||||||
else bo1 &= ~(1L << (idx & 63));
|
else hi &= ~(1L << (idx & 63));
|
||||||
}
|
}
|
||||||
static boolean isDigit(byte b) { return (b & 48) == 48; }
|
static boolean isDigit(byte b) { return (b & 48) == 48; }
|
||||||
boolean isDigitAt(int index) { return isDigit(g[index]); }
|
boolean isDigitAt(int index) { return isDigit(g[index]); }
|
||||||
|
boolean isClue(long index) {
|
||||||
|
if (index < 64) return ((lo >> index) & 1L) != X;
|
||||||
|
return ((hi >> (index & 63)) & 1L) != X;
|
||||||
|
}
|
||||||
boolean isClue(int index) {
|
boolean isClue(int index) {
|
||||||
if (index < 64) return ((bo0 >> index) & 1L) != 0;
|
if (index < 64) return ((lo >> index) & 1L) != 0;
|
||||||
return ((bo1 >> (index & 63)) & 1L) != 0;
|
return ((hi >> (index & 63)) & 1L) != 0;
|
||||||
|
}
|
||||||
|
boolean notClue(long index) {
|
||||||
|
if (index < 64) return ((lo >> index) & 1L) == X;
|
||||||
|
return ((hi >> (index & 63)) & 1L) == X;
|
||||||
}
|
}
|
||||||
boolean notClue(int index) {
|
boolean notClue(int index) {
|
||||||
if (index < 64) return ((bo0 >> index) & 1L) == 0L;
|
if (index < 64) return ((lo >> index) & 1L) == X;
|
||||||
return ((bo1 >> (index & 63)) & 1L) == 0L;
|
return ((hi >> (index & 63)) & 1L) == X;
|
||||||
}
|
}
|
||||||
boolean clueless(int idx) {
|
boolean clueless(int idx) {
|
||||||
if (idx < 64) {
|
if (idx < 64) {
|
||||||
val test = (1L << idx);
|
val test = (1L << idx);
|
||||||
if ((test & bo0) != 0L) {
|
if ((test & lo) == X) return false;
|
||||||
g[idx] = DASH;
|
g[idx] = DASH;
|
||||||
bo0 &= ~test;
|
|
||||||
return true;
|
lo &= ~test;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
val test = (1L << (idx & 63));
|
val test = (1L << (idx & 63));
|
||||||
if ((test & bo1) != 0L) {
|
if ((test & hi) == X) return false;
|
||||||
g[idx] = DASH;
|
g[idx] = DASH;
|
||||||
bo1 &= ~test;
|
|
||||||
|
hi &= ~test;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static boolean isLetter(byte b) { return (b & 64) != 0; }
|
static boolean isLetter(byte b) { return (b & 64) != 0; }
|
||||||
public boolean isLetterSet(int idx) { return isLetter(g[idx]); }
|
public boolean isLetterSet(int idx) { return isLetter(g[idx]); }
|
||||||
static boolean notDigit(byte b) { return (b & 48) != 48; }
|
static boolean notDigit(byte b) { return (b & 48) != 48; }
|
||||||
@@ -217,11 +252,17 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
for (int i = 0; i < SIZE; i++) if (g[i] == b.g[i]) same++;
|
for (int i = 0; i < SIZE; i++) if (g[i] == b.g[i]) same++;
|
||||||
return same / SIZED;
|
return same / SIZED;
|
||||||
}
|
}
|
||||||
int clueCount() { return Long.bitCount(bo0) + Long.bitCount(bo1); }
|
int clueCount() { return Long.bitCount(lo) + Long.bitCount(hi); }
|
||||||
|
/* for (int k = 0, n = Math.min(MAX_WORD_LENGTH7, (int) (packed >>> 56) * 7); k < n; ) {
|
||||||
|
if (isClue((int) ((packed >>> k) & 0x7F))) break;
|
||||||
|
k += 7;
|
||||||
|
if (k >= MIN_LEN7) return true;
|
||||||
|
}
|
||||||
|
return false;*/
|
||||||
|
boolean hasRoomForClue(long packed) { return ((packed >>> 56)) > 1L && notClue(packed & 0x7FL) && notClue((packed >>> 7) & 0x7FL); }
|
||||||
void forEachSlot(SlotVisitor visitor) {
|
void forEachSlot(SlotVisitor visitor) {
|
||||||
for (var lo = bo0; lo != 0L; lo &= lo - 1) processSlot(this, visitor, Long.numberOfTrailingZeros(lo));
|
for (var l = lo; l != X; l &= l - 1) processSlot(this, visitor, Long.numberOfTrailingZeros(l));
|
||||||
for (var hi = bo1; hi != 0L; hi &= hi - 1) processSlot(this, visitor, 64 + Long.numberOfTrailingZeros(hi));
|
for (var h = hi; h != X; h &= h - 1) processSlot(this, visitor, 64 + Long.numberOfTrailingZeros(h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +416,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
public int dir() { return key & 15; }
|
public int dir() { return key & 15; }
|
||||||
public boolean horiz() { return horiz(key); }
|
public boolean horiz() { return horiz(key); }
|
||||||
public int pos(int i) { return offset(packedPos, i); }
|
public int pos(int i) { return offset(packedPos, i); }
|
||||||
public static boolean horiz(int key) { return ((key & 15) & 1) == 0; }
|
public static boolean horiz(int key) { return (key & 1) == 0/*((key & 15) & 1) == 0*/; }
|
||||||
public static int offset(long packedPos, int i) { return (int) ((packedPos >> (i * 7)) & 127); }
|
public static int offset(long packedPos, int i) { return (int) ((packedPos >> (i * 7)) & 127); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,14 +440,6 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
grid.forEachSlot((key, packedPos, len) -> slots.add(Slot.from(key, packedPos, len)));
|
grid.forEachSlot((key, packedPos, len) -> slots.add(Slot.from(key, packedPos, len)));
|
||||||
return slots;
|
return slots;
|
||||||
}
|
}
|
||||||
static boolean hasRoomForClue(Grid grid, long packed) {
|
|
||||||
for (int n = (int) (packed >>> 56) * 7, k = 0; k < n && k < MAX_WORD_LENGTH7; ) {
|
|
||||||
if (grid.isClue((int) ((packed >>> k) & 0x7F))) break;
|
|
||||||
k += 7;
|
|
||||||
if (k >= MIN_LEN7) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
long maskFitness(Grid grid) {
|
long maskFitness(Grid grid) {
|
||||||
var ctx = CTX.get();
|
var ctx = CTX.get();
|
||||||
@@ -415,12 +448,12 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
Arrays.fill(covH, 0, SIZE, 0);
|
Arrays.fill(covH, 0, SIZE, 0);
|
||||||
Arrays.fill(covV, 0, SIZE, 0);
|
Arrays.fill(covV, 0, SIZE, 0);
|
||||||
|
|
||||||
long lo_cl = grid.bo0, hi_cl = grid.bo1;
|
long lo_cl = grid.lo, hi_cl = grid.hi;
|
||||||
long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) << 3);
|
long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) << 3);
|
||||||
boolean hasSlots = false;
|
boolean hasSlots = false;
|
||||||
|
|
||||||
for (int i = 0; i < 65; i+=64) {
|
for (int i = 0; i < 65; i += 64) {
|
||||||
for (long bits = (i == 0 ? lo_cl : hi_cl); bits != 0L; bits &= bits - 1) {
|
for (long bits = (i == 0 ? lo_cl : hi_cl); bits != X; bits &= bits - 1) {
|
||||||
int clueIdx = i + Long.numberOfTrailingZeros(bits);
|
int clueIdx = i + Long.numberOfTrailingZeros(bits);
|
||||||
var d = grid.digitAt(clueIdx);
|
var d = grid.digitAt(clueIdx);
|
||||||
var nbrs16 = OFFSETS[d];
|
var nbrs16 = OFFSETS[d];
|
||||||
@@ -445,8 +478,8 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
var stack = ctx.stack;
|
var stack = ctx.stack;
|
||||||
seen.clear();
|
seen.clear();
|
||||||
|
|
||||||
for (int i = 0; i < 65; i+=64) {
|
for (int i = 0; i < 65; i += 64) {
|
||||||
for (long bits = (i == 0 ? lo_cl : hi_cl); bits != 0L; bits &= bits - 1) {
|
for (long bits = (i == 0 ? lo_cl : hi_cl); bits != X; bits &= bits - 1) {
|
||||||
int clueIdx = i + Long.numberOfTrailingZeros(bits);
|
int clueIdx = i + Long.numberOfTrailingZeros(bits);
|
||||||
if (seen.get(clueIdx)) continue;
|
if (seen.get(clueIdx)) continue;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
@@ -454,8 +487,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
seen.set(clueIdx);
|
seen.set(clueIdx);
|
||||||
for (int sp = 1; sp > 0; size++) {
|
for (int sp = 1; sp > 0; size++) {
|
||||||
long packed = Neighbors9x8.NBR8_PACKED[stack[--sp]];
|
long packed = Neighbors9x8.NBR8_PACKED[stack[--sp]];
|
||||||
int n = (int) (packed >>> 56) * 7;
|
for (int k = 0, n = (int) (packed >>> 56) * 7; k < n; k += 7) {
|
||||||
for (int k = 0; k < n; k += 7) {
|
|
||||||
int nidx = (int) ((packed >>> k) & 0x7F);
|
int nidx = (int) ((packed >>> k) & 0x7F);
|
||||||
if (seen.get(nidx) || grid.notClue(nidx)) continue;
|
if (seen.get(nidx) || grid.notClue(nidx)) continue;
|
||||||
seen.set(nidx);
|
seen.set(nidx);
|
||||||
@@ -466,9 +498,9 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 65; i+=64) {
|
for (int i = 0; i < 65; i += 64) {
|
||||||
long bits = (i == 0 ? ~lo_cl : (~hi_cl & 0xFFL));
|
long bits = (i == 0 ? ~lo_cl : (~hi_cl & 0xFFL));
|
||||||
for (; bits != 0L; bits &= bits - 1) {
|
for (; bits != X; bits &= bits - 1) {
|
||||||
int idx = i + Long.numberOfTrailingZeros(bits);
|
int idx = i + Long.numberOfTrailingZeros(bits);
|
||||||
var rci = IT[idx];
|
var rci = IT[idx];
|
||||||
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
||||||
@@ -486,11 +518,11 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
Grid randomMask() {
|
Grid randomMask() {
|
||||||
var g = Grid.createEmpty();
|
var g = Grid.createEmpty();
|
||||||
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 - 1);
|
idx = rng.randint(0, SIZE_MIN_1);
|
||||||
if (g.isClue(idx)) continue;
|
if (g.isClue(idx)) continue;
|
||||||
var d = OFFSETS[rng.randbyte(1, 4)];
|
var d = OFFSETS_FOUR[rng.randint2bit()];
|
||||||
|
|
||||||
if (hasRoomForClue(g, d.path()[idx])) {
|
if (g.hasRoomForClue(d.path()[idx])) {
|
||||||
g.setClue(idx, d.dbyte());
|
g.setClue(idx, d.dbyte());
|
||||||
placed++;
|
placed++;
|
||||||
}
|
}
|
||||||
@@ -499,15 +531,14 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
}
|
}
|
||||||
Grid mutate(Grid grid) {
|
Grid mutate(Grid grid) {
|
||||||
var g = grid.deepCopyGrid();
|
var g = grid.deepCopyGrid();
|
||||||
var centerIdx = rng.randint(0, SIZE - 1);
|
int ri;
|
||||||
|
var bytes = MUTATE_RI[rng.randint(0, SIZE_MIN_1)];
|
||||||
var steps = 4;
|
nbrs_16 d;
|
||||||
for (var k = 0; k < steps; k++) {
|
for (var k = 0; k < 4; k++) {
|
||||||
var ri = MUTATE_RI[centerIdx][rng.randint(0, 624)];
|
ri = bytes[rng.randint(0, 624)];
|
||||||
|
|
||||||
if (!g.clueless(ri)) {
|
if (!g.clueless(ri)) {
|
||||||
var d = OFFSETS[rng.randint(1, 4)];
|
d = OFFSETS_FOUR[rng.randint2bit()];
|
||||||
if (hasRoomForClue(g, d.path()[ri])) g.setClue(ri, d.dbyte());
|
if (g.hasRoomForClue(d.path()[ri])) g.setClue(ri, d.dbyte());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return g;
|
return g;
|
||||||
@@ -518,7 +549,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
var nc = Math.cos(theta);
|
var nc = Math.cos(theta);
|
||||||
var nr = Math.sin(theta);
|
var nr = Math.sin(theta);
|
||||||
|
|
||||||
long bo0 = out.bo0, bo1 = out.bo1;
|
long bo0 = out.lo, bo1 = out.hi;
|
||||||
for (var rci : IT) {
|
for (var rci : IT) {
|
||||||
int i = rci.i();
|
int i = rci.i();
|
||||||
if ((rci.cross_r()) * nc + (rci.cross_c()) * nr < 0) {
|
if ((rci.cross_r()) * nc + (rci.cross_c()) * nr < 0) {
|
||||||
@@ -535,13 +566,13 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.bo0 = bo0;
|
out.lo = bo0;
|
||||||
out.bo1 = bo1;
|
out.hi = bo1;
|
||||||
for (var lo = out.bo0; lo != 0L; 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.bo1; hi != 0L; 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 (!hasRoomForClue(out, OFFSETS[out.digitAt(idx)].path()[idx])) out.clearClue(idx); }
|
public static void clearClues(Grid out, int idx) { if (!out.hasRoomForClue(OFFSETS[out.digitAt(idx)].path()[idx])) out.clearClue(idx); }
|
||||||
|
|
||||||
Grid hillclimb(Grid start, int limit) {
|
Grid hillclimb(Grid start, int limit) {
|
||||||
var best = start;
|
var best = start;
|
||||||
|
|||||||
Reference in New Issue
Block a user