@cubingcenter/scrambler 0.5.3 → 0.6.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 (244) hide show
  1. package/README.md +24 -9
  2. package/dist/cli/index.js +0 -0
  3. package/dist/core/api.d.ts.map +1 -1
  4. package/dist/core/api.js +11 -1
  5. package/dist/core/types.d.ts +1 -1
  6. package/dist/core/types.d.ts.map +1 -1
  7. package/dist/puzzles/cube4/index.d.ts +4 -2
  8. package/dist/puzzles/cube4/index.d.ts.map +1 -1
  9. package/dist/puzzles/cube4/index.js +3 -1
  10. package/dist/puzzles/cube4/random-state.d.ts +16 -0
  11. package/dist/puzzles/cube4/random-state.d.ts.map +1 -0
  12. package/dist/puzzles/cube4/random-state.js +76 -0
  13. package/dist/puzzles/cube4/reduction/browser-loader.d.ts +18 -0
  14. package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -0
  15. package/dist/puzzles/cube4/reduction/browser-loader.js +95 -0
  16. package/dist/puzzles/cube4/reduction/center1.d.ts +65 -0
  17. package/dist/puzzles/cube4/reduction/center1.d.ts.map +1 -0
  18. package/dist/puzzles/cube4/reduction/center1.js +245 -0
  19. package/dist/puzzles/cube4/reduction/center2.d.ts +91 -0
  20. package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -0
  21. package/dist/puzzles/cube4/reduction/center2.js +449 -0
  22. package/dist/puzzles/cube4/reduction/center3.d.ts +47 -0
  23. package/dist/puzzles/cube4/reduction/center3.d.ts.map +1 -0
  24. package/dist/puzzles/cube4/reduction/center3.js +278 -0
  25. package/dist/puzzles/cube4/reduction/edge3.d.ts +100 -0
  26. package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -0
  27. package/dist/puzzles/cube4/reduction/edge3.js +511 -0
  28. package/dist/puzzles/cube4/reduction/generated/center1-distance.bin +1 -0
  29. package/dist/puzzles/cube4/reduction/generated/center1-manifest.json +46 -0
  30. package/dist/puzzles/cube4/reduction/generated/center1-move-maps.bin +0 -0
  31. package/dist/puzzles/cube4/reduction/generated/center2-ct-move.bin +0 -0
  32. package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +87 -0
  33. package/dist/puzzles/cube4/reduction/generated/center2-pruning.bin +1 -0
  34. package/dist/puzzles/cube4/reduction/generated/center2-rl-move.bin +0 -0
  35. package/dist/puzzles/cube4/reduction/generated/center3-manifest.json +40 -0
  36. package/dist/puzzles/cube4/reduction/generated/center3-move.bin +0 -0
  37. package/dist/puzzles/cube4/reduction/generated/center3-pruning.bin +0 -0
  38. package/dist/puzzles/cube4/reduction/generated/edge3-distances.bin +1 -0
  39. package/dist/puzzles/cube4/reduction/generated/edge3-manifest.json +12 -0
  40. package/dist/puzzles/cube4/reduction/geometry.d.ts +33 -0
  41. package/dist/puzzles/cube4/reduction/geometry.d.ts.map +1 -0
  42. package/dist/puzzles/cube4/reduction/geometry.js +302 -0
  43. package/dist/puzzles/cube4/reduction/node-loader.d.ts +17 -0
  44. package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -0
  45. package/dist/puzzles/cube4/reduction/node-loader.js +98 -0
  46. package/dist/puzzles/cube4/reduction/pairing-coordinate.d.ts +130 -0
  47. package/dist/puzzles/cube4/reduction/pairing-coordinate.d.ts.map +1 -0
  48. package/dist/puzzles/cube4/reduction/pairing-coordinate.js +281 -0
  49. package/dist/puzzles/cube4/reduction/phase3-search.d.ts +42 -0
  50. package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -0
  51. package/dist/puzzles/cube4/reduction/phase3-search.js +133 -0
  52. package/dist/puzzles/cube4/reduction/phase3.d.ts +34 -0
  53. package/dist/puzzles/cube4/reduction/phase3.d.ts.map +1 -0
  54. package/dist/puzzles/cube4/reduction/phase3.js +83 -0
  55. package/dist/puzzles/cube4/reduction/phase4.d.ts +35 -0
  56. package/dist/puzzles/cube4/reduction/phase4.d.ts.map +1 -0
  57. package/dist/puzzles/cube4/reduction/phase4.js +82 -0
  58. package/dist/puzzles/cube4/reduction/solve.d.ts +31 -0
  59. package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -0
  60. package/dist/puzzles/cube4/reduction/solve.js +311 -0
  61. package/dist/puzzles/cube4/scrambler.d.ts +9 -1
  62. package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
  63. package/dist/puzzles/cube4/scrambler.js +123 -81
  64. package/dist/puzzles/cube4/types.d.ts +6 -0
  65. package/dist/puzzles/cube4/types.d.ts.map +1 -1
  66. package/dist/puzzles/cube4/validation.d.ts +6 -0
  67. package/dist/puzzles/cube4/validation.d.ts.map +1 -0
  68. package/dist/puzzles/cube4/validation.js +91 -0
  69. package/dist/puzzles/fto/coordinates.d.ts +53 -0
  70. package/dist/puzzles/fto/coordinates.d.ts.map +1 -0
  71. package/dist/puzzles/fto/coordinates.js +228 -0
  72. package/dist/puzzles/fto/facelets.d.ts +6 -0
  73. package/dist/puzzles/fto/facelets.d.ts.map +1 -0
  74. package/dist/puzzles/fto/facelets.js +99 -0
  75. package/dist/puzzles/fto/index.d.ts +12 -0
  76. package/dist/puzzles/fto/index.d.ts.map +1 -0
  77. package/dist/puzzles/fto/index.js +13 -0
  78. package/dist/puzzles/fto/moves.d.ts +12 -0
  79. package/dist/puzzles/fto/moves.d.ts.map +1 -0
  80. package/dist/puzzles/fto/moves.js +115 -0
  81. package/dist/puzzles/fto/random-state.d.ts +17 -0
  82. package/dist/puzzles/fto/random-state.d.ts.map +1 -0
  83. package/dist/puzzles/fto/random-state.js +40 -0
  84. package/dist/puzzles/fto/scrambler.d.ts +6 -0
  85. package/dist/puzzles/fto/scrambler.d.ts.map +1 -0
  86. package/dist/puzzles/fto/scrambler.js +49 -0
  87. package/dist/puzzles/fto/solver/engine.d.ts +18 -0
  88. package/dist/puzzles/fto/solver/engine.d.ts.map +1 -0
  89. package/dist/puzzles/fto/solver/engine.js +1168 -0
  90. package/dist/puzzles/fto/solver/index.d.ts +2 -0
  91. package/dist/puzzles/fto/solver/index.d.ts.map +1 -0
  92. package/dist/puzzles/fto/solver/index.js +1 -0
  93. package/dist/puzzles/fto/state.d.ts +16 -0
  94. package/dist/puzzles/fto/state.d.ts.map +1 -0
  95. package/dist/puzzles/fto/state.js +61 -0
  96. package/dist/puzzles/fto/types.d.ts +32 -0
  97. package/dist/puzzles/fto/types.d.ts.map +1 -0
  98. package/dist/puzzles/fto/types.js +46 -0
  99. package/dist/puzzles/fto/validation.d.ts +19 -0
  100. package/dist/puzzles/fto/validation.d.ts.map +1 -0
  101. package/dist/puzzles/fto/validation.js +143 -0
  102. package/dist/puzzles/index.d.ts +2 -0
  103. package/dist/puzzles/index.d.ts.map +1 -1
  104. package/dist/puzzles/index.js +6 -0
  105. package/dist/puzzles/skewb/index.d.ts +1 -1
  106. package/dist/puzzles/skewb/index.d.ts.map +1 -1
  107. package/dist/puzzles/skewb/index.js +1 -1
  108. package/dist/puzzles/skewb/random-state.d.ts.map +1 -1
  109. package/dist/puzzles/skewb/random-state.js +4 -1
  110. package/dist/puzzles/sq1/facelets.d.ts +12 -0
  111. package/dist/puzzles/sq1/facelets.d.ts.map +1 -0
  112. package/dist/puzzles/sq1/facelets.js +26 -0
  113. package/dist/puzzles/sq1/index.d.ts +10 -0
  114. package/dist/puzzles/sq1/index.d.ts.map +1 -0
  115. package/dist/puzzles/sq1/index.js +11 -0
  116. package/dist/puzzles/sq1/moves.d.ts +55 -0
  117. package/dist/puzzles/sq1/moves.d.ts.map +1 -0
  118. package/dist/puzzles/sq1/moves.js +220 -0
  119. package/dist/puzzles/sq1/random-state.d.ts +6 -0
  120. package/dist/puzzles/sq1/random-state.d.ts.map +1 -0
  121. package/dist/puzzles/sq1/random-state.js +49 -0
  122. package/dist/puzzles/sq1/scrambler.d.ts +10 -0
  123. package/dist/puzzles/sq1/scrambler.d.ts.map +1 -0
  124. package/dist/puzzles/sq1/scrambler.js +90 -0
  125. package/dist/puzzles/sq1/solver/browser-loader.d.ts +5 -0
  126. package/dist/puzzles/sq1/solver/browser-loader.d.ts.map +1 -0
  127. package/dist/puzzles/sq1/solver/browser-loader.js +92 -0
  128. package/dist/puzzles/sq1/solver/full-cube.d.ts +53 -0
  129. package/dist/puzzles/sq1/solver/full-cube.d.ts.map +1 -0
  130. package/dist/puzzles/sq1/solver/full-cube.js +281 -0
  131. package/dist/puzzles/sq1/solver/generated/manifest.json +50 -0
  132. package/dist/puzzles/sq1/solver/generated/shape-bottom-move.bin +0 -0
  133. package/dist/puzzles/sq1/solver/generated/shape-idx.bin +0 -0
  134. package/dist/puzzles/sq1/solver/generated/shape-prun.bin +0 -0
  135. package/dist/puzzles/sq1/solver/generated/shape-top-move.bin +0 -0
  136. package/dist/puzzles/sq1/solver/generated/shape-twist-move.bin +0 -0
  137. package/dist/puzzles/sq1/solver/generated/square-bottom-move.bin +0 -0
  138. package/dist/puzzles/sq1/solver/generated/square-prun.bin +0 -0
  139. package/dist/puzzles/sq1/solver/generated/square-top-move.bin +0 -0
  140. package/dist/puzzles/sq1/solver/generated/square-twist-move.bin +0 -0
  141. package/dist/puzzles/sq1/solver/index.d.ts +5 -0
  142. package/dist/puzzles/sq1/solver/index.d.ts.map +1 -0
  143. package/dist/puzzles/sq1/solver/index.js +4 -0
  144. package/dist/puzzles/sq1/solver/node-loader.d.ts +4 -0
  145. package/dist/puzzles/sq1/solver/node-loader.d.ts.map +1 -0
  146. package/dist/puzzles/sq1/solver/node-loader.js +113 -0
  147. package/dist/puzzles/sq1/solver/search.d.ts +27 -0
  148. package/dist/puzzles/sq1/solver/search.d.ts.map +1 -0
  149. package/dist/puzzles/sq1/solver/search.js +225 -0
  150. package/dist/puzzles/sq1/solver/shape.d.ts +22 -0
  151. package/dist/puzzles/sq1/solver/shape.d.ts.map +1 -0
  152. package/dist/puzzles/sq1/solver/shape.js +185 -0
  153. package/dist/puzzles/sq1/solver/square.d.ts +10 -0
  154. package/dist/puzzles/sq1/solver/square.d.ts.map +1 -0
  155. package/dist/puzzles/sq1/solver/square.js +90 -0
  156. package/dist/puzzles/sq1/solver/table-metadata.d.ts +48 -0
  157. package/dist/puzzles/sq1/solver/table-metadata.d.ts.map +1 -0
  158. package/dist/puzzles/sq1/solver/table-metadata.js +47 -0
  159. package/dist/puzzles/sq1/solver/tables.d.ts +17 -0
  160. package/dist/puzzles/sq1/solver/tables.d.ts.map +1 -0
  161. package/dist/puzzles/sq1/solver/tables.js +66 -0
  162. package/dist/puzzles/sq1/state.d.ts +10 -0
  163. package/dist/puzzles/sq1/state.d.ts.map +1 -0
  164. package/dist/puzzles/sq1/state.js +74 -0
  165. package/dist/puzzles/sq1/types.d.ts +32 -0
  166. package/dist/puzzles/sq1/types.d.ts.map +1 -0
  167. package/dist/puzzles/sq1/types.js +1 -0
  168. package/dist/puzzles/sq1/validation.d.ts +7 -0
  169. package/dist/puzzles/sq1/validation.d.ts.map +1 -0
  170. package/dist/puzzles/sq1/validation.js +64 -0
  171. package/dist/random/prng.d.ts.map +1 -1
  172. package/dist/random/prng.js +9 -4
  173. package/dist-cjs/core/api.js +11 -1
  174. package/dist-cjs/puzzles/cube4/index.js +11 -4
  175. package/dist-cjs/puzzles/cube4/random-state.js +79 -0
  176. package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +100 -0
  177. package/dist-cjs/puzzles/cube4/reduction/center1.js +258 -0
  178. package/dist-cjs/puzzles/cube4/reduction/center2.js +462 -0
  179. package/dist-cjs/puzzles/cube4/reduction/center3.js +284 -0
  180. package/dist-cjs/puzzles/cube4/reduction/edge3.js +522 -0
  181. package/dist-cjs/puzzles/cube4/reduction/generated/center1-distance.bin +1 -0
  182. package/dist-cjs/puzzles/cube4/reduction/generated/center1-manifest.json +46 -0
  183. package/dist-cjs/puzzles/cube4/reduction/generated/center1-move-maps.bin +0 -0
  184. package/dist-cjs/puzzles/cube4/reduction/generated/center2-ct-move.bin +0 -0
  185. package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +87 -0
  186. package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning.bin +1 -0
  187. package/dist-cjs/puzzles/cube4/reduction/generated/center2-rl-move.bin +0 -0
  188. package/dist-cjs/puzzles/cube4/reduction/generated/center3-manifest.json +40 -0
  189. package/dist-cjs/puzzles/cube4/reduction/generated/center3-move.bin +0 -0
  190. package/dist-cjs/puzzles/cube4/reduction/generated/center3-pruning.bin +0 -0
  191. package/dist-cjs/puzzles/cube4/reduction/generated/edge3-distances.bin +1 -0
  192. package/dist-cjs/puzzles/cube4/reduction/generated/edge3-manifest.json +12 -0
  193. package/dist-cjs/puzzles/cube4/reduction/geometry.js +308 -0
  194. package/dist-cjs/puzzles/cube4/reduction/node-loader.js +104 -0
  195. package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +294 -0
  196. package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +138 -0
  197. package/dist-cjs/puzzles/cube4/reduction/phase3.js +86 -0
  198. package/dist-cjs/puzzles/cube4/reduction/phase4.js +87 -0
  199. package/dist-cjs/puzzles/cube4/reduction/solve.js +314 -0
  200. package/dist-cjs/puzzles/cube4/scrambler.js +122 -79
  201. package/dist-cjs/puzzles/cube4/validation.js +97 -0
  202. package/dist-cjs/puzzles/fto/coordinates.js +240 -0
  203. package/dist-cjs/puzzles/fto/facelets.js +104 -0
  204. package/dist-cjs/puzzles/fto/index.js +68 -0
  205. package/dist-cjs/puzzles/fto/moves.js +126 -0
  206. package/dist-cjs/puzzles/fto/random-state.js +43 -0
  207. package/dist-cjs/puzzles/fto/scrambler.js +53 -0
  208. package/dist-cjs/puzzles/fto/solver/engine.js +1175 -0
  209. package/dist-cjs/puzzles/fto/solver/index.js +9 -0
  210. package/dist-cjs/puzzles/fto/state.js +69 -0
  211. package/dist-cjs/puzzles/fto/types.js +49 -0
  212. package/dist-cjs/puzzles/fto/validation.js +147 -0
  213. package/dist-cjs/puzzles/index.js +7 -1
  214. package/dist-cjs/puzzles/skewb/index.js +2 -1
  215. package/dist-cjs/puzzles/skewb/random-state.js +4 -1
  216. package/dist-cjs/puzzles/sq1/facelets.js +30 -0
  217. package/dist-cjs/puzzles/sq1/index.js +52 -0
  218. package/dist-cjs/puzzles/sq1/moves.js +234 -0
  219. package/dist-cjs/puzzles/sq1/random-state.js +52 -0
  220. package/dist-cjs/puzzles/sq1/scrambler.js +95 -0
  221. package/dist-cjs/puzzles/sq1/solver/browser-loader.js +97 -0
  222. package/dist-cjs/puzzles/sq1/solver/full-cube.js +289 -0
  223. package/dist-cjs/puzzles/sq1/solver/generated/manifest.json +50 -0
  224. package/dist-cjs/puzzles/sq1/solver/generated/shape-bottom-move.bin +0 -0
  225. package/dist-cjs/puzzles/sq1/solver/generated/shape-idx.bin +0 -0
  226. package/dist-cjs/puzzles/sq1/solver/generated/shape-prun.bin +0 -0
  227. package/dist-cjs/puzzles/sq1/solver/generated/shape-top-move.bin +0 -0
  228. package/dist-cjs/puzzles/sq1/solver/generated/shape-twist-move.bin +0 -0
  229. package/dist-cjs/puzzles/sq1/solver/generated/square-bottom-move.bin +0 -0
  230. package/dist-cjs/puzzles/sq1/solver/generated/square-prun.bin +0 -0
  231. package/dist-cjs/puzzles/sq1/solver/generated/square-top-move.bin +0 -0
  232. package/dist-cjs/puzzles/sq1/solver/generated/square-twist-move.bin +0 -0
  233. package/dist-cjs/puzzles/sq1/solver/index.js +18 -0
  234. package/dist-cjs/puzzles/sq1/solver/node-loader.js +120 -0
  235. package/dist-cjs/puzzles/sq1/solver/search.js +229 -0
  236. package/dist-cjs/puzzles/sq1/solver/shape.js +191 -0
  237. package/dist-cjs/puzzles/sq1/solver/square.js +93 -0
  238. package/dist-cjs/puzzles/sq1/solver/table-metadata.js +50 -0
  239. package/dist-cjs/puzzles/sq1/solver/tables.js +106 -0
  240. package/dist-cjs/puzzles/sq1/state.js +81 -0
  241. package/dist-cjs/puzzles/sq1/types.js +2 -0
  242. package/dist-cjs/puzzles/sq1/validation.js +68 -0
  243. package/dist-cjs/random/prng.js +9 -4
  244. package/package.json +43 -14
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ /**
3
+ * Center1 (phase 1 of the 4x4 reduction solver): reduce the two colors of a
4
+ * chosen axis (U/D, R/L or F/B) onto a single face-pair.
5
+ *
6
+ * Design (simpler than the reference's symmetry-reduced tables, which use a
7
+ * fragile 48-element non-group of "block-turn symmetries"):
8
+ * - coordinate: the raw C(24,8) = 735,471 mask of the positions holding the
9
+ * two axis colors — NO symmetry reduction;
10
+ * - pruning: the exact BFS distance table from the three face-pair goal
11
+ * masks (God's number 9; the 27-move set reaches the whole space);
12
+ * - search: greedy descent — any move that decreases the exact distance by
13
+ * exactly 1 is on an optimal path, so repeatedly applying the first such
14
+ * move reaches the goal in exactly `distance` moves, with zero
15
+ * backtracking and no iterative deepening.
16
+ *
17
+ * One table serves all three axes (the face-pairs are equivalent goals).
18
+ * The phase-1 move set: 9 axes [U,R,F,D,L,B,Uw,Rw,Fw] × 3 powers = 27.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.CENTER1_GOAL_MASKS = exports.CENTER1_RAW_STATES = exports.CENTER1_MOVES = exports.CENTER1_AXES = void 0;
22
+ exports.center1Mask = center1Mask;
23
+ exports.rankCenter1Mask = rankCenter1Mask;
24
+ exports.unrankCenter1Mask = unrankCenter1Mask;
25
+ exports.buildCenter1MoveMaps = buildCenter1MoveMaps;
26
+ exports.applyCenter1Move = applyCenter1Move;
27
+ exports.generateCenter1Tables = generateCenter1Tables;
28
+ exports.getCenter1Distance = getCenter1Distance;
29
+ exports.solveCenter1 = solveCenter1;
30
+ exports.solveCenter1All = solveCenter1All;
31
+ exports.verifyCenter1 = verifyCenter1;
32
+ const moves_js_1 = require("../moves.js");
33
+ // ---------------------------------------------------------------------------
34
+ // Constants
35
+ // ---------------------------------------------------------------------------
36
+ exports.CENTER1_AXES = [
37
+ "U", "R", "F", "D", "L", "B", "Uw", "Rw", "Fw"
38
+ ];
39
+ exports.CENTER1_MOVES = exports.CENTER1_AXES.flatMap((face) => [face, `${face}2`, `${face}'`]);
40
+ exports.CENTER1_RAW_STATES = 735471;
41
+ // Cnk table up to n=24.
42
+ const CNK = (() => {
43
+ const table = [];
44
+ for (let n = 0; n <= 24; n++) {
45
+ table[n] = [];
46
+ for (let k = 0; k <= 24; k++) {
47
+ if (k === 0 || k === n)
48
+ table[n][k] = 1;
49
+ else if (k > n)
50
+ table[n][k] = 0;
51
+ else
52
+ table[n][k] = table[n - 1][k - 1] + table[n - 1][k];
53
+ }
54
+ }
55
+ return table;
56
+ })();
57
+ // ---------------------------------------------------------------------------
58
+ // Mask utilities (24-bit integers; bit i = center position i)
59
+ // ---------------------------------------------------------------------------
60
+ /** The mask of the positions holding the two axis colors (colors % 3 == urf). */
61
+ function center1Mask(centers, urf) {
62
+ let mask = 0;
63
+ for (let i = 0; i < 24; i++) {
64
+ if (centers[i] % 3 === urf)
65
+ mask |= 1 << i;
66
+ }
67
+ return mask;
68
+ }
69
+ /** C(24,8) combination rank of a mask. */
70
+ function rankCenter1Mask(mask) {
71
+ let idx = 0;
72
+ let r = 8;
73
+ for (let i = 23; i >= 0; i--) {
74
+ if ((mask >> i) & 1)
75
+ idx += CNK[i][r--];
76
+ }
77
+ return idx;
78
+ }
79
+ function unrankCenter1Mask(idx) {
80
+ let mask = 0;
81
+ let r = 8;
82
+ for (let i = 23; i >= 0; i--) {
83
+ if (idx >= CNK[i][r]) {
84
+ idx -= CNK[i][r];
85
+ r--;
86
+ mask |= 1 << i;
87
+ }
88
+ }
89
+ return mask;
90
+ }
91
+ /** The three face-pair goal masks (bit i = center position i, face-major). */
92
+ exports.CENTER1_GOAL_MASKS = {
93
+ ud: 0xf00f,
94
+ rl: 0xf00f0,
95
+ fb: 0xf00f00
96
+ };
97
+ // ---------------------------------------------------------------------------
98
+ // Move bit-permutations
99
+ // ---------------------------------------------------------------------------
100
+ /** The 27 phase-1 moves as bit-permutations of the 24-bit mask. */
101
+ function buildCenter1MoveMaps() {
102
+ const maps = new Int32Array(exports.CENTER1_MOVES.length * 24);
103
+ for (let m = 0; m < exports.CENTER1_MOVES.length; m++) {
104
+ const { face, turns } = (0, moves_js_1.parseMove)(exports.CENTER1_MOVES[m]);
105
+ const effect = moves_js_1.FACE_MOVE_EFFECTS[face];
106
+ let pos = Array.from({ length: 24 }, (_, i) => i);
107
+ for (let t = 0; t < turns; t++) {
108
+ const next = new Array(24);
109
+ for (let i = 0; i < 24; i++)
110
+ next[i] = pos[effect.ctperm[i]];
111
+ pos = next;
112
+ }
113
+ // apply a move: dest bit i takes source bit pos[i]
114
+ for (let i = 0; i < 24; i++)
115
+ maps[m * 24 + i] = pos[i];
116
+ }
117
+ return maps;
118
+ }
119
+ function applyCenter1Move(mask, moveMap, move) {
120
+ let out = 0;
121
+ for (let i = 0; i < 24; i++) {
122
+ if ((mask >> moveMap[move * 24 + i]) & 1)
123
+ out |= 1 << i;
124
+ }
125
+ return out;
126
+ }
127
+ function generateCenter1Tables() {
128
+ const moveMaps = buildCenter1MoveMaps();
129
+ const distance = new Uint8Array(Math.ceil(exports.CENTER1_RAW_STATES / 2)).fill(0xff);
130
+ const setDistance = (rank, d) => {
131
+ const byte = rank >> 1;
132
+ if ((rank & 1) === 0)
133
+ distance[byte] = (distance[byte] & 0xf0) | (d & 0x0f);
134
+ else
135
+ distance[byte] = (distance[byte] & 0x0f) | ((d & 0x0f) << 4);
136
+ };
137
+ const getDistance = (rank) => {
138
+ const byte = distance[rank >> 1];
139
+ return (rank & 1) === 0 ? byte & 0x0f : byte >> 4;
140
+ };
141
+ const isUnset = (rank) => {
142
+ const byte = distance[rank >> 1];
143
+ return (rank & 1) === 0 ? (byte & 0x0f) === 0x0f : (byte >> 4) === 0x0f;
144
+ };
145
+ // BFS from the three goal masks.
146
+ for (const goal of [exports.CENTER1_GOAL_MASKS.ud, exports.CENTER1_GOAL_MASKS.rl, exports.CENTER1_GOAL_MASKS.fb]) {
147
+ setDistance(rankCenter1Mask(goal), 0);
148
+ }
149
+ const queue = [
150
+ rankCenter1Mask(exports.CENTER1_GOAL_MASKS.ud),
151
+ rankCenter1Mask(exports.CENTER1_GOAL_MASKS.rl),
152
+ rankCenter1Mask(exports.CENTER1_GOAL_MASKS.fb)
153
+ ];
154
+ let head = 0;
155
+ while (head < queue.length) {
156
+ const rank = queue[head++];
157
+ const mask = unrankCenter1Mask(rank);
158
+ const d = getDistance(rank);
159
+ for (let m = 0; m < exports.CENTER1_MOVES.length; m++) {
160
+ const next = applyCenter1Move(mask, moveMaps, m);
161
+ const nextRank = rankCenter1Mask(next);
162
+ if (isUnset(nextRank)) {
163
+ setDistance(nextRank, d + 1);
164
+ queue.push(nextRank);
165
+ }
166
+ }
167
+ }
168
+ // verify completeness: every state reached
169
+ let reached = 0;
170
+ for (let rank = 0; rank < exports.CENTER1_RAW_STATES; rank++) {
171
+ if (!isUnset(rank))
172
+ reached++;
173
+ }
174
+ if (reached !== exports.CENTER1_RAW_STATES) {
175
+ throw new Error(`Center1 BFS incomplete: ${reached}/${exports.CENTER1_RAW_STATES} states reached.`);
176
+ }
177
+ return { distance, moveMaps };
178
+ }
179
+ function getCenter1Distance(mask, tables) {
180
+ const rank = rankCenter1Mask(mask);
181
+ const byte = tables.distance[rank >> 1];
182
+ return (rank & 1) === 0 ? byte & 0x0f : byte >> 4;
183
+ }
184
+ /**
185
+ * Phase-1 greedy descent: bring the axis colors onto some face-pair in
186
+ * exactly `distance` moves (optimal). Every move that decreases the exact
187
+ * distance by 1 is on an optimal path, so no backtracking is needed.
188
+ * Returns null if the state is unreachable (should not happen).
189
+ */
190
+ function solveCenter1(centers, urf, tables) {
191
+ const solutions = solveCenter1All(centers, urf, tables, 1);
192
+ return solutions.length > 0 ? solutions[0] : null;
193
+ }
194
+ /**
195
+ * Enumerate phase-1 solutions (the optimal descending paths, then longer
196
+ * alternatives up to `cap`). The phase-1 → phase-3 pipeline needs variety:
197
+ * the phase-2 gate rate depends strongly on the phase-1 output's wings.
198
+ */
199
+ function solveCenter1All(centers, urf, tables, cap = 50) {
200
+ const moveMaps = tables.moveMaps;
201
+ const solutions = [];
202
+ const path = [];
203
+ const maxLength = 30;
204
+ const dfs = (mask, depth) => {
205
+ if (solutions.length >= cap)
206
+ return true;
207
+ const h = getCenter1Distance(mask, tables);
208
+ if (h === 0) {
209
+ solutions.push({ moves: path.slice(0, depth).map((m) => exports.CENTER1_MOVES[m]), length: depth });
210
+ return false;
211
+ }
212
+ if (depth >= maxLength)
213
+ return false;
214
+ for (let m = 0; m < exports.CENTER1_MOVES.length; m++) {
215
+ const next = applyCenter1Move(mask, moveMaps, m);
216
+ if (getCenter1Distance(next, tables) !== h - 1)
217
+ continue;
218
+ path[depth] = m;
219
+ if (dfs(next, depth + 1))
220
+ return true;
221
+ }
222
+ return false;
223
+ };
224
+ dfs(center1Mask(centers, urf), 0);
225
+ return solutions;
226
+ }
227
+ // ---------------------------------------------------------------------------
228
+ // Verification gates
229
+ // ---------------------------------------------------------------------------
230
+ function verifyCenter1(tables) {
231
+ const errors = [];
232
+ if (getCenter1Distance(exports.CENTER1_GOAL_MASKS.ud, tables) !== 0) {
233
+ errors.push("Goal mask ud must have distance 0.");
234
+ }
235
+ if (getCenter1Distance(exports.CENTER1_GOAL_MASKS.rl, tables) !== 0) {
236
+ errors.push("Goal mask rl must have distance 0.");
237
+ }
238
+ if (getCenter1Distance(exports.CENTER1_GOAL_MASKS.fb, tables) !== 0) {
239
+ errors.push("Goal mask fb must have distance 0.");
240
+ }
241
+ // distances must be consistent with the moves
242
+ let maxDepth = 0;
243
+ for (let rank = 0; rank < exports.CENTER1_RAW_STATES; rank++) {
244
+ const mask = unrankCenter1Mask(rank);
245
+ const d = getCenter1Distance(mask, tables);
246
+ if (d > maxDepth)
247
+ maxDepth = d;
248
+ for (let m = 0; m < exports.CENTER1_MOVES.length; m++) {
249
+ const next = applyCenter1Move(mask, tables.moveMaps, m);
250
+ const nd = getCenter1Distance(next, tables);
251
+ if (nd < d - 1 || nd > d + 1) {
252
+ errors.push(`Distance inconsistency at rank ${rank} move ${exports.CENTER1_MOVES[m]}: ${d} -> ${nd}.`);
253
+ break;
254
+ }
255
+ }
256
+ }
257
+ return errors;
258
+ }