@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.
Files changed (115) hide show
  1. package/README.md +2 -0
  2. package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
  3. package/dist/puzzles/cube2/solver/search.js +3 -3
  4. package/dist/puzzles/cube2/solver/tables.d.ts +6 -0
  5. package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
  6. package/dist/puzzles/cube2/solver/tables.js +16 -2
  7. package/dist/puzzles/cube3/index.d.ts +1 -0
  8. package/dist/puzzles/cube3/index.d.ts.map +1 -1
  9. package/dist/puzzles/cube3/moves.d.ts.map +1 -1
  10. package/dist/puzzles/cube3/moves.js +104 -18
  11. package/dist/puzzles/cube3/scrambler.d.ts +16 -1
  12. package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
  13. package/dist/puzzles/cube3/scrambler.js +1 -1
  14. package/dist/puzzles/cube3/solver/browser-loader.js +6 -2
  15. package/dist/puzzles/cube3/solver/index.d.ts +5 -3
  16. package/dist/puzzles/cube3/solver/index.d.ts.map +1 -1
  17. package/dist/puzzles/cube3/solver/index.js +2 -1
  18. package/dist/puzzles/cube3/solver/node-loader.js +9 -2
  19. package/dist/puzzles/cube3/solver/phase1.d.ts +18 -0
  20. package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
  21. package/dist/puzzles/cube3/solver/phase1.js +132 -14
  22. package/dist/puzzles/cube3/solver/phase2.d.ts +47 -0
  23. package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
  24. package/dist/puzzles/cube3/solver/phase2.js +236 -66
  25. package/dist/puzzles/cube3/solver/search-utils.d.ts +1 -1
  26. package/dist/puzzles/cube3/solver/search-utils.d.ts.map +1 -1
  27. package/dist/puzzles/cube3/solver/symmetry.d.ts +24 -0
  28. package/dist/puzzles/cube3/solver/symmetry.d.ts.map +1 -0
  29. package/dist/puzzles/cube3/solver/symmetry.js +74 -0
  30. package/dist/puzzles/cube3/solver/tables.d.ts +6 -1
  31. package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
  32. package/dist/puzzles/cube3/validation.d.ts.map +1 -1
  33. package/dist/puzzles/cube3/validation.js +15 -7
  34. package/dist/puzzles/cube4/index.d.ts +3 -2
  35. package/dist/puzzles/cube4/index.d.ts.map +1 -1
  36. package/dist/puzzles/cube4/index.js +2 -2
  37. package/dist/puzzles/cube4/moves.d.ts +5 -0
  38. package/dist/puzzles/cube4/moves.d.ts.map +1 -1
  39. package/dist/puzzles/cube4/moves.js +120 -11
  40. package/dist/puzzles/cube4/reduction/browser-loader.d.ts +3 -0
  41. package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
  42. package/dist/puzzles/cube4/reduction/browser-loader.js +34 -3
  43. package/dist/puzzles/cube4/reduction/center2.d.ts +20 -3
  44. package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
  45. package/dist/puzzles/cube4/reduction/center2.js +53 -9
  46. package/dist/puzzles/cube4/reduction/edge3.d.ts +4 -0
  47. package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -1
  48. package/dist/puzzles/cube4/reduction/edge3.js +23 -3
  49. package/dist/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
  50. package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
  51. package/dist/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
  52. package/dist/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
  53. package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
  54. package/dist/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
  55. package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +50 -0
  56. package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -0
  57. package/dist/puzzles/cube4/reduction/hc-pdb.js +202 -0
  58. package/dist/puzzles/cube4/reduction/node-loader.d.ts +5 -0
  59. package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
  60. package/dist/puzzles/cube4/reduction/node-loader.js +48 -8
  61. package/dist/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
  62. package/dist/puzzles/cube4/reduction/phase3-search.d.ts +111 -5
  63. package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
  64. package/dist/puzzles/cube4/reduction/phase3-search.js +341 -22
  65. package/dist/puzzles/cube4/reduction/solve.d.ts +112 -1
  66. package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
  67. package/dist/puzzles/cube4/reduction/solve.js +920 -181
  68. package/dist/puzzles/cube4/scrambler.d.ts +105 -4
  69. package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
  70. package/dist/puzzles/cube4/scrambler.js +216 -166
  71. package/dist/puzzles/cube4/state.d.ts.map +1 -1
  72. package/dist/puzzles/cube4/state.js +4 -1
  73. package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -1
  74. package/dist/puzzles/pyraminx/solver/search.js +3 -6
  75. package/dist/puzzles/pyraminx/solver/tables.d.ts +6 -0
  76. package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -1
  77. package/dist/puzzles/pyraminx/solver/tables.js +17 -0
  78. package/dist/puzzles/skewb/solver/search.js +3 -3
  79. package/dist/puzzles/skewb/solver/tables.d.ts +6 -0
  80. package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
  81. package/dist/puzzles/skewb/solver/tables.js +17 -0
  82. package/dist-cjs/puzzles/cube2/solver/search.js +2 -2
  83. package/dist-cjs/puzzles/cube2/solver/tables.js +17 -3
  84. package/dist-cjs/puzzles/cube3/moves.js +104 -18
  85. package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
  86. package/dist-cjs/puzzles/cube3/solver/browser-loader.js +6 -2
  87. package/dist-cjs/puzzles/cube3/solver/index.js +8 -1
  88. package/dist-cjs/puzzles/cube3/solver/node-loader.js +9 -2
  89. package/dist-cjs/puzzles/cube3/solver/phase1.js +133 -14
  90. package/dist-cjs/puzzles/cube3/solver/phase2.js +233 -63
  91. package/dist-cjs/puzzles/cube3/solver/symmetry.js +80 -0
  92. package/dist-cjs/puzzles/cube3/validation.js +15 -7
  93. package/dist-cjs/puzzles/cube4/index.js +3 -1
  94. package/dist-cjs/puzzles/cube4/moves.js +121 -11
  95. package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +34 -3
  96. package/dist-cjs/puzzles/cube4/reduction/center2.js +54 -9
  97. package/dist-cjs/puzzles/cube4/reduction/edge3.js +24 -3
  98. package/dist-cjs/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
  99. package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
  100. package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
  101. package/dist-cjs/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
  102. package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
  103. package/dist-cjs/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
  104. package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +213 -0
  105. package/dist-cjs/puzzles/cube4/reduction/node-loader.js +48 -8
  106. package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
  107. package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +343 -23
  108. package/dist-cjs/puzzles/cube4/reduction/solve.js +918 -173
  109. package/dist-cjs/puzzles/cube4/scrambler.js +214 -163
  110. package/dist-cjs/puzzles/cube4/state.js +4 -1
  111. package/dist-cjs/puzzles/pyraminx/solver/search.js +2 -5
  112. package/dist-cjs/puzzles/pyraminx/solver/tables.js +18 -1
  113. package/dist-cjs/puzzles/skewb/solver/search.js +2 -2
  114. package/dist-cjs/puzzles/skewb/solver/tables.js +18 -1
  115. package/package.json +14 -5
@@ -0,0 +1,38 @@
1
+ {
2
+ "version": 2,
3
+ "puzzle": "cube4",
4
+ "phase": "hc",
5
+ "moves": [
6
+ "U",
7
+ "U2",
8
+ "U'",
9
+ "R2",
10
+ "F",
11
+ "F2",
12
+ "F'",
13
+ "D",
14
+ "D2",
15
+ "D'",
16
+ "L2",
17
+ "B",
18
+ "B2",
19
+ "B'",
20
+ "Uw2",
21
+ "Rw2",
22
+ "Fw2"
23
+ ],
24
+ "states": 2704156,
25
+ "reachableStates": 58800,
26
+ "reachableDense": 58800,
27
+ "maxDepth": 11,
28
+ "distances": {
29
+ "file": "hc-distances.bin",
30
+ "range": 2704156,
31
+ "checksum": "8720ec4a83eca33c3d56ae0ab8709c0b3d847c14d011b6dcc4413b28bd9dfa12"
32
+ },
33
+ "moveTable": {
34
+ "file": "hc-move.bin",
35
+ "range": 999600,
36
+ "checksum": "6bd1d8f36b77e0863425bced1dfb69df7a13dde4fb18ceeaeba00abf14519922"
37
+ }
38
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Half-class exact PDB (Phase-3 center heuristic, Fase 1 pivot).
3
+ *
4
+ * PIVOT NOTE: the original Fase-1 spec (3 exact face-pair color PDBs,
5
+ * C(24,4)xC(20,4) = 51M states each) is unworkable — verified that outer
6
+ * face turns never move centers across faces (only wide doubles do), so
7
+ * the exact-color orbit under the 17 search moves holds ~70 states and
8
+ * the bound would read "unknown" almost everywhere. This table instead
9
+ * tracks the EXACT arrangement of half-class bits ((color/3)^1: 12 ones,
10
+ * 12 zeros), which moves under every search move:
11
+ *
12
+ * states = C(24,12) = 2,704,156, nibble-packed (~1.35 MB)
13
+ *
14
+ * Center3 (29,400 states) is a quotient of this coordinate (rank-7 pair
15
+ * + rl-index + parity), so this PDB dominates it by construction:
16
+ * bound = max(ct3, edge, hc). BFS from solved with the 17 search moves.
17
+ */
18
+ export declare const HC_PDB_MOVES: readonly string[];
19
+ /** C(24,12) = 2,704,156. */
20
+ export declare const HC_PDB_STATES = 2704156;
21
+ /** C(24,12) rank of a 24-bit mask with popcount 12 (bit i = position i holds 1). */
22
+ export declare function hcRank(mask: number): number;
23
+ /** Inverse of hcRank: mask with popcount 12. */
24
+ export declare function hcUnrank(rank: number): number;
25
+ /** Encode center colors to the half-class coordinate. */
26
+ export declare function encodeHcPdb(centers: Uint8Array): number;
27
+ export declare function getHcPdbMoveMaps(): Int32Array;
28
+ /** Nibble-packed lookup (high nibble = odd index). */
29
+ export declare function hcPdbDistance(packed: Uint8Array, coordinate: number): number;
30
+ /**
31
+ * BFS from the solved half-class mask. Returns nibble-packed distances
32
+ * (0x0f = unreachable). ~2.7M states x 17 moves.
33
+ */
34
+ export declare function generateHcPdb(onProgress?: (done: number, total: number) => void): Uint8Array;
35
+ /** Number of reachable states (BFS orbit size). Fixed by the move set. */
36
+ export declare const HC_REACHABLE = 58800;
37
+ export interface HcDenseTables {
38
+ /** Full coordinate -> dense index, -1 if unreachable. */
39
+ index: Int32Array;
40
+ /** Dense moves: reachableCount x 17, dense indices. */
41
+ moves: Int32Array;
42
+ /** Dense distances (unpacked, 0x0f = unknown). */
43
+ distances: Uint8Array;
44
+ reachableCount: number;
45
+ }
46
+ /** Build the dense index + unpacked distances from nibble-packed BFS output. */
47
+ export declare function buildHcDense(packed: Uint8Array): HcDenseTables;
48
+ /** Dense transition table: for each reachable state and move, dense index (or -1). */
49
+ export declare function generateHcDenseMoves(dense: HcDenseTables): Int32Array;
50
+ //# sourceMappingURL=hc-pdb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hc-pdb.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/hc-pdb.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAA+B,CAAC;AAE1E,4BAA4B;AAC5B,eAAO,MAAM,aAAa,UAAU,CAAC;AAmBrC,oFAAoF;AACpF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU3C;AAED,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc7C;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAMvD;AAoBD,wBAAgB,gBAAgB,IAAI,UAAU,CAG7C;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACjD,UAAU,CA+CZ;AAED,0EAA0E;AAC1E,eAAO,MAAM,YAAY,QAAQ,CAAC;AAElC,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,KAAK,EAAE,UAAU,CAAC;IAClB,uDAAuD;IACvD,KAAK,EAAE,UAAU,CAAC;IAClB,kDAAkD;IAClD,SAAS,EAAE,UAAU,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAY9D;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAiBrE"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Half-class exact PDB (Phase-3 center heuristic, Fase 1 pivot).
3
+ *
4
+ * PIVOT NOTE: the original Fase-1 spec (3 exact face-pair color PDBs,
5
+ * C(24,4)xC(20,4) = 51M states each) is unworkable — verified that outer
6
+ * face turns never move centers across faces (only wide doubles do), so
7
+ * the exact-color orbit under the 17 search moves holds ~70 states and
8
+ * the bound would read "unknown" almost everywhere. This table instead
9
+ * tracks the EXACT arrangement of half-class bits ((color/3)^1: 12 ones,
10
+ * 12 zeros), which moves under every search move:
11
+ *
12
+ * states = C(24,12) = 2,704,156, nibble-packed (~1.35 MB)
13
+ *
14
+ * Center3 (29,400 states) is a quotient of this coordinate (rank-7 pair
15
+ * + rl-index + parity), so this PDB dominates it by construction:
16
+ * bound = max(ct3, edge, hc). BFS from solved with the 17 search moves.
17
+ */
18
+ import { CENTER3_MOVES } from "./center3.js";
19
+ import { FACE_MOVE_EFFECTS, parseMove } from "../moves.js";
20
+ export const HC_PDB_MOVES = CENTER3_MOVES.slice(0, 17);
21
+ /** C(24,12) = 2,704,156. */
22
+ export const HC_PDB_STATES = 2704156;
23
+ const CNK = (() => {
24
+ const table = [];
25
+ for (let n = 0; n <= 24; n++) {
26
+ table[n] = [];
27
+ for (let k = 0; k <= 12; k++) {
28
+ if (k === 0 || k === n)
29
+ table[n][k] = 1;
30
+ else if (k > n)
31
+ table[n][k] = 0;
32
+ else
33
+ table[n][k] = table[n - 1][k - 1] + table[n - 1][k];
34
+ }
35
+ }
36
+ return table;
37
+ })();
38
+ function halfClass(color) {
39
+ return (Math.floor(color / 3) ^ 1) & 1;
40
+ }
41
+ /** C(24,12) rank of a 24-bit mask with popcount 12 (bit i = position i holds 1). */
42
+ export function hcRank(mask) {
43
+ let rank = 0;
44
+ let k = 1;
45
+ for (let i = 0; i < 24; i++) {
46
+ if (mask & (1 << i)) {
47
+ rank += CNK[i][k];
48
+ k++;
49
+ }
50
+ }
51
+ return rank;
52
+ }
53
+ /** Inverse of hcRank: mask with popcount 12. */
54
+ export function hcUnrank(rank) {
55
+ let mask = 0;
56
+ let r = rank;
57
+ for (let k = 12; k >= 1; k--) {
58
+ for (let v = 23; v >= 0; v--) {
59
+ const c = CNK[v][k];
60
+ if (c <= r) {
61
+ mask |= 1 << v;
62
+ r -= c;
63
+ break;
64
+ }
65
+ }
66
+ }
67
+ return mask;
68
+ }
69
+ /** Encode center colors to the half-class coordinate. */
70
+ export function encodeHcPdb(centers) {
71
+ let mask = 0;
72
+ for (let i = 0; i < 24; i++) {
73
+ if (halfClass(centers[i]) === 1)
74
+ mask |= 1 << i;
75
+ }
76
+ return hcRank(mask);
77
+ }
78
+ /** Position permutation maps for the 17 moves (next[i] = prev[map[i]]). */
79
+ function buildMovePositionMaps() {
80
+ const maps = new Int32Array(HC_PDB_MOVES.length * 24);
81
+ for (let m = 0; m < HC_PDB_MOVES.length; m++) {
82
+ const { face, turns } = parseMove(HC_PDB_MOVES[m]);
83
+ const effect = FACE_MOVE_EFFECTS[face];
84
+ let pos = Array.from({ length: 24 }, (_, i) => i);
85
+ for (let t = 0; t < turns; t++) {
86
+ const next = new Array(24);
87
+ for (let i = 0; i < 24; i++)
88
+ next[i] = pos[effect.ctperm[i]];
89
+ pos = next;
90
+ }
91
+ for (let i = 0; i < 24; i++)
92
+ maps[m * 24 + i] = pos[i];
93
+ }
94
+ return maps;
95
+ }
96
+ let cachedMoveMaps = null;
97
+ export function getHcPdbMoveMaps() {
98
+ if (!cachedMoveMaps)
99
+ cachedMoveMaps = buildMovePositionMaps();
100
+ return cachedMoveMaps;
101
+ }
102
+ /** Nibble-packed lookup (high nibble = odd index). */
103
+ export function hcPdbDistance(packed, coordinate) {
104
+ const byte = packed[coordinate >> 1];
105
+ return (coordinate & 1) === 0 ? byte & 0x0f : byte >> 4;
106
+ }
107
+ /**
108
+ * BFS from the solved half-class mask. Returns nibble-packed distances
109
+ * (0x0f = unreachable). ~2.7M states x 17 moves.
110
+ */
111
+ export function generateHcPdb(onProgress) {
112
+ const maps = getHcPdbMoveMaps();
113
+ const packed = new Uint8Array((HC_PDB_STATES + 1) >> 1).fill(0xff);
114
+ const get = (c) => {
115
+ const b = packed[c >> 1];
116
+ return (c & 1) === 0 ? b & 0x0f : b >> 4;
117
+ };
118
+ const set = (c, d) => {
119
+ const i = c >> 1;
120
+ if ((c & 1) === 0)
121
+ packed[i] = (packed[i] & 0xf0) | (d & 0x0f);
122
+ else
123
+ packed[i] = (packed[i] & 0x0f) | ((d & 0x0f) << 4);
124
+ };
125
+ // Solved mask: U/R/F faces hold half-class 1.
126
+ let solvedMask = 0;
127
+ for (const i of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
128
+ solvedMask |= 1 << i;
129
+ const solved = hcRank(solvedMask);
130
+ if (solved !== 0)
131
+ throw new Error(`solved rank != 0 (${solved})`);
132
+ const queue = new Int32Array(HC_PDB_STATES);
133
+ let head = 0;
134
+ let tail = 0;
135
+ set(0, 0);
136
+ queue[tail++] = 0;
137
+ while (head < tail) {
138
+ const coord = queue[head++];
139
+ const d = get(coord);
140
+ const nd = d + 1;
141
+ if (nd > 14)
142
+ continue; // nibble range; 0x0f stays "unknown" (admissible)
143
+ const mask = hcUnrank(coord);
144
+ for (let m = 0; m < HC_PDB_MOVES.length; m++) {
145
+ const base = m * 24;
146
+ let nmask = 0;
147
+ for (let i = 0; i < 24; i++) {
148
+ if (mask & (1 << maps[base + i]))
149
+ nmask |= 1 << i;
150
+ }
151
+ const next = hcRank(nmask);
152
+ if (get(next) === 0x0f) {
153
+ set(next, nd);
154
+ queue[tail++] = next;
155
+ }
156
+ }
157
+ if (onProgress && (head & 0x7ffff) === 0)
158
+ onProgress(head, HC_PDB_STATES);
159
+ }
160
+ if (onProgress)
161
+ onProgress(tail, HC_PDB_STATES);
162
+ return packed;
163
+ }
164
+ /** Number of reachable states (BFS orbit size). Fixed by the move set. */
165
+ export const HC_REACHABLE = 58800;
166
+ /** Build the dense index + unpacked distances from nibble-packed BFS output. */
167
+ export function buildHcDense(packed) {
168
+ const index = new Int32Array(HC_PDB_STATES).fill(-1);
169
+ let count = 0;
170
+ for (let c = 0; c < HC_PDB_STATES; c++) {
171
+ if (hcPdbDistance(packed, c) !== 0x0f)
172
+ index[c] = count++;
173
+ }
174
+ const distances = new Uint8Array(count).fill(0x0f);
175
+ for (let c = 0; c < HC_PDB_STATES; c++) {
176
+ const di = index[c];
177
+ if (di >= 0)
178
+ distances[di] = hcPdbDistance(packed, c);
179
+ }
180
+ return { index, moves: new Int32Array(0), distances, reachableCount: count };
181
+ }
182
+ /** Dense transition table: for each reachable state and move, dense index (or -1). */
183
+ export function generateHcDenseMoves(dense) {
184
+ const maps = getHcPdbMoveMaps();
185
+ const moves = new Int32Array(dense.reachableCount * HC_PDB_MOVES.length).fill(-1);
186
+ for (let c = 0; c < HC_PDB_STATES; c++) {
187
+ const di = dense.index[c];
188
+ if (di < 0)
189
+ continue;
190
+ const mask = hcUnrank(c);
191
+ for (let m = 0; m < HC_PDB_MOVES.length; m++) {
192
+ const base = m * 24;
193
+ let nmask = 0;
194
+ for (let i = 0; i < 24; i++) {
195
+ if (mask & (1 << maps[base + i]))
196
+ nmask |= 1 << i;
197
+ }
198
+ moves[di * HC_PDB_MOVES.length + m] = dense.index[hcRank(nmask)];
199
+ }
200
+ }
201
+ return moves;
202
+ }
@@ -6,11 +6,16 @@ import type { Center1Tables } from "./center1.js";
6
6
  import type { Center2Tables } from "./center2.js";
7
7
  import type { Center3Tables } from "./center3.js";
8
8
  import type { Edge3Tables } from "./edge3.js";
9
+ import { type HcDenseTables } from "./hc-pdb.js";
9
10
  export interface Cube4ReductionTables {
10
11
  center1: Center1Tables;
11
12
  center2: Center2Tables;
12
13
  center3: Center3Tables;
13
14
  edge3: Edge3Tables;
15
+ /** Half-class exact PDB distances (optional; absent = bound disabled). */
16
+ hc?: HcDenseTables;
17
+ /** Joint Center3 x Single Pair PDB distances (optional). */
18
+ c3PairDist?: Uint8Array;
14
19
  }
15
20
  /** Load all cube4 reduction tables (throws if the generated assets are missing). */
16
21
  export declare function loadCube4ReductionTables(): Cube4ReductionTables;
@@ -1 +1 @@
1
- {"version":3,"file":"node-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/node-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,WAAW,CAAC;CACpB;AAuGD,oFAAoF;AACpF,wBAAgB,wBAAwB,IAAI,oBAAoB,CAW/D"}
1
+ {"version":3,"file":"node-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/node-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,WAAW,CAAC;IACnB,0EAA0E;IAC1E,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AA2ID,oFAAoF;AACpF,wBAAgB,wBAAwB,IAAI,oBAAoB,CAgB/D"}
@@ -7,6 +7,7 @@ import { createRequire } from "node:module";
7
7
  import path from "node:path";
8
8
  import { createHash } from "node:crypto";
9
9
  import { edge3DistanceLookup } from "./edge3.js";
10
+ import { buildHcDense } from "./hc-pdb.js";
10
11
  const GENERATED_DIRECTORY = "puzzles/cube4/reduction/generated";
11
12
  function resolveGeneratedAssetDirectory() {
12
13
  const envDirectory = process.env.CUBINGCENTER_SCRAMBLER_TABLES_DIR;
@@ -59,17 +60,27 @@ function loadCenter1(assetDirectory) {
59
60
  }
60
61
  function loadCenter2(assetDirectory) {
61
62
  const manifest = JSON.parse(readFileSync(path.join(assetDirectory, "center2-manifest.json"), "utf8"));
62
- const pruningBuffer = readChecked(path.join(assetDirectory, manifest.pruningTable.file), manifest.pruningTable.checksum);
63
- const pruning = new Uint8Array(450450);
64
- for (let i = 0; i < 450450; i++) {
65
- const byte = pruningBuffer[i >> 1];
66
- pruning[i] = (i & 1) === 0 ? byte & 0x0f : byte >> 4;
63
+ function unpackPruning(buffer) {
64
+ const pruning = new Uint8Array(450450);
65
+ for (let i = 0; i < 450450; i++) {
66
+ const byte = buffer[i >> 1];
67
+ pruning[i] = (i & 1) === 0 ? byte & 0x0f : byte >> 4;
68
+ }
69
+ return pruning;
67
70
  }
68
- return {
71
+ const pruningBuffer = readChecked(path.join(assetDirectory, manifest.pruningTable.file), manifest.pruningTable.checksum);
72
+ const tables = {
69
73
  ctMove: readInt32(readChecked(path.join(assetDirectory, manifest.ctMove.file), manifest.ctMove.checksum)),
70
74
  rlMove: readInt32(readChecked(path.join(assetDirectory, manifest.rlMove.file), manifest.rlMove.checksum)),
71
- pruning
75
+ pruning: unpackPruning(pruningBuffer)
72
76
  };
77
+ // Tolerates older assets without the wide table (wide searches throw
78
+ // a clear error only when actually requested).
79
+ if (manifest.pruningWideTable) {
80
+ const wideBuffer = readChecked(path.join(assetDirectory, manifest.pruningWideTable.file), manifest.pruningWideTable.checksum);
81
+ tables.pruningWide = unpackPruning(wideBuffer);
82
+ }
83
+ return tables;
73
84
  }
74
85
  function loadCenter3(assetDirectory) {
75
86
  const manifest = JSON.parse(readFileSync(path.join(assetDirectory, "center3-manifest.json"), "utf8"));
@@ -80,19 +91,48 @@ function loadCenter3(assetDirectory) {
80
91
  }
81
92
  function loadEdge3(assetDirectory) {
82
93
  const manifest = JSON.parse(readFileSync(path.join(assetDirectory, "edge3-manifest.json"), "utf8"));
94
+ // Keep the nibble-packed distances as-is (15.5MB instead of 31MB): every
95
+ // reader (phase3 getPrun, solve.ts, edge3DistanceLookup) handles both
96
+ // formats, and the smaller working set halves edge-table DRAM traffic.
83
97
  const distances = new Uint8Array(readChecked(path.join(assetDirectory, manifest.distances.file), manifest.distances.checksum));
84
98
  return { distances, distanceOfEdge: edge3DistanceLookup(distances) };
85
99
  }
100
+ function loadHc(assetDirectory) {
101
+ const manifestPath = path.join(assetDirectory, "hc-manifest.json");
102
+ if (!existsSync(manifestPath))
103
+ return undefined;
104
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
105
+ const packed = new Uint8Array(readChecked(path.join(assetDirectory, manifest.distances.file), manifest.distances.checksum));
106
+ const dense = buildHcDense(packed);
107
+ if (manifest.moveTable) {
108
+ const moveBuffer = readChecked(path.join(assetDirectory, manifest.moveTable.file), manifest.moveTable.checksum);
109
+ dense.moves = new Int32Array(moveBuffer.buffer.slice(moveBuffer.byteOffset, moveBuffer.byteOffset + moveBuffer.byteLength));
110
+ }
111
+ return dense;
112
+ }
113
+ function loadC3Pair(assetDirectory) {
114
+ const filePath = path.join(assetDirectory, "c3_pair_dist.bin");
115
+ if (!existsSync(filePath))
116
+ return undefined;
117
+ return new Uint8Array(readFileSync(filePath));
118
+ }
86
119
  /** Load all cube4 reduction tables (throws if the generated assets are missing). */
87
120
  export function loadCube4ReductionTables() {
88
121
  const assetDirectory = resolveGeneratedAssetDirectory();
89
122
  if (!existsSync(path.join(assetDirectory, "center1-manifest.json"))) {
90
123
  throw new Error("Cube4 reduction tables not generated — run pnpm cube4:center1:tables etc.");
91
124
  }
92
- return {
125
+ const tables = {
93
126
  center1: loadCenter1(assetDirectory),
94
127
  center2: loadCenter2(assetDirectory),
95
128
  center3: loadCenter3(assetDirectory),
96
129
  edge3: loadEdge3(assetDirectory)
97
130
  };
131
+ const hc = loadHc(assetDirectory);
132
+ if (hc)
133
+ tables.hc = hc;
134
+ const c3Pair = loadC3Pair(assetDirectory);
135
+ if (c3Pair)
136
+ tables.c3PairDist = c3Pair;
137
+ return tables;
98
138
  }
@@ -103,12 +103,12 @@ export function applyPairingMoveToArray(arr24, move) {
103
103
  * and preserved by the phase-3 move set (verified).
104
104
  */
105
105
  export function hasPairingTransversal(wp) {
106
- const seen = new Uint8Array(12);
107
- for (const s of PAIRING_SECOND_HALVES) {
108
- const pair = wp[s] >> 1;
109
- if (seen[pair] !== 0)
106
+ let mask = 0;
107
+ for (let i = 0; i < 12; i++) {
108
+ const bit = 1 << (wp[PAIRING_SECOND_HALVES[i]] >> 1);
109
+ if ((mask & bit) !== 0)
110
110
  return false;
111
- seen[pair] = 1;
111
+ mask |= bit;
112
112
  }
113
113
  return true;
114
114
  }
@@ -8,6 +8,7 @@ import type { Cube4Move } from "../types.js";
8
8
  import { type Center3Tables } from "./center3.js";
9
9
  import { type Edge3Tables } from "./edge3.js";
10
10
  import type { Phase3Start } from "./phase3.js";
11
+ import { type HcDenseTables } from "./hc-pdb.js";
11
12
  /** The 17 exploration moves (the reference's m < 17 bound). */
12
13
  export declare const SEARCH_MOVES: readonly Cube4Move[];
13
14
  export declare const ckmv3: boolean[][];
@@ -18,23 +19,128 @@ export interface Phase3Result {
18
19
  edge: Uint8Array;
19
20
  }
20
21
  /**
21
- * Fast table-driven Phase 3 IDA* solver class.
22
+ * Goal enumeration control for the phase-3 search. The classic search
23
+ * returns the FIRST goal-reaching sequence, which for some states is
24
+ * systematically unusable downstream (e.g. uniform-but-nonstandard
25
+ * centers). With a validator, the search keeps enumerating goal sequences
26
+ * — within the same node budget — until one passes or `limit` goals have
27
+ * been examined.
22
28
  */
29
+ export interface Phase3SolutionValidator {
30
+ /** Max goal states to examine per call (bounds the extra cost). */
31
+ limit: number;
32
+ /** Goals examined so far (reset per call). */
33
+ examined: number;
34
+ /**
35
+ * Inspect a goal-reaching move sequence. Return true to accept it (stops
36
+ * the whole search); false keeps searching until `limit` goals examined.
37
+ */
38
+ validate: (moves: Cube4Move[]) => boolean;
39
+ }
23
40
  export declare class FastPhase3Solver {
24
41
  private readonly tempep;
25
42
  private readonly moveLog;
26
43
  private readonly sym;
44
+ /** Transposition Table size: 2^21 = 2,097,152 entries (24 MB in RAM).
45
+ * NOTE: doubling to 4M was tried and reverted (-0.07% nodes on the
46
+ * corpus — the 2M working set already captures the hit locality). */
47
+ private static readonly TT_SIZE;
48
+ private static readonly TT_MASK;
49
+ private static readonly tt;
50
+ private static epoch;
51
+ /**
52
+ * Per-slot exact-length-call tag (8 MB transient). TT pruning stays
53
+ * epoch-scoped (unchanged traversal), but threshold proofs only trust
54
+ * same-call hits: a hit from another call may have validated under a
55
+ * different candidate, so it still prunes yet marks the proof dirty.
56
+ */
57
+ private static readonly ttGen;
58
+ private static callSeq;
59
+ private callId;
60
+ /** Reset the per-attempt cumulative node counter. */
61
+ resetEpochNodes(): void;
62
+ static nextEpoch(): void;
63
+ /** Fresh per-call id for TT-generation tagging (epoch wrap resets it). */
64
+ private static nextCallId;
27
65
  constructor();
66
+ private nodeCount;
67
+ /** Cumulative nodes across calls (reset per attempt via resetEpochNodes). */
68
+ epochNodes: number;
69
+ /**
70
+ * Proof bookkeeping for IDA* threshold propagation (reset per exact-length
71
+ * call). When a length-L search exhausts its tree WITHOUT hitting any of
72
+ * these flags, no (center, edge) solution exists at any length below
73
+ * `minExcess`, so the caller may skip straight to it:
74
+ * - `capped`: the node budget aborted the search (bounds unknown).
75
+ * - `limitHit`: goal enumeration hit its cap (tree not exhausted).
76
+ * - `sawGoal`: a goal was reached (even if the validator rejected it —
77
+ * a nearby length may still validate, so only step L+1).
78
+ * - `ttTouched`: a transposition-table hit from ANOTHER exact-length call
79
+ * skipped a subtree (same-call hits replay this call's own exhausted
80
+ * subtree and stay clean; other calls may validate under a different
81
+ * candidate, so their stored proof does not transfer).
82
+ * Bound-based axis skips need no flag: the skipped siblings are
83
+ * same-face turns, so noteExcess records their triangle-inequality bound.
84
+ */
85
+ private capped;
86
+ private limitHit;
87
+ private sawGoal;
88
+ private ttTouched;
89
+ private minExcess;
28
90
  private getPrun;
29
91
  /**
30
- * Recursive IDA* worker on table transitions.
92
+ * Recursive IDA* worker on table transitions with Transposition Table pruning.
93
+ */
94
+ search(eplast: Uint8Array, ct: number, prun: number, maxl: number, lm: number, depth: number, center3Tables: Center3Tables, edge3Distances: Uint8Array, maxNodes?: number, collect?: Phase3SolutionValidator, hc?: HcDenseTables, hcCoord?: number, c3PairDist?: Uint8Array): boolean;
95
+ /**
96
+ * Record an IDA* bound prune: the child at `depth + 1` needs at least
97
+ * `childBound` more moves, so no solution exists through this branch
98
+ * below root threshold `depth + 1 + childBound`. When a bound-based axis
99
+ * skip also fires, the skipped siblings are same-face turns (verified:
100
+ * every non-empty skipAxis3 run under m < 14 is a same-base triple),
101
+ * hence at most 1 legal move apart — their bound is at least
102
+ * `childBound - 1` by the triangle inequality on the exact PDBs, so the
103
+ * recorded excess `depth + childBound` stays a true lower bound.
104
+ */
105
+ private noteExcess;
106
+ /**
107
+ * Search for a phase-3 solution with exact target length (first found).
108
+ */
109
+ solveLength(edge: Uint8Array, ct3: number, edist: number, length3: number, center3Tables: Center3Tables, edge3Distances: Uint8Array, maxNodes?: number, hc?: HcDenseTables, hcCoord?: number, c3PairDist?: Uint8Array): Cube4Move[] | null;
110
+ /**
111
+ * Search for a phase-3 solution with exact target length, accepting the
112
+ * first goal sequence that passes `validate` (up to `limit` examined,
113
+ * sharing `maxNodes`). With a validator that enforces the downstream
114
+ * requirements (reduction + standard orientation + 3x3 conversion), hard
115
+ * states whose first-found solutions are unusable get more draws from
116
+ * the same budget instead of an immediate miss.
31
117
  */
32
- search(eplast: Uint8Array, ct: number, prun: number, maxl: number, lm: number, depth: number, center3Tables: Center3Tables, edge3Distances: Uint8Array): Promise<boolean>;
118
+ solveLengthValid(edge: Uint8Array, ct3: number, edist: number, length3: number, center3Tables: Center3Tables, edge3Distances: Uint8Array, maxNodes: number | undefined, limit: number | undefined, validate: (moves: Cube4Move[]) => boolean, hc?: HcDenseTables, hcCoord?: number, c3PairDist?: Uint8Array): Cube4Move[] | null;
33
119
  /**
34
- * Search for a phase-3 solution with exact target length.
120
+ * Exact-length validated search that also reports what the call proved.
121
+ * `provenThrough` is the greatest length with provably no (center, edge)
122
+ * solution: set only when the tree was exhaustively explored with no goal
123
+ * reached, no node-cap abort, no TT hit, and complete excess info — the
124
+ * caller may then skip every shorter length for this candidate. Otherwise
125
+ * it is `length3 - 1` at most (only the attempted length is settled).
35
126
  */
36
- solveLength(edge: Uint8Array, ct3: number, edist: number, length3: number, center3Tables: Center3Tables, edge3Distances: Uint8Array): Promise<Cube4Move[] | null>;
127
+ solveLengthProven(edge: Uint8Array, ct3: number, edist: number, length3: number, center3Tables: Center3Tables, edge3Distances: Uint8Array, maxNodes: number | undefined, limit: number | undefined, validate: (moves: Cube4Move[]) => boolean, hc?: HcDenseTables, hcCoord?: number, c3PairDist?: Uint8Array): {
128
+ moves: Cube4Move[] | null;
129
+ provenThrough: number;
130
+ nodesUsed: number;
131
+ };
37
132
  }
133
+ /** Temporary instrumentation for proof-statistics (CUBE4_PROOF_STATS=1). */
134
+ export declare const proofStats: {
135
+ total: number;
136
+ capped: number;
137
+ limitHit: number;
138
+ sawGoal: number;
139
+ ttTouched: number;
140
+ clean: number;
141
+ jumpSum: number;
142
+ };
143
+ export declare function resetProofStats(): void;
38
144
  /**
39
145
  * Solve Phase 3 with iterative deepening on a single Phase3Start.
40
146
  */
@@ -1 +1 @@
1
- {"version":3,"file":"phase3-search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/phase3-search.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,+DAA+D;AAC/D,eAAO,MAAM,YAAY,EAAE,SAAS,SAAS,EAA+B,CAAC;AAa7E,eAAO,MAAM,KAAK,EAAE,OAAO,EAAE,EAAgE,CAAC;AAO9F,eAAO,MAAM,SAAS,EAAE,MAAM,EAA2B,CAAC;AAU1D,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;;IAQhC,OAAO,CAAC,OAAO;IAKf;;OAEG;IACU,MAAM,CACjB,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,UAAU,GACzB,OAAO,CAAC,OAAO,CAAC;IA8DnB;;OAEG;IACU,WAAW,CACtB,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,UAAU,GACzB,OAAO,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC;CAkB/B;AAID;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,WAAW,EACxB,SAAS,SAAK,GACb,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmC9B"}
1
+ {"version":3,"file":"phase3-search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/phase3-search.ts"],"names":[],"mappings":"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"}