diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 139cf53..fb45f51 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -335,10 +335,13 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { } } - static record Slotinfo(int key, long lo, long hi, int score, DictEntry entry) { - + static class Assign { + + long w; } + static record Slotinfo(int key, long lo, long hi, int score, Assign assign, DictEntry entry) { } + static record Slot(int key, long lo, long hi, DictEntry entry) { static final int BIT_FOR_DIR = 2; @@ -725,11 +728,39 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { } return best.grid; } - - static long patternForSlot(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) { - if (((lo & glo) | (hi & ghi)) == X) { - return 0; + static long patternForSlot2(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) { + if (((lo & glo) | (hi & ghi)) == X) return 0; + long p = 0; + int n = 0; + if (Slot.increasing(key)) { + for (long b = lo & glo; b != X; b &= b - 1) { + int idx = numberOfTrailingZeros(b); + int i = bitCount(lo & ((1L << idx) - 1)); + p |= ((long) (i * 26 + g[idx])) << (n++ << 3); + } + int offset = bitCount(lo); + for (long b = hi & ghi; b != X; b &= b - 1) { + int idx = numberOfTrailingZeros(b); + int i = offset + bitCount(hi & ((1L << idx) - 1)); + p |= ((long) (i * 26 + g[64 | idx])) << (n++ << 3); + } + } else { + int offset = bitCount(hi); + for (long b = hi & ghi; b != X; b &= b - 1) { + int idx = numberOfTrailingZeros(b); + int i = bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))); + p |= ((long) (i * 26 + g[64 | idx])) << (n++ << 3); + } + for (long b = lo & glo; b != X; b &= b - 1) { + int idx = numberOfTrailingZeros(b); + int i = offset + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))); + p |= ((long) (i * 26 + g[idx])) << (n++ << 3); + } } + return p; + } + static long patternForSlot(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) { + if (((lo & glo) | (hi & ghi)) == X) return 0; long p = 0; if (Slot.increasing(key)) { for (long b = lo & glo; b != X; b &= b - 1) { @@ -819,34 +850,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { } static int[] candidateInfoForPattern(long[] res, long pattern, long[][] posBitsets, int numLongs) { - boolean first = true; - - for (long p = pattern; p != X; ) { - int combined = (int) (p & 0xFF); - if (combined != X) { - long[] bs = posBitsets[combined - 1]; - if (first) { - System.arraycopy(bs, 0, res, 0, numLongs); - first = false; - } else { - for (int k = 0; k < numLongs; k++) res[k] &= bs[k]; - } - p >>>= 8; - } else { - p >>>= (numberOfTrailingZeros(p) & ~7); - } + System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs); + for (long p = pattern >>> 8; p != X; p >>>= 8) { + long[] bs = posBitsets[(int) (p & 0xFF) - 1]; + for (int k = 0; k < numLongs; k++) res[k] &= bs[k]; } int count = 0; for (int k = 0; k < numLongs; k++) count += bitCount(res[k]); int[] indices = new int[count]; - int ki = 0; - for (int k = 0; k < numLongs; k++) { + for (int k = 0, ki = 0; k < numLongs; k++) { long w = res[k]; while (w != X) { - int t = numberOfTrailingZeros(w); - indices[ki++] = (k << 6) | t; + indices[ki++] = (k << 6) | numberOfTrailingZeros(w); w &= w - 1; } } @@ -855,22 +872,10 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { } static int candidateCountForPattern(final long[] res, final long pattern, final long[][] posBitsets, final int numLongs) { - boolean first = true; - - for (long p = pattern; p != X; ) { - int combined = (int) (p & 0xFF); - if (combined != X) { - long[] bs = posBitsets[combined - 1]; - if (first) { - System.arraycopy(bs, 0, res, 0, numLongs); - first = false; - } else { - for (int k = 0; k < numLongs; k++) res[k] &= bs[k]; - } - p >>>= 8; - } else { - p >>>= (numberOfTrailingZeros(p) & ~7); - } + System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs); + for (long p = pattern >>> 8; p != X; p >>>= 8) { + long[] bs = posBitsets[(int) (p & 0xFF) - 1]; + for (int k = 0; k < numLongs; k++) res[k] &= bs[k]; } int count = 0; @@ -888,21 +893,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { for (int i = 0; i < slots.length; i++) { var slot = slots[i]; slotScores[i] = slotScore(count, slot.lo, slot.hi); - slotInfo[i] = new Slotinfo(slot.key, slot.lo, slot.hi, slotScores[i], slot.entry); + slotInfo[i] = new Slotinfo(slot.key, slot.lo, slot.hi, slotScores[i], new Assign(), slot.entry); } return slotInfo; } public static FillResult fillMask(final Rng rng, final Slotinfo[] slots, final Grid grid, final boolean multiThreaded) { - val NO_LOG = (!Main.VERBOSE || multiThreaded); - val used = new long[2048]; - val assigned = new long[CLUE_INDEX_MAX_SIZE]; - val bitset = new long[2500]; - val g = grid.g; - val TOTAL = slots.length; - val t0 = System.currentTimeMillis(); - val CARRIER = new Pick(null, null, 0); + val NO_LOG = (!Main.VERBOSE || multiThreaded); + val used = new long[2048]; + val bitset = new long[2500]; + val g = grid.g; + val TOTAL = slots.length; + val t0 = System.currentTimeMillis(); + val CARRIER = new Pick(null, null, 0); class Solver { long nodes; @@ -915,8 +919,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { if ((now - lastLog) < LOG_EVERY_MS) return; lastLog = (now); var done = 0; - for (var lemma : assigned) { - if (lemma != X) done++; + for (var lemma : slots) { + if (lemma.assign.w != X) done++; } var pct = (TOTAL == 0) ? 100 : (int) Math.floor((done / (double) TOTAL) * 100); var filled = Math.min(BAR_LEN, (int) Math.floor((pct / 100.0) * BAR_LEN)); @@ -964,11 +968,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { return true; } void chooseMRV() { - Slotinfo best = null; + SwedishGenerator.Slotinfo best = null; for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) { var s = slots[i]; - if (assigned[s.key] != X) continue; - var pattern = patternForSlot(glo, ghi, g, s.key, s.lo, s.hi); + if (s.assign.w != X) continue; + var pattern = patternForSlot2(glo, ghi, g, s.key, s.lo, s.hi); var index = s.entry; count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong); @@ -990,7 +994,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { current = PICK_DONE; return; } - var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi); + var pattern = patternForSlot2(glo, ghi, g, best.key, best.lo, best.hi); var index = best.entry; current = CARRIER; current.slot = best; @@ -1032,21 +1036,19 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { for (var t = 0; t < tries; t++) { var r = rng.nextFloat(); //int idxInArray = rng.biasedIndexPow3(L - 1); - int idxInArray = (int) (r * r * r * (L - 1)); - var idx = idxs[idxInArray]; - var w = entry.words[idx]; - var lemIdx = Lemma.unpackIndex(w); + var w = entry.words[idxs[(int) (r * r * r * (L - 1))]]; + var lemIdx = Lemma.unpackIndex(w); if (Bit1029.get(used, lemIdx)) continue; low = glo; top = ghi; if (!placeWord(k, slo, shi, w)) continue; Bit1029.set(used, lemIdx); - assigned[k] = w; - + //assigned[k] = w; + s.assign.w = w; if (backtrack(depth + 1)) return true; - - assigned[k] = X; + s.assign.w = X; + //assigned[k] = X; Bit1029.clear(used, lemIdx); glo = low; ghi = top; @@ -1059,21 +1061,21 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { var tries = Math.min(MAX_TRIES_PER_SLOT, N); for (var t = 0; t < tries; t++) { - double r = rng.nextFloat(); - int idxInArray = (int) (r * r * r * (N - 1)); - var w = entry.words[idxInArray]; - var lemIdx = Lemma.unpackIndex(w); + double r = rng.nextFloat(); + var w = entry.words[(int) (r * r * r * (N - 1))]; + var lemIdx = Lemma.unpackIndex(w); if (Bit1029.get(used, lemIdx)) continue; low = glo; top = ghi; if (!placeWord(k, slo, shi, w)) continue; Bit1029.set(used, lemIdx); - assigned[k] = w; + s.assign.w = w; + //assigned[k] = w; if (backtrack(depth + 1)) return true; - - assigned[k] = X; + s.assign.w = X; + //assigned[k] = X; Bit1029.clear(used, lemIdx); glo = low; ghi = top; @@ -1091,6 +1093,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { // final progress line grid.lo = solver.glo; grid.hi = solver.ghi; + val assigned = new long[CLUE_INDEX_MAX_SIZE]; + Arrays.stream(slots).forEach(s -> assigned[s.key] = s.assign.w); var res = new FillResult(ok, new Gridded(grid), assigned, new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV)); if (!multiThreaded) { diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index dd5f2c1..a35fc76 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -2,6 +2,7 @@ package puzzle; import lombok.val; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import puzzle.Export.ClueAt; import puzzle.Export.Clued;