@cubingcenter/scrambler 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/search.js +3 -3
- package/dist/puzzles/cube2/solver/tables.d.ts +6 -0
- package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/tables.js +16 -2
- package/dist/puzzles/cube3/index.d.ts +1 -0
- package/dist/puzzles/cube3/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/moves.d.ts.map +1 -1
- package/dist/puzzles/cube3/moves.js +104 -18
- package/dist/puzzles/cube3/scrambler.d.ts +16 -1
- package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube3/scrambler.js +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.js +6 -2
- package/dist/puzzles/cube3/solver/index.d.ts +5 -3
- package/dist/puzzles/cube3/solver/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/index.js +2 -1
- package/dist/puzzles/cube3/solver/node-loader.js +9 -2
- package/dist/puzzles/cube3/solver/phase1.d.ts +18 -0
- package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase1.js +132 -14
- package/dist/puzzles/cube3/solver/phase2.d.ts +47 -0
- package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase2.js +236 -66
- package/dist/puzzles/cube3/solver/search-utils.d.ts +1 -1
- package/dist/puzzles/cube3/solver/search-utils.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/symmetry.d.ts +24 -0
- package/dist/puzzles/cube3/solver/symmetry.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/symmetry.js +74 -0
- package/dist/puzzles/cube3/solver/tables.d.ts +6 -1
- package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube3/validation.d.ts.map +1 -1
- package/dist/puzzles/cube3/validation.js +15 -7
- package/dist/puzzles/cube4/index.d.ts +3 -2
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +2 -2
- package/dist/puzzles/cube4/moves.d.ts +5 -0
- package/dist/puzzles/cube4/moves.d.ts.map +1 -1
- package/dist/puzzles/cube4/moves.js +120 -11
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts +3 -0
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/browser-loader.js +34 -3
- package/dist/puzzles/cube4/reduction/center2.d.ts +20 -3
- package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/center2.js +53 -9
- package/dist/puzzles/cube4/reduction/edge3.d.ts +4 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/edge3.js +23 -3
- package/dist/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
- package/dist/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
- package/dist/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +50 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.js +202 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts +5 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/node-loader.js +48 -8
- package/dist/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts +111 -5
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/phase3-search.js +341 -22
- package/dist/puzzles/cube4/reduction/solve.d.ts +112 -1
- package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/solve.js +920 -181
- package/dist/puzzles/cube4/scrambler.d.ts +105 -4
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +216 -166
- package/dist/puzzles/cube4/state.d.ts.map +1 -1
- package/dist/puzzles/cube4/state.js +4 -1
- package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/search.js +3 -6
- package/dist/puzzles/pyraminx/solver/tables.d.ts +6 -0
- package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/tables.js +17 -0
- package/dist/puzzles/skewb/solver/search.js +3 -3
- package/dist/puzzles/skewb/solver/tables.d.ts +6 -0
- package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/tables.js +17 -0
- package/dist-cjs/puzzles/cube2/solver/search.js +2 -2
- package/dist-cjs/puzzles/cube2/solver/tables.js +17 -3
- package/dist-cjs/puzzles/cube3/moves.js +104 -18
- package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
- package/dist-cjs/puzzles/cube3/solver/browser-loader.js +6 -2
- package/dist-cjs/puzzles/cube3/solver/index.js +8 -1
- package/dist-cjs/puzzles/cube3/solver/node-loader.js +9 -2
- package/dist-cjs/puzzles/cube3/solver/phase1.js +133 -14
- package/dist-cjs/puzzles/cube3/solver/phase2.js +233 -63
- package/dist-cjs/puzzles/cube3/solver/symmetry.js +80 -0
- package/dist-cjs/puzzles/cube3/validation.js +15 -7
- package/dist-cjs/puzzles/cube4/index.js +3 -1
- package/dist-cjs/puzzles/cube4/moves.js +121 -11
- package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +34 -3
- package/dist-cjs/puzzles/cube4/reduction/center2.js +54 -9
- package/dist-cjs/puzzles/cube4/reduction/edge3.js +24 -3
- package/dist-cjs/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +213 -0
- package/dist-cjs/puzzles/cube4/reduction/node-loader.js +48 -8
- package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
- package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +343 -23
- package/dist-cjs/puzzles/cube4/reduction/solve.js +918 -173
- package/dist-cjs/puzzles/cube4/scrambler.js +214 -163
- package/dist-cjs/puzzles/cube4/state.js +4 -1
- package/dist-cjs/puzzles/pyraminx/solver/search.js +2 -5
- package/dist-cjs/puzzles/pyraminx/solver/tables.js +18 -1
- package/dist-cjs/puzzles/skewb/solver/search.js +2 -2
- package/dist-cjs/puzzles/skewb/solver/tables.js +18 -1
- package/package.json +14 -5
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { CENTER3_MOVES } from "./center3.js";
|
|
8
8
|
import { getSymTables, getMvSymFrom, MOVE3_STD } from "./edge3.js";
|
|
9
|
+
import { HC_PDB_MOVES } from "./hc-pdb.js";
|
|
9
10
|
/** The 17 exploration moves (the reference's m < 17 bound). */
|
|
10
11
|
export const SEARCH_MOVES = CENTER3_MOVES.slice(0, 17);
|
|
11
12
|
// Commutation / move-cancellation pruning tables
|
|
@@ -33,79 +34,397 @@ for (let i = 0; i < 20; i++) {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const F_SLOT_MAP = [
|
|
38
|
+
[4, 5, 2, 3, 1, 0, 6, 7, 8, 9, 10, 11],
|
|
39
|
+
[1, 0, 2, 3, 5, 4, 6, 7, 8, 9, 10, 11],
|
|
40
|
+
[5, 4, 2, 3, 0, 1, 6, 7, 8, 9, 10, 11],
|
|
41
|
+
[0, 1, 2, 3, 4, 6, 5, 7, 8, 9, 11, 10],
|
|
42
|
+
[11, 1, 2, 8, 4, 5, 6, 7, 0, 9, 10, 3],
|
|
43
|
+
[3, 1, 2, 0, 4, 5, 6, 7, 11, 9, 10, 8],
|
|
44
|
+
[8, 1, 2, 11, 4, 5, 6, 7, 3, 9, 10, 0],
|
|
45
|
+
[0, 1, 7, 6, 4, 5, 2, 3, 8, 9, 10, 11],
|
|
46
|
+
[0, 1, 3, 2, 4, 5, 7, 6, 8, 9, 10, 11],
|
|
47
|
+
[0, 1, 6, 7, 4, 5, 3, 2, 8, 9, 10, 11],
|
|
48
|
+
[0, 1, 2, 3, 7, 5, 6, 4, 9, 8, 10, 11],
|
|
49
|
+
[0, 9, 10, 3, 4, 5, 6, 7, 8, 2, 1, 11],
|
|
50
|
+
[0, 2, 1, 3, 4, 5, 6, 7, 8, 10, 9, 11],
|
|
51
|
+
[0, 10, 9, 3, 4, 5, 6, 7, 8, 1, 2, 11],
|
|
52
|
+
[1, 0, 2, 3, 5, 4, 6, 7, 8, 11, 10, 9],
|
|
53
|
+
[0, 3, 2, 1, 4, 6, 5, 7, 8, 9, 11, 10],
|
|
54
|
+
[3, 1, 2, 0, 4, 7, 6, 5, 11, 9, 10, 8]
|
|
55
|
+
];
|
|
56
|
+
const H_SLOT_MAP = [
|
|
57
|
+
[4, 5, 2, 3, 1, 0, 6, 7, 8, 9, 10, 11],
|
|
58
|
+
[1, 0, 2, 3, 5, 4, 6, 7, 8, 9, 10, 11],
|
|
59
|
+
[5, 4, 2, 3, 0, 1, 6, 7, 8, 9, 10, 11],
|
|
60
|
+
[0, 1, 2, 3, 4, 6, 5, 7, 8, 9, 11, 10],
|
|
61
|
+
[11, 1, 2, 8, 4, 5, 6, 7, 0, 9, 10, 3],
|
|
62
|
+
[3, 1, 2, 0, 4, 5, 6, 7, 11, 9, 10, 8],
|
|
63
|
+
[8, 1, 2, 11, 4, 5, 6, 7, 3, 9, 10, 0],
|
|
64
|
+
[0, 1, 7, 6, 4, 5, 2, 3, 8, 9, 10, 11],
|
|
65
|
+
[0, 1, 3, 2, 4, 5, 7, 6, 8, 9, 10, 11],
|
|
66
|
+
[0, 1, 6, 7, 4, 5, 3, 2, 8, 9, 10, 11],
|
|
67
|
+
[0, 1, 2, 3, 7, 5, 6, 4, 9, 8, 10, 11],
|
|
68
|
+
[0, 9, 10, 3, 4, 5, 6, 7, 8, 2, 1, 11],
|
|
69
|
+
[0, 2, 1, 3, 4, 5, 6, 7, 8, 10, 9, 11],
|
|
70
|
+
[0, 10, 9, 3, 4, 5, 6, 7, 8, 1, 2, 11],
|
|
71
|
+
[1, 0, 2, 3, 5, 4, 6, 7, 10, 9, 8, 11],
|
|
72
|
+
[2, 1, 0, 3, 4, 6, 5, 7, 8, 9, 11, 10],
|
|
73
|
+
[3, 1, 2, 0, 6, 5, 4, 7, 11, 9, 10, 8]
|
|
74
|
+
];
|
|
39
75
|
export class FastPhase3Solver {
|
|
40
76
|
tempep;
|
|
41
77
|
moveLog;
|
|
42
78
|
sym;
|
|
79
|
+
/** Transposition Table size: 2^21 = 2,097,152 entries (24 MB in RAM).
|
|
80
|
+
* NOTE: doubling to 4M was tried and reverted (-0.07% nodes on the
|
|
81
|
+
* corpus — the 2M working set already captures the hit locality). */
|
|
82
|
+
static TT_SIZE = 1 << 21;
|
|
83
|
+
static TT_MASK = FastPhase3Solver.TT_SIZE - 1;
|
|
84
|
+
static tt = new Uint32Array(FastPhase3Solver.TT_SIZE * 3);
|
|
85
|
+
static epoch = 1;
|
|
86
|
+
/**
|
|
87
|
+
* Per-slot exact-length-call tag (8 MB transient). TT pruning stays
|
|
88
|
+
* epoch-scoped (unchanged traversal), but threshold proofs only trust
|
|
89
|
+
* same-call hits: a hit from another call may have validated under a
|
|
90
|
+
* different candidate, so it still prunes yet marks the proof dirty.
|
|
91
|
+
*/
|
|
92
|
+
static ttGen = new Uint32Array(FastPhase3Solver.TT_SIZE);
|
|
93
|
+
static callSeq = 1;
|
|
94
|
+
callId = 0;
|
|
95
|
+
/** Reset the per-attempt cumulative node counter. */
|
|
96
|
+
resetEpochNodes() {
|
|
97
|
+
this.epochNodes = 0;
|
|
98
|
+
}
|
|
99
|
+
static nextEpoch() {
|
|
100
|
+
FastPhase3Solver.epoch = (FastPhase3Solver.epoch + 1) & 0xffff;
|
|
101
|
+
if (FastPhase3Solver.epoch === 0) {
|
|
102
|
+
FastPhase3Solver.tt.fill(0);
|
|
103
|
+
FastPhase3Solver.ttGen.fill(0);
|
|
104
|
+
FastPhase3Solver.callSeq = 1;
|
|
105
|
+
FastPhase3Solver.epoch = 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Fresh per-call id for TT-generation tagging (epoch wrap resets it). */
|
|
109
|
+
static nextCallId() {
|
|
110
|
+
const id = FastPhase3Solver.callSeq++;
|
|
111
|
+
if (FastPhase3Solver.callSeq > 0xfffffffe) {
|
|
112
|
+
FastPhase3Solver.ttGen.fill(0);
|
|
113
|
+
FastPhase3Solver.callSeq = 1;
|
|
114
|
+
return 1;
|
|
115
|
+
}
|
|
116
|
+
return id;
|
|
117
|
+
}
|
|
43
118
|
constructor() {
|
|
44
119
|
this.tempep = Array.from({ length: 30 }, () => new Uint8Array(12));
|
|
45
120
|
this.moveLog = new Array(30);
|
|
46
121
|
this.sym = getSymTables();
|
|
47
122
|
}
|
|
123
|
+
nodeCount = 0;
|
|
124
|
+
/** Cumulative nodes across calls (reset per attempt via resetEpochNodes). */
|
|
125
|
+
epochNodes = 0;
|
|
126
|
+
/**
|
|
127
|
+
* Proof bookkeeping for IDA* threshold propagation (reset per exact-length
|
|
128
|
+
* call). When a length-L search exhausts its tree WITHOUT hitting any of
|
|
129
|
+
* these flags, no (center, edge) solution exists at any length below
|
|
130
|
+
* `minExcess`, so the caller may skip straight to it:
|
|
131
|
+
* - `capped`: the node budget aborted the search (bounds unknown).
|
|
132
|
+
* - `limitHit`: goal enumeration hit its cap (tree not exhausted).
|
|
133
|
+
* - `sawGoal`: a goal was reached (even if the validator rejected it —
|
|
134
|
+
* a nearby length may still validate, so only step L+1).
|
|
135
|
+
* - `ttTouched`: a transposition-table hit from ANOTHER exact-length call
|
|
136
|
+
* skipped a subtree (same-call hits replay this call's own exhausted
|
|
137
|
+
* subtree and stay clean; other calls may validate under a different
|
|
138
|
+
* candidate, so their stored proof does not transfer).
|
|
139
|
+
* Bound-based axis skips need no flag: the skipped siblings are
|
|
140
|
+
* same-face turns, so noteExcess records their triangle-inequality bound.
|
|
141
|
+
*/
|
|
142
|
+
capped = false;
|
|
143
|
+
limitHit = false;
|
|
144
|
+
sawGoal = false;
|
|
145
|
+
ttTouched = false;
|
|
146
|
+
minExcess = 0;
|
|
48
147
|
getPrun(distances, idx) {
|
|
49
|
-
|
|
50
|
-
|
|
148
|
+
return distances.length >= 31006080
|
|
149
|
+
? distances[idx]
|
|
150
|
+
: (distances[idx >> 1] >> ((idx & 1) * 4)) & 0x0f;
|
|
51
151
|
}
|
|
52
152
|
/**
|
|
53
|
-
* Recursive IDA* worker on table transitions.
|
|
153
|
+
* Recursive IDA* worker on table transitions with Transposition Table pruning.
|
|
54
154
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
155
|
+
search(eplast, ct, prun, maxl, lm, depth, center3Tables, edge3Distances, maxNodes = 15000, collect, hc, hcCoord = -1, c3PairDist) {
|
|
156
|
+
this.nodeCount++;
|
|
157
|
+
this.epochNodes++;
|
|
158
|
+
if (this.nodeCount > maxNodes) {
|
|
159
|
+
this.capped = true;
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (maxl === 0) {
|
|
163
|
+
if (!collect)
|
|
164
|
+
return true;
|
|
165
|
+
this.sawGoal = true;
|
|
166
|
+
collect.examined++;
|
|
167
|
+
const moves = this.moveLog.slice(0, depth).map((m) => SEARCH_MOVES[m]);
|
|
168
|
+
if (collect.validate(moves))
|
|
169
|
+
return true;
|
|
170
|
+
if (collect.examined >= collect.limit)
|
|
171
|
+
this.limitHit = true;
|
|
172
|
+
return collect.examined >= collect.limit;
|
|
173
|
+
}
|
|
174
|
+
const sym = this.sym;
|
|
175
|
+
const symMvrot = sym.mvrot;
|
|
176
|
+
const symMvroto = sym.mvroto;
|
|
60
177
|
const ep = this.tempep[depth];
|
|
61
178
|
if (lm !== 20) {
|
|
62
179
|
const movoBase = (lm << 3) * 12;
|
|
63
|
-
const movBase = (lm << 3) * 12;
|
|
64
180
|
for (let i = 0; i < 12; i++) {
|
|
65
|
-
ep[i] =
|
|
181
|
+
ep[i] = symMvroto[movoBase + eplast[symMvrot[movoBase + i]]];
|
|
66
182
|
}
|
|
67
183
|
}
|
|
68
184
|
else {
|
|
69
185
|
ep.set(eplast);
|
|
70
186
|
}
|
|
187
|
+
// TT lookup (for depths >= 2 where TT hit prunes multi-move subtrees)
|
|
188
|
+
const keyHigh = ((ct << 16) | (ep[8] | (ep[9] << 4) | (ep[10] << 8) | (ep[11] << 12))) >>> 0;
|
|
189
|
+
const keyLow = (ep[0] | (ep[1] << 4) | (ep[2] << 8) | (ep[3] << 12) |
|
|
190
|
+
(ep[4] << 16) | (ep[5] << 20) | (ep[6] << 24) | (ep[7] << 28)) >>> 0;
|
|
191
|
+
const slot = (((keyLow ^ Math.imul(keyHigh, 0x9e3779b9)) & FastPhase3Solver.TT_MASK) * 3) >>> 0;
|
|
192
|
+
if (maxl >= 2) {
|
|
193
|
+
const storedHigh = FastPhase3Solver.tt[slot];
|
|
194
|
+
const storedLow = FastPhase3Solver.tt[slot + 1];
|
|
195
|
+
const storedInfo = FastPhase3Solver.tt[slot + 2];
|
|
196
|
+
if (storedHigh === keyHigh && storedLow === keyLow) {
|
|
197
|
+
const storedEpoch = storedInfo >>> 16;
|
|
198
|
+
const storedLm = (storedInfo >> 8) & 0xff;
|
|
199
|
+
const storedDepth = storedInfo & 0xff;
|
|
200
|
+
if (storedEpoch === FastPhase3Solver.epoch && storedDepth >= maxl && storedLm === lm) {
|
|
201
|
+
// Same-call hits replay this call's own exhausted subtree (proof
|
|
202
|
+
// stays clean); cross-call hits still prune but dirty the proof.
|
|
203
|
+
// NOTE: ignoring cross-call entries was tried and reverted — they
|
|
204
|
+
// carry most of the pruning power (3.82s vs 2.39s on the corpus).
|
|
205
|
+
if (FastPhase3Solver.ttGen[(slot / 3) | 0] !== this.callId)
|
|
206
|
+
this.ttTouched = true;
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const c3Move = center3Tables.moveTable;
|
|
212
|
+
const c3Prun = center3Tables.pruning;
|
|
213
|
+
const c3Row = ct * CENTER3_MOVES.length;
|
|
214
|
+
const sym2Raw = sym.sym2Raw;
|
|
215
|
+
const sym2Mask = sym.sym2Mask;
|
|
216
|
+
const raw2Sym = sym.raw2Sym;
|
|
217
|
+
const hasHc = hc !== undefined && hcCoord >= 0 && hc.moves.length > 0;
|
|
218
|
+
const hcMoves = hasHc ? hc.moves : null;
|
|
219
|
+
const hcDist = hasHc ? hc.distances : null;
|
|
220
|
+
const hcRow = hasHc ? hcCoord * HC_PDB_MOVES.length : 0;
|
|
221
|
+
// Byte-expanded (tests/generators) vs nibble-packed (loaders) distances.
|
|
222
|
+
const edgeUnpacked = edge3Distances.length >= 31006080;
|
|
71
223
|
for (let m = 0; m < 17; m++) {
|
|
72
224
|
if (ckmv3[lm][m]) {
|
|
73
225
|
m = skipAxis3[m];
|
|
74
226
|
continue;
|
|
75
227
|
}
|
|
76
|
-
const nc =
|
|
228
|
+
const nc = c3Move[c3Row + m];
|
|
77
229
|
if (nc < 0)
|
|
78
230
|
continue;
|
|
79
|
-
const prun1 =
|
|
231
|
+
const prun1 = c3Prun[nc];
|
|
80
232
|
if (prun1 >= maxl) {
|
|
233
|
+
this.noteExcess(depth, prun1, prun1 > maxl && m < 14);
|
|
81
234
|
if (prun1 > maxl && m < 14)
|
|
82
235
|
m = skipAxis3[m];
|
|
83
236
|
continue;
|
|
84
237
|
}
|
|
85
|
-
|
|
86
|
-
|
|
238
|
+
let nhc = -1;
|
|
239
|
+
if (hasHc) {
|
|
240
|
+
nhc = hcMoves[hcRow + m];
|
|
241
|
+
if (nhc >= 0) {
|
|
242
|
+
const prunh = hcDist[nhc];
|
|
243
|
+
if (prunh >= maxl) {
|
|
244
|
+
this.noteExcess(depth, prunh, prunh > maxl && m < 14);
|
|
245
|
+
if (prunh > maxl && m < 14)
|
|
246
|
+
m = skipAxis3[m];
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (c3PairDist && depth === 0) {
|
|
252
|
+
const c3Base = nc * 144;
|
|
253
|
+
const fSlot = F_SLOT_MAP[m];
|
|
254
|
+
const hSlot = H_SLOT_MAP[m];
|
|
255
|
+
let prunPair = 0;
|
|
256
|
+
for (let s = 0; s < 12; s++) {
|
|
257
|
+
const idx = c3Base + fSlot[s] * 12 + hSlot[ep[s]];
|
|
258
|
+
const d = (idx & 1) === 0 ? (c3PairDist[idx >> 1] & 0x0f) : (c3PairDist[idx >> 1] >> 4);
|
|
259
|
+
if (d >= maxl) {
|
|
260
|
+
prunPair = d;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
if (d > prunPair)
|
|
264
|
+
prunPair = d;
|
|
265
|
+
}
|
|
266
|
+
if (prunPair >= maxl) {
|
|
267
|
+
this.noteExcess(depth, prunPair, prunPair > maxl && m < 14);
|
|
268
|
+
if (prunPair > maxl && m < 14)
|
|
269
|
+
m = skipAxis3[m];
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const symIdx = getMvSymFrom(ep, ep, m, sym2Raw, sym2Mask, raw2Sym, symMvrot, symMvroto);
|
|
274
|
+
// Format-aware read: loaders keep the nibble-packed table (15.5MB);
|
|
275
|
+
// tests and generators may pass byte-expanded buffers instead.
|
|
276
|
+
const eIdx = symIdx >> 3;
|
|
277
|
+
const prunx = edgeUnpacked
|
|
278
|
+
? edge3Distances[eIdx]
|
|
279
|
+
: (edge3Distances[eIdx >> 1] >> ((eIdx & 1) * 4)) & 0x0f;
|
|
87
280
|
if (prunx >= maxl) {
|
|
281
|
+
this.noteExcess(depth, prunx, prunx > maxl && m < 14);
|
|
88
282
|
if (prunx > maxl && m < 14)
|
|
89
283
|
m = skipAxis3[m];
|
|
90
284
|
continue;
|
|
91
285
|
}
|
|
92
|
-
|
|
93
|
-
|
|
286
|
+
this.moveLog[depth] = m;
|
|
287
|
+
if (this.search(ep, nc, prunx, maxl - 1, m, depth + 1, center3Tables, edge3Distances, maxNodes, collect, hc, nhc, c3PairDist)) {
|
|
94
288
|
return true;
|
|
95
289
|
}
|
|
96
290
|
}
|
|
291
|
+
// Record failure in TT if node didn't abort due to node cap
|
|
292
|
+
if (this.nodeCount <= maxNodes && maxl >= 2) {
|
|
293
|
+
FastPhase3Solver.tt[slot] = keyHigh;
|
|
294
|
+
FastPhase3Solver.tt[slot + 1] = keyLow;
|
|
295
|
+
FastPhase3Solver.tt[slot + 2] = (FastPhase3Solver.epoch << 16) | (lm << 8) | maxl;
|
|
296
|
+
FastPhase3Solver.ttGen[(slot / 3) | 0] = this.callId;
|
|
297
|
+
}
|
|
97
298
|
return false;
|
|
98
299
|
}
|
|
99
300
|
/**
|
|
100
|
-
*
|
|
301
|
+
* Record an IDA* bound prune: the child at `depth + 1` needs at least
|
|
302
|
+
* `childBound` more moves, so no solution exists through this branch
|
|
303
|
+
* below root threshold `depth + 1 + childBound`. When a bound-based axis
|
|
304
|
+
* skip also fires, the skipped siblings are same-face turns (verified:
|
|
305
|
+
* every non-empty skipAxis3 run under m < 14 is a same-base triple),
|
|
306
|
+
* hence at most 1 legal move apart — their bound is at least
|
|
307
|
+
* `childBound - 1` by the triangle inequality on the exact PDBs, so the
|
|
308
|
+
* recorded excess `depth + childBound` stays a true lower bound.
|
|
101
309
|
*/
|
|
102
|
-
|
|
310
|
+
noteExcess(depth, childBound, skippedSiblings) {
|
|
311
|
+
const excess = skippedSiblings ? depth + childBound : depth + 1 + childBound;
|
|
312
|
+
if (excess < this.minExcess)
|
|
313
|
+
this.minExcess = excess;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Search for a phase-3 solution with exact target length (first found).
|
|
317
|
+
*/
|
|
318
|
+
solveLength(edge, ct3, edist, length3, center3Tables, edge3Distances, maxNodes = 15000, hc, hcCoord = -1, c3PairDist) {
|
|
103
319
|
this.tempep[0].set(edge);
|
|
104
|
-
|
|
320
|
+
this.nodeCount = 0;
|
|
321
|
+
if (this.search(this.tempep[0], ct3, edist, length3, 20, 0, center3Tables, edge3Distances, maxNodes, undefined, hc, hcCoord, c3PairDist)) {
|
|
105
322
|
return this.moveLog.slice(0, length3).map((m) => SEARCH_MOVES[m]);
|
|
106
323
|
}
|
|
107
324
|
return null;
|
|
108
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Search for a phase-3 solution with exact target length, accepting the
|
|
328
|
+
* first goal sequence that passes `validate` (up to `limit` examined,
|
|
329
|
+
* sharing `maxNodes`). With a validator that enforces the downstream
|
|
330
|
+
* requirements (reduction + standard orientation + 3x3 conversion), hard
|
|
331
|
+
* states whose first-found solutions are unusable get more draws from
|
|
332
|
+
* the same budget instead of an immediate miss.
|
|
333
|
+
*/
|
|
334
|
+
solveLengthValid(edge, ct3, edist, length3, center3Tables, edge3Distances, maxNodes = 15000, limit = 16, validate, hc, hcCoord = -1, c3PairDist) {
|
|
335
|
+
return this.solveLengthProven(edge, ct3, edist, length3, center3Tables, edge3Distances, maxNodes, limit, validate, hc, hcCoord, c3PairDist).moves;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Exact-length validated search that also reports what the call proved.
|
|
339
|
+
* `provenThrough` is the greatest length with provably no (center, edge)
|
|
340
|
+
* solution: set only when the tree was exhaustively explored with no goal
|
|
341
|
+
* reached, no node-cap abort, no TT hit, and complete excess info — the
|
|
342
|
+
* caller may then skip every shorter length for this candidate. Otherwise
|
|
343
|
+
* it is `length3 - 1` at most (only the attempted length is settled).
|
|
344
|
+
*/
|
|
345
|
+
solveLengthProven(edge, ct3, edist, length3, center3Tables, edge3Distances, maxNodes = 15000, limit = 16, validate, hc, hcCoord = -1, c3PairDist) {
|
|
346
|
+
if (c3PairDist) {
|
|
347
|
+
const c3Base = ct3 * 144;
|
|
348
|
+
let maxPairDist = 0;
|
|
349
|
+
for (let s = 0; s < 12; s++) {
|
|
350
|
+
const idx = c3Base + s * 12 + edge[s];
|
|
351
|
+
const d = (idx & 1) === 0 ? (c3PairDist[idx >> 1] & 0x0f) : (c3PairDist[idx >> 1] >> 4);
|
|
352
|
+
if (d > maxPairDist)
|
|
353
|
+
maxPairDist = d;
|
|
354
|
+
}
|
|
355
|
+
if (maxPairDist > length3) {
|
|
356
|
+
return { moves: null, provenThrough: maxPairDist - 1, nodesUsed: 0 };
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
this.tempep[0].set(edge);
|
|
360
|
+
this.nodeCount = 0;
|
|
361
|
+
this.capped = false;
|
|
362
|
+
this.limitHit = false;
|
|
363
|
+
this.sawGoal = false;
|
|
364
|
+
this.ttTouched = false;
|
|
365
|
+
this.minExcess = Number.MAX_SAFE_INTEGER;
|
|
366
|
+
this.callId = FastPhase3Solver.nextCallId();
|
|
367
|
+
let accepted = null;
|
|
368
|
+
const collect = {
|
|
369
|
+
limit,
|
|
370
|
+
examined: 0,
|
|
371
|
+
validate: (moves) => {
|
|
372
|
+
if (validate(moves)) {
|
|
373
|
+
accepted = moves;
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
if (!accepted)
|
|
377
|
+
accepted = moves;
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
this.search(this.tempep[0], ct3, edist, length3, 20, 0, center3Tables, edge3Distances, maxNodes, collect, hc, hcCoord, c3PairDist);
|
|
382
|
+
if (accepted)
|
|
383
|
+
return { moves: accepted, provenThrough: length3, nodesUsed: this.nodeCount };
|
|
384
|
+
if (process.env.CUBE4_PROOF_STATS === "1") {
|
|
385
|
+
proofStats.total++;
|
|
386
|
+
if (this.capped)
|
|
387
|
+
proofStats.capped++;
|
|
388
|
+
if (this.limitHit)
|
|
389
|
+
proofStats.limitHit++;
|
|
390
|
+
if (this.sawGoal)
|
|
391
|
+
proofStats.sawGoal++;
|
|
392
|
+
if (this.ttTouched)
|
|
393
|
+
proofStats.ttTouched++;
|
|
394
|
+
}
|
|
395
|
+
if (!this.capped &&
|
|
396
|
+
!this.limitHit &&
|
|
397
|
+
!this.sawGoal &&
|
|
398
|
+
!this.ttTouched &&
|
|
399
|
+
this.minExcess > length3 &&
|
|
400
|
+
this.minExcess !== Number.MAX_SAFE_INTEGER) {
|
|
401
|
+
if (process.env.CUBE4_PROOF_STATS === "1") {
|
|
402
|
+
proofStats.clean++;
|
|
403
|
+
proofStats.jumpSum += this.minExcess - 1 - length3;
|
|
404
|
+
}
|
|
405
|
+
return { moves: null, provenThrough: this.minExcess - 1, nodesUsed: this.nodeCount };
|
|
406
|
+
}
|
|
407
|
+
return { moves: null, provenThrough: length3, nodesUsed: this.nodeCount };
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/** Temporary instrumentation for proof-statistics (CUBE4_PROOF_STATS=1). */
|
|
411
|
+
export const proofStats = {
|
|
412
|
+
total: 0,
|
|
413
|
+
capped: 0,
|
|
414
|
+
limitHit: 0,
|
|
415
|
+
sawGoal: 0,
|
|
416
|
+
ttTouched: 0,
|
|
417
|
+
clean: 0,
|
|
418
|
+
jumpSum: 0
|
|
419
|
+
};
|
|
420
|
+
export function resetProofStats() {
|
|
421
|
+
proofStats.total = 0;
|
|
422
|
+
proofStats.capped = 0;
|
|
423
|
+
proofStats.limitHit = 0;
|
|
424
|
+
proofStats.sawGoal = 0;
|
|
425
|
+
proofStats.ttTouched = 0;
|
|
426
|
+
proofStats.clean = 0;
|
|
427
|
+
proofStats.jumpSum = 0;
|
|
109
428
|
}
|
|
110
429
|
const defaultSolver = new FastPhase3Solver();
|
|
111
430
|
/**
|
|
@@ -7,25 +7,136 @@ import type { Cube4State, Cube4Move } from "../types.js";
|
|
|
7
7
|
import { type Center1Tables } from "./center1.js";
|
|
8
8
|
import { type Center2Tables } from "./center2.js";
|
|
9
9
|
import { type Center3Tables } from "./center3.js";
|
|
10
|
+
import { type HcDenseTables } from "./hc-pdb.js";
|
|
10
11
|
import { type Edge3Tables } from "./edge3.js";
|
|
11
12
|
import type { Cube3State, Cube3Move } from "../../cube3/types.js";
|
|
13
|
+
import type { Cube3Phase1Tables } from "../../cube3/solver/tables.js";
|
|
12
14
|
export interface Cube4SolveTables {
|
|
13
15
|
center1: Center1Tables;
|
|
14
16
|
center2: Center2Tables;
|
|
15
17
|
center3: Center3Tables;
|
|
16
18
|
edge3: Edge3Tables;
|
|
19
|
+
cube3Phase1?: Cube3Phase1Tables;
|
|
20
|
+
/** Half-class exact PDB (optional; tightens the phase-3 root bound and node-level pruning). */
|
|
21
|
+
hc?: HcDenseTables;
|
|
22
|
+
/** Joint Center3 x Single Pair PDB distances (optional). */
|
|
23
|
+
c3PairDist?: Uint8Array;
|
|
17
24
|
}
|
|
18
25
|
export interface Cube4SolveResult {
|
|
19
26
|
/** The complete solve sequence (solves the input state). */
|
|
20
27
|
moves: Cube4Move[];
|
|
21
28
|
/** The scramble (the inverted solution). */
|
|
22
29
|
scramble: Cube4Move[];
|
|
30
|
+
/** Winning reduction breakdown (unsimplified lengths). */
|
|
31
|
+
phases?: {
|
|
32
|
+
length12: number;
|
|
33
|
+
length1: number;
|
|
34
|
+
length2: number;
|
|
35
|
+
length3: number;
|
|
36
|
+
finish: number;
|
|
37
|
+
};
|
|
38
|
+
/** Search work: phase-2 DFS nodes + phase-3 IDA* nodes this attempt. */
|
|
39
|
+
nodes?: {
|
|
40
|
+
p2: number;
|
|
41
|
+
p3: number;
|
|
42
|
+
f3calls: number;
|
|
43
|
+
};
|
|
44
|
+
/** Wall-clock split of this solve (reduction search / finish loop / polish). */
|
|
45
|
+
timings?: {
|
|
46
|
+
reductionMs: number;
|
|
47
|
+
f1Ms: number;
|
|
48
|
+
f2Ms: number;
|
|
49
|
+
f3Ms: number;
|
|
50
|
+
finishMs: number;
|
|
51
|
+
polishMs: number;
|
|
52
|
+
};
|
|
23
53
|
}
|
|
54
|
+
export declare function rotateAlgorithm(alg: readonly Cube4Move[], rotSeq: string[]): Cube4Move[];
|
|
55
|
+
export declare function invertRotationSequence(rotSeq: string[]): string[];
|
|
56
|
+
export declare function applyCubeRotation(state: Cube4State, rotSeq: string[]): Cube4State;
|
|
57
|
+
export declare const P2_CANCEL: readonly (readonly boolean[])[];
|
|
58
|
+
/** Temporary instrumentation for F2 goal statistics (CUBE4_F2_STATS=1). */
|
|
59
|
+
export declare const f2Stats: {
|
|
60
|
+
goals: number;
|
|
61
|
+
transversalPass: number;
|
|
62
|
+
axisRejects: number;
|
|
63
|
+
minTransversalL2: number;
|
|
64
|
+
minChiralL2: number;
|
|
65
|
+
};
|
|
66
|
+
export declare function resetF2Stats(): void;
|
|
67
|
+
/** Trigger rate for the stagnationCut early-stop (checks vs actual cuts). */
|
|
68
|
+
export declare const stagnationStats: {
|
|
69
|
+
checks: number;
|
|
70
|
+
cuts: number;
|
|
71
|
+
};
|
|
72
|
+
export declare function resetStagnationStats(): void;
|
|
24
73
|
/**
|
|
25
74
|
* Solve a 4x4 state with the reduction solver + the cube3 two-phase finish.
|
|
26
75
|
* `solveCube3` is injected (the cube3 solver loads its tables lazily).
|
|
76
|
+
*
|
|
77
|
+
* The search is bounded by deterministic work caps (candidate counts, node
|
|
78
|
+
* budgets, length caps), so `timeoutMs` is only a wall-clock backstop for
|
|
79
|
+
* pathological cases — not a quality filter. Attempt failures mean the
|
|
80
|
+
* state is outside the solver's horizon, never "ran out of time".
|
|
27
81
|
*/
|
|
82
|
+
export interface Cube4SolveOptions {
|
|
83
|
+
/**
|
|
84
|
+
* Accepted for API compatibility but NOT enforced inside the search
|
|
85
|
+
* (deliberately: every loop is work-capped so the same state always
|
|
86
|
+
* takes the same path). Callers enforce their own wall-clock backstop
|
|
87
|
+
* around the call.
|
|
88
|
+
*/
|
|
89
|
+
timeoutMs?: number;
|
|
90
|
+
/**
|
|
91
|
+
* Last-resort effort: widens every work cap (phase-2 depth/nodes,
|
|
92
|
+
* phase-3 budgets/lengths, pool caps). Only the fast path failing
|
|
93
|
+
* should trigger this — easy states never pay it.
|
|
94
|
+
*/
|
|
95
|
+
deep?: boolean;
|
|
96
|
+
/** Phase-4 attempts among valid reductions (default 3, or centersBeam * edgesPerCenter). */
|
|
97
|
+
finishTries?: number;
|
|
98
|
+
/** Number of distinct center candidates from phase 2 to explore in phase 3 (default 3). */
|
|
99
|
+
centersBeam?: number | undefined;
|
|
100
|
+
/** Maximum number of distinct edge pairings to collect per center candidate in phase 3 (default 3). */
|
|
101
|
+
edgesPerCenter?: number | undefined;
|
|
102
|
+
/** Deep multi-candidate polish pass in Phase 3. */
|
|
103
|
+
deepPolish?: boolean | undefined;
|
|
104
|
+
/** Prune searches whose reduction exceeds this bound (branch-and-bound). */
|
|
105
|
+
maxReductionLen?: number | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Phase-2 wide move set: search all 28 center2 moves (adds
|
|
108
|
+
* Dw2/Lw/Lw2/Lw'/Bw2) with the `pruningWide` table instead of the
|
|
109
|
+
* default 23. Requires regenerated center2 tables; default false.
|
|
110
|
+
* (Measured: ~-0.2 moves for ~+15% time; keep opt-in.)
|
|
111
|
+
*/
|
|
112
|
+
center2Wide?: boolean | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* F1 enumeration depth beyond the per-axis optimum (default 3):
|
|
115
|
+
* collects up to `phase1Cap` F1 solutions of length <= minH + this,
|
|
116
|
+
* deliberately supra-optimal, to feed diverse F2/F3 candidates.
|
|
117
|
+
* (Measured: restricting to 0 shows no consistent benefit and
|
|
118
|
+
* interacts badly with center2Wide; keep the default.)
|
|
119
|
+
*/
|
|
120
|
+
phase1ExtraDepths?: number | undefined;
|
|
121
|
+
/** F1 solution collection cap (default 60). */
|
|
122
|
+
phase1Cap?: number | undefined;
|
|
123
|
+
/** Phase-2 prep collection cap (default 100, or 160 in deep mode). */
|
|
124
|
+
prepCap?: number | undefined;
|
|
125
|
+
/** Max candidates to collect per (prep, length) DFS call (default 64, or 96 in deep mode). */
|
|
126
|
+
p1CandCap?: number | undefined;
|
|
127
|
+
/** Early stop when candidate pool has >= CAND_MIN and best value stagnates across 2 lengths. */
|
|
128
|
+
stagnationCut?: boolean | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Full-pipeline restarts over the SAME state (default 1): each restart
|
|
131
|
+
* re-runs phases 1-4 with a reshuffled search order (seeded by the state
|
|
132
|
+
* hash ^ restart index, so results stay deterministic) and the shortest
|
|
133
|
+
* simplified total wins. Same-state diversity preserves the sampled
|
|
134
|
+
* state's distribution — unlike bestOf, which samples new states.
|
|
135
|
+
* `1` keeps the legacy single deterministic pass bit-identical.
|
|
136
|
+
*/
|
|
137
|
+
restarts?: number | undefined;
|
|
138
|
+
}
|
|
28
139
|
export declare function solveCube4State(state: Cube4State, tables: Cube4SolveTables, solveCube3: (state: Cube3State) => Promise<{
|
|
29
140
|
moves: Cube3Move[];
|
|
30
|
-
}
|
|
141
|
+
}>, options?: Cube4SolveOptions): Promise<Cube4SolveResult>;
|
|
31
142
|
//# sourceMappingURL=solve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solve.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/solve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"solve.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/solve.ts"],"names":[],"mappings":"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"}
|