@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,522 @@
1
+ "use strict";
2
+ /**
3
+ * Edge3 (the pairing pruning table for the phase-3 search).
4
+ *
5
+ * The BFS from the solved pairing state over the 17 BFS moves, canonicalized
6
+ * by the 8 rotation symmetries of the reference's Edge3 phase (`$rot_1` /
7
+ * `$rotate_0` decomposition with the `$circlex` / `$swapx` coordinate
8
+ * effects). The pairing state is the relative 12-permutation between the
9
+ * two halves of the edge slots (see `pairing-coordinate.ts`), stored in the
10
+ * reference's `(edge, edgeo)` form with shared labels and `$std`-normalized
11
+ * (second halves hold pairs 0..11 in order).
12
+ *
13
+ * Canonicalization and indexing follow the reference exactly:
14
+ * - the state space is the 12!/2 even edge permutations (parity is
15
+ * invariant under the phase-3 moves), grouped into 1538 first-4
16
+ * "sym" classes under the 8 rotations (the reference's
17
+ * `initEdge3Sym2Raw`);
18
+ * - the canonical sym-index of a state is `symcord1 * 20160 + cord2`,
19
+ * computed by `getMvSym` (the reference's move-conjugated
20
+ * canonicalization with the `mvrot`/`mvroto` tables);
21
+ * - the table stores the exact BFS distance per sym-index (4-bit packed
22
+ * nibbles): 31,006,080 * 4 bits = 15.5 MB, no class-key file needed.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.MOVE3_STD = exports.EDGE3_MAX_DEPTH = exports.EDGE3_CORD2 = exports.EDGE3_CLASSES = exports.EDGE3_TOTAL = void 0;
26
+ exports.bitCount = bitCount;
27
+ exports.getSymTables = getSymTables;
28
+ exports.buildSymTables = buildSymTables;
29
+ exports.getMvSymFrom = getMvSymFrom;
30
+ exports.generateEdge3Tables = generateEdge3Tables;
31
+ exports.edge3DistanceLookup = edge3DistanceLookup;
32
+ exports.__edge3TestHooks = __edge3TestHooks;
33
+ exports.verifyEdge3 = verifyEdge3;
34
+ const pairing_coordinate_js_1 = require("./pairing-coordinate.js");
35
+ // ---------------------------------------------------------------------------
36
+ // The reference's constants
37
+ // ---------------------------------------------------------------------------
38
+ /** The sym-index space: 1538 first-4 classes × 20160 remaining. */
39
+ exports.EDGE3_TOTAL = 31_006_080;
40
+ exports.EDGE3_CLASSES = 1538;
41
+ exports.EDGE3_CORD2 = 20_160;
42
+ /** The first-4 Lehmer range (12 * 11 * 10 * 9). */
43
+ const EDGE3_FIRST4 = 11_880;
44
+ /** The maximum BFS depth (the reference's prunValues length - 1). */
45
+ exports.EDGE3_MAX_DEPTH = 13;
46
+ /** The reference's `factX` (factorials / 2, with the small ones = 1). */
47
+ const FACT_X = [
48
+ 1, 1, 1, 3, 12, 60, 360, 2520, 20160, 181440, 1814400, 19958400, 239500800
49
+ ];
50
+ /** The reference's `syminv_0`: inverse rotation index mapping. */
51
+ const SYMINV_0 = [0, 1, 6, 3, 4, 5, 2, 7];
52
+ /** The reference's `move3std`: $move_4 case → std3 move id (the % 3 class). */
53
+ exports.MOVE3_STD = [
54
+ 0, 1, 2, 4, 6, 7, 8, 9, 10, 11, 13, 15, 16, 17, 19, 22, 25, 28, 31, 34, 36
55
+ ];
56
+ /** The reference's `bfsMoves` (the $move_4 case indices). */
57
+ const EDGE3_MOVE_CASES = [1, 0, 2, 3, 5, 4, 6, 8, 7, 9, 10, 12, 11, 13, 14, 15, 16];
58
+ const BIT_COUNT = (() => {
59
+ const table = new Uint8Array(4096);
60
+ for (let i = 0; i < 4096; i++) {
61
+ table[i] = table[i >> 1] + (i & 1);
62
+ }
63
+ return table;
64
+ })();
65
+ function bitCount(v) {
66
+ return BIT_COUNT[v & 4095] + BIT_COUNT[(v >> 12) & 4095] + BIT_COUNT[v >> 24];
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // The (edge, edgeo) coordinate with the shared labels
70
+ // ---------------------------------------------------------------------------
71
+ /**
72
+ * The reference's `$swap_0`: the two transpositions (a↔c, b↔d) on one array.
73
+ */
74
+ function swap0(arr, a, b, c, d) {
75
+ let temp = arr[a];
76
+ arr[a] = arr[c];
77
+ arr[c] = temp;
78
+ temp = arr[b];
79
+ arr[b] = arr[d];
80
+ arr[d] = temp;
81
+ }
82
+ /** The reference's `$circlex`: a 4-cycle across the two halves. */
83
+ function circlex(edge, edgeo, a, b, c, d) {
84
+ const temp = edgeo[d];
85
+ edgeo[d] = edge[c];
86
+ edge[c] = edgeo[b];
87
+ edgeo[b] = edge[a];
88
+ edge[a] = temp;
89
+ }
90
+ /** The reference's `$swapx`: swap the halves across slots x and y. */
91
+ function swapx(edge, edgeo, x, y) {
92
+ const temp = edge[x];
93
+ edge[x] = edgeo[y];
94
+ edgeo[y] = temp;
95
+ }
96
+ /**
97
+ * The reference's `$move_4` (cases 0-19) as coordinate effects: the same
98
+ * slot permutations applied to `edge` and `edgeo`. The `circle` direction
99
+ * (the cubing.js `mathlib.circle`: the value at a moves to b) is verified
100
+ * against the physical move tables in `verifyEdge3`.
101
+ */
102
+ function applyMoveCase(edge, edgeo, m) {
103
+ const circle = (arr, a, b, c, d) => {
104
+ const temp = arr[a];
105
+ arr[a] = arr[d];
106
+ arr[d] = arr[c];
107
+ arr[c] = arr[b];
108
+ arr[b] = temp;
109
+ };
110
+ const circle2 = (arr, a, b) => {
111
+ const temp = arr[a];
112
+ arr[a] = arr[b];
113
+ arr[b] = temp;
114
+ };
115
+ switch (m) {
116
+ case 0:
117
+ circle(edge, 0, 4, 1, 5);
118
+ circle(edgeo, 0, 4, 1, 5);
119
+ break;
120
+ case 1:
121
+ swap0(edge, 0, 4, 1, 5);
122
+ swap0(edgeo, 0, 4, 1, 5);
123
+ break;
124
+ case 2:
125
+ circle(edge, 0, 5, 1, 4);
126
+ circle(edgeo, 0, 5, 1, 4);
127
+ break;
128
+ case 3:
129
+ swap0(edge, 5, 10, 6, 11);
130
+ swap0(edgeo, 5, 10, 6, 11);
131
+ break;
132
+ case 4:
133
+ circle(edge, 0, 11, 3, 8);
134
+ circle(edgeo, 0, 11, 3, 8);
135
+ break;
136
+ case 5:
137
+ swap0(edge, 0, 11, 3, 8);
138
+ swap0(edgeo, 0, 11, 3, 8);
139
+ break;
140
+ case 6:
141
+ circle(edge, 0, 8, 3, 11);
142
+ circle(edgeo, 0, 8, 3, 11);
143
+ break;
144
+ case 7:
145
+ circle(edge, 2, 7, 3, 6);
146
+ circle(edgeo, 2, 7, 3, 6);
147
+ break;
148
+ case 8:
149
+ swap0(edge, 2, 7, 3, 6);
150
+ swap0(edgeo, 2, 7, 3, 6);
151
+ break;
152
+ case 9:
153
+ circle(edge, 2, 6, 3, 7);
154
+ circle(edgeo, 2, 6, 3, 7);
155
+ break;
156
+ case 10:
157
+ swap0(edge, 4, 8, 7, 9);
158
+ swap0(edgeo, 4, 8, 7, 9);
159
+ break;
160
+ case 11:
161
+ circle(edge, 1, 9, 2, 10);
162
+ circle(edgeo, 1, 9, 2, 10);
163
+ break;
164
+ case 12:
165
+ swap0(edge, 1, 9, 2, 10);
166
+ swap0(edgeo, 1, 9, 2, 10);
167
+ break;
168
+ case 13:
169
+ circle(edge, 1, 10, 2, 9);
170
+ circle(edgeo, 1, 10, 2, 9);
171
+ break;
172
+ case 14:
173
+ swap0(edge, 0, 4, 1, 5);
174
+ swap0(edgeo, 0, 4, 1, 5);
175
+ circle2(edge, 9, 11);
176
+ circle2(edgeo, 8, 10);
177
+ break;
178
+ case 15:
179
+ swap0(edge, 5, 10, 6, 11);
180
+ swap0(edgeo, 5, 10, 6, 11);
181
+ circle2(edge, 1, 3);
182
+ circle2(edgeo, 0, 2);
183
+ break;
184
+ case 16:
185
+ swap0(edge, 0, 11, 3, 8);
186
+ swap0(edgeo, 0, 11, 3, 8);
187
+ circle2(edge, 5, 7);
188
+ circle2(edgeo, 4, 6);
189
+ break;
190
+ case 17:
191
+ swap0(edge, 2, 7, 3, 6);
192
+ swap0(edgeo, 2, 7, 3, 6);
193
+ circle2(edge, 8, 10);
194
+ circle2(edgeo, 9, 11);
195
+ break;
196
+ case 18:
197
+ swap0(edge, 4, 8, 7, 9);
198
+ swap0(edgeo, 4, 8, 7, 9);
199
+ circle2(edge, 0, 2);
200
+ circle2(edgeo, 1, 3);
201
+ break;
202
+ case 19:
203
+ swap0(edge, 1, 9, 2, 10);
204
+ swap0(edgeo, 1, 9, 2, 10);
205
+ circle2(edge, 4, 6);
206
+ circle2(edgeo, 5, 7);
207
+ break;
208
+ }
209
+ }
210
+ /** The reference's `$rot_1` (r = 0, 1, 2) on the (edge, edgeo) pair. */
211
+ function rot1(edge, edgeo, r) {
212
+ switch (r) {
213
+ case 0:
214
+ applyMoveCase(edge, edgeo, 14);
215
+ applyMoveCase(edge, edgeo, 17);
216
+ break;
217
+ case 1:
218
+ circlex(edge, edgeo, 11, 5, 10, 6);
219
+ circlex(edge, edgeo, 5, 10, 6, 11);
220
+ circlex(edge, edgeo, 1, 2, 3, 0);
221
+ circlex(edge, edgeo, 4, 9, 7, 8);
222
+ circlex(edge, edgeo, 8, 4, 9, 7);
223
+ circlex(edge, edgeo, 0, 1, 2, 3);
224
+ break;
225
+ case 2:
226
+ swapx(edge, edgeo, 4, 5);
227
+ swapx(edge, edgeo, 5, 4);
228
+ swapx(edge, edgeo, 11, 8);
229
+ swapx(edge, edgeo, 8, 11);
230
+ swapx(edge, edgeo, 7, 6);
231
+ swapx(edge, edgeo, 6, 7);
232
+ swapx(edge, edgeo, 9, 10);
233
+ swapx(edge, edgeo, 10, 9);
234
+ swapx(edge, edgeo, 1, 1);
235
+ swapx(edge, edgeo, 0, 0);
236
+ swapx(edge, edgeo, 3, 3);
237
+ swapx(edge, edgeo, 2, 2);
238
+ break;
239
+ }
240
+ }
241
+ /** The reference's `$rotate_0`: rotation r (0..7) via the rot1 decomposition. */
242
+ function rotateByIndex(edge, edgeo, r) {
243
+ while (r >= 2) {
244
+ r -= 2;
245
+ rot1(edge, edgeo, 1);
246
+ rot1(edge, edgeo, 2);
247
+ }
248
+ if (r !== 0)
249
+ rot1(edge, edgeo, 0);
250
+ }
251
+ // ---------------------------------------------------------------------------
252
+ // Lehmer helpers (the reference's get12Perm / $set_4)
253
+ // ---------------------------------------------------------------------------
254
+ /**
255
+ * The mixed-radix Lehmer encode of the first `end` values (the reference's
256
+ * `get12Perm`): idx = Σ digit_i * (12-i)!-radix, with the digits reduced by
257
+ * the values already seen.
258
+ */
259
+ function get12Perm(arr, end, returnMask = false) {
260
+ let idx = 0;
261
+ let mask = 0;
262
+ for (let i = 0; i < end; i++) {
263
+ const val = arr[i];
264
+ idx = idx * (12 - i) + val - bitCount(mask & ((1 << val) - 1));
265
+ mask |= 1 << val;
266
+ }
267
+ return returnMask ? mask : idx;
268
+ }
269
+ /**
270
+ * Decode a 12-permutation from the mixed-radix index (the reference's
271
+ * `$set_4`): the 11 digits with the parity-corrected last two positions.
272
+ */
273
+ function set4(out, idx) {
274
+ let parity = 0;
275
+ const unused = [];
276
+ for (let i = 0; i < 12; i++)
277
+ unused.push(i);
278
+ for (let i = 0; i < 11; i++) {
279
+ const p = FACT_X[11 - i];
280
+ const v = Math.floor(idx / p);
281
+ idx = idx % p;
282
+ parity ^= v;
283
+ out[i] = unused[v];
284
+ unused.splice(v, 1);
285
+ }
286
+ const last = unused[0];
287
+ if ((parity & 1) === 0) {
288
+ out[11] = last;
289
+ }
290
+ else {
291
+ out[11] = out[10];
292
+ out[10] = last;
293
+ }
294
+ }
295
+ let symTables = null;
296
+ function getSymTables() {
297
+ if (!symTables) {
298
+ symTables = buildSymTables();
299
+ }
300
+ return symTables;
301
+ }
302
+ function buildSymTables() {
303
+ const mvrot = new Uint8Array(21 * 8 * 12);
304
+ const mvroto = new Uint8Array(21 * 8 * 12);
305
+ const edge = new Uint8Array(12);
306
+ const edgeo = new Uint8Array(12);
307
+ // initEdge3MvRot: the move-conjugated rotation effects on the solved state.
308
+ for (let m = 0; m < 21; m++) {
309
+ for (let r = 0; r < 8; r++) {
310
+ set4(edge, 0);
311
+ for (let i = 0; i < 12; i++)
312
+ edgeo[i] = i;
313
+ if (m < 20)
314
+ applyMoveCase(edge, edgeo, m);
315
+ rotateByIndex(edge, edgeo, r);
316
+ const base = (m << 3 | r) * 12;
317
+ for (let i = 0; i < 12; i++)
318
+ mvrot[base + i] = edge[i];
319
+ // the reference's $std: temp[edgeo[i]] = i; mvroto = the temp (the
320
+ // inverse of the pre-std edgeo), NOT the std'ed edge.
321
+ const temp = new Uint8Array(12);
322
+ for (let i = 0; i < 12; i++)
323
+ temp[edgeo[i]] = i;
324
+ for (let i = 0; i < 12; i++)
325
+ mvroto[base + i] = temp[i];
326
+ }
327
+ }
328
+ // initEdge3Sym2Raw: the 1538 first-4 classes under the 8 rotations.
329
+ const occ = new Uint8Array(1485);
330
+ const sym2Raw = new Uint32Array(exports.EDGE3_CLASSES);
331
+ const sym2Mask = new Uint32Array(exports.EDGE3_CLASSES);
332
+ const raw2Sym = new Uint32Array(EDGE3_FIRST4);
333
+ const symState = new Uint32Array(exports.EDGE3_CLASSES);
334
+ let count = 0;
335
+ for (let i = 0; i < EDGE3_FIRST4; i++) {
336
+ if ((occ[i >> 3] & (1 << (i & 7))) !== 0)
337
+ continue;
338
+ set4(edge, i * FACT_X[8]);
339
+ for (let k = 0; k < 12; k++)
340
+ edgeo[k] = k;
341
+ sym2Raw[count] = i;
342
+ sym2Mask[count] = get12Perm((0, pairing_coordinate_js_1.normalizePairingState)(edge, edgeo).edge, 4, true);
343
+ for (let j = 0; j < 8; j++) {
344
+ const idx = get12Perm((0, pairing_coordinate_js_1.normalizePairingState)(edge, edgeo).edge, 4);
345
+ if (idx === i)
346
+ symState[count] = (symState[count] | (1 << j)) >>> 0;
347
+ occ[idx >> 3] = (occ[idx >> 3] | (1 << (idx & 7)));
348
+ raw2Sym[idx] = (count << 3 | SYMINV_0[j]) >>> 0;
349
+ rot1(edge, edgeo, 0);
350
+ if ((j & 1) === 1) {
351
+ rot1(edge, edgeo, 1);
352
+ rot1(edge, edgeo, 2);
353
+ }
354
+ }
355
+ count++;
356
+ }
357
+ if (count !== exports.EDGE3_CLASSES) {
358
+ throw new Error(`Edge3: expected ${exports.EDGE3_CLASSES} classes, found ${count}`);
359
+ }
360
+ // the reference's initEdge3Sym2Raw second half: the sym-advance table.
361
+ const symMove = new Uint16Array(20 * exports.EDGE3_CLASSES);
362
+ for (let i = 0; i < exports.EDGE3_CLASSES; i++) {
363
+ set4(edge, sym2Raw[i] * FACT_X[8]);
364
+ for (let k = 0; k < 12; k++)
365
+ edgeo[k] = k;
366
+ for (let m = 0; m < 20; m++) {
367
+ if (exports.MOVE3_STD[m] % 3 !== 1)
368
+ continue;
369
+ const idx = getMvSymFrom(edge, edgeo, m, sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto);
370
+ symMove[m * exports.EDGE3_CLASSES + i] = (Math.floor((idx >> 3) / exports.EDGE3_CORD2) << 3 | (idx & 7));
371
+ }
372
+ }
373
+ const tables = { mvrot, mvroto, sym2Raw, sym2Mask, raw2Sym, symState, symMove };
374
+ symTables = tables;
375
+ return tables;
376
+ }
377
+ /**
378
+ * The reference's `getMvSym`: the canonical sym-index of the state (edge,
379
+ * edgeo) under the move-conjugated rotation, as `(sym-index << 3 | r)`.
380
+ */
381
+ function getMvSymFrom(edge, _edgeo, mv, sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto, assumeIdx) {
382
+ let mrIdx = mv << 3;
383
+ let idx;
384
+ if (assumeIdx !== undefined && exports.MOVE3_STD[mv] % 3 === 1) {
385
+ mrIdx |= assumeIdx & 7;
386
+ idx = assumeIdx >> 3;
387
+ }
388
+ else {
389
+ const movoBase = mrIdx * 12;
390
+ let baseIdx = 0;
391
+ let mask = 0;
392
+ for (let i = 0; i < 4; i++) {
393
+ const val = mvroto[movoBase + edge[mvrot[movoBase + i]]];
394
+ baseIdx = baseIdx * (12 - i) + val - bitCount(mask & ((1 << val) - 1));
395
+ mask |= 1 << val;
396
+ }
397
+ baseIdx = raw2Sym[baseIdx];
398
+ mrIdx |= baseIdx & 7;
399
+ baseIdx >>= 3;
400
+ idx = baseIdx;
401
+ }
402
+ const mrIdxBase = mrIdx * 12;
403
+ let mask = sym2Mask[idx];
404
+ let out = idx;
405
+ for (let i = 4; i < 10; i++) {
406
+ const val = mvroto[mrIdxBase + edge[mvrot[mrIdxBase + i]]];
407
+ out = out * (12 - i) + val - bitCount(mask & ((1 << val) - 1));
408
+ mask |= 1 << val;
409
+ }
410
+ return (out << 3 | (mrIdx & 7)) >>> 0;
411
+ }
412
+ /**
413
+ * Generate the exact BFS distances over the 31,006,080 sym-index space.
414
+ * `maxDepthCap` stops the BFS early (validation only).
415
+ */
416
+ function generateEdge3Tables(maxDepthCap = -1) {
417
+ const t = buildSymTables();
418
+ const { sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto, symMove, symState } = t;
419
+ const distances = new Uint8Array(Math.ceil(exports.EDGE3_TOTAL / 2)).fill(0xff);
420
+ const setDistance = (idx, depth) => {
421
+ const byte = idx >> 1;
422
+ const shift = (idx & 1) * 4;
423
+ distances[byte] = (distances[byte] & ~(0x0f << shift)) | ((depth & 0x0f) << shift);
424
+ };
425
+ const getDistance = (idx) => (distances[idx >> 1] >> ((idx & 1) * 4)) & 0x0f;
426
+ const edge = new Uint8Array(12);
427
+ const edgeo = new Uint8Array(12);
428
+ const fEdge = new Uint8Array(12);
429
+ const fEdgeo = new Uint8Array(12);
430
+ const gEdge = new Uint8Array(12);
431
+ const gEdgeo = new Uint8Array(12);
432
+ setDistance(0, 0);
433
+ let frontier = [0];
434
+ let depth = 0;
435
+ while (frontier.length > 0) {
436
+ if (maxDepthCap >= 0 && depth >= maxDepthCap)
437
+ break;
438
+ const next = [];
439
+ for (const si of frontier) {
440
+ const symcord1 = Math.floor(si / exports.EDGE3_CORD2);
441
+ const cord2 = si % exports.EDGE3_CORD2;
442
+ set4(edge, sym2Raw[symcord1] * FACT_X[8] + cord2);
443
+ for (let k = 0; k < 12; k++)
444
+ edgeo[k] = k;
445
+ for (let mi = 0; mi < 17; mi++) {
446
+ const m = EDGE3_MOVE_CASES[mi];
447
+ // the reference's getMvSym takes the UNMOVED state: the
448
+ // move-conjugated tables provide the moved canonical.
449
+ const idx = getMvSymFrom(edge, edgeo, m, sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto, symMove[m * exports.EDGE3_CLASSES + symcord1]);
450
+ const canonical = idx >> 3;
451
+ if (getDistance(canonical) !== 0x0f)
452
+ continue;
453
+ setDistance(canonical, depth + 1);
454
+ next.push(canonical);
455
+ // the rotation-conjugated representatives of the moved class
456
+ const symcord1x = Math.floor(canonical / exports.EDGE3_CORD2);
457
+ let symStateBits = symState[symcord1x];
458
+ if (symStateBits === 1)
459
+ continue;
460
+ fEdge.set(edge);
461
+ fEdgeo.set(edgeo);
462
+ applyMoveCase(fEdge, fEdgeo, m);
463
+ rotateByIndex(fEdge, fEdgeo, idx & 7);
464
+ for (let j = 1; (symStateBits = symStateBits >> 1) !== 0; j++) {
465
+ if ((symStateBits & 1) !== 1)
466
+ continue;
467
+ gEdge.set(fEdge);
468
+ gEdgeo.set(fEdgeo);
469
+ rotateByIndex(gEdge, gEdgeo, j);
470
+ const normalized = (0, pairing_coordinate_js_1.normalizePairingState)(gEdge, gEdgeo);
471
+ const idxx = symcord1x * exports.EDGE3_CORD2 + (get12Perm(normalized.edge, 10) % exports.EDGE3_CORD2);
472
+ if (getDistance(idxx) !== 0x0f)
473
+ continue;
474
+ setDistance(idxx, depth + 1);
475
+ next.push(idxx);
476
+ }
477
+ }
478
+ }
479
+ frontier = next;
480
+ depth++;
481
+ }
482
+ const distanceOfEdge = edge3DistanceLookup(distances);
483
+ return { distances, distanceOfEdge };
484
+ }
485
+ /**
486
+ * The distance lookup over a loaded distances buffer: builds the sym
487
+ * machinery once (cached) and returns a closure from the std-form edge
488
+ * (a 12-permutation) to its BFS distance.
489
+ */
490
+ function edge3DistanceLookup(distances) {
491
+ const t = symTables ?? buildSymTables();
492
+ const { sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto } = t;
493
+ const identity = Uint8Array.from({ length: 12 }, (_, i) => i);
494
+ return (e) => {
495
+ const std = (0, pairing_coordinate_js_1.normalizePairingState)(e, identity).edge;
496
+ const idx = getMvSymFrom(std, identity, 20, sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto) >> 3;
497
+ return (distances[idx >> 1] >> ((idx & 1) * 4)) & 0x0f;
498
+ };
499
+ }
500
+ // ---------------------------------------------------------------------------
501
+ // Verification gates
502
+ // ---------------------------------------------------------------------------
503
+ /** Test-only hooks. */
504
+ function __edge3TestHooks() {
505
+ return { buildSymTables, applyMoveCase, get12Perm, set4, rotateByIndex, getMvSymFrom };
506
+ }
507
+ function verifyEdge3(tables) {
508
+ const errors = [];
509
+ const identity = Uint8Array.from({ length: 12 }, (_, i) => i);
510
+ if (tables.distanceOfEdge(identity) !== 0) {
511
+ errors.push("Solved state must have distance 0.");
512
+ }
513
+ let seen = 0;
514
+ for (let i = 0; i < exports.EDGE3_TOTAL; i++) {
515
+ if (((tables.distances[i >> 1] >> ((i & 1) * 4)) & 0x0f) !== 0x0f)
516
+ seen++;
517
+ }
518
+ if (seen !== exports.EDGE3_TOTAL) {
519
+ errors.push(`Expected ${exports.EDGE3_TOTAL} reachable classes, saw ${seen}.`);
520
+ }
521
+ return errors;
522
+ }