@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,284 @@
1
+ "use strict";
2
+ /**
3
+ * Center3 (the center part of the phase-3 search): track the center
4
+ * arrangement through the phase-3 moves (which disturb the solved centers
5
+ * with the wide doubles) and reach the fully-solved centers.
6
+ *
7
+ * Ported from the reference's `Center3` class, adapted to this repo's
8
+ * layout. The state is three 8-entry arrays of "half-class" bits
9
+ * ((color / 3) ^ 1) per face-pair, plus a parity bit:
10
+ * - ud: the U, D face positions (this repo: U = 0-3, D = 12-15)
11
+ * - fb: the F, B face positions (8-11, 20-23)
12
+ * - rl: the R, L face positions (4-7, 16-19)
13
+ *
14
+ * Coordinate (reference `$getct_0`): C(7,4) ranks of ud and fb vs their 8th
15
+ * entry (35 each), the rl C(8,4) rank reduced to one of 12 standard values,
16
+ * then ×2 + parity = 29,400 × 2. The rank-0 pattern is "the first four
17
+ * entries differ from the last four" — i.e. each face-pair uniform in half
18
+ * — which is exactly the solved-cube arrangement (verified: the solved cube
19
+ * encodes to coordinate 0). The parity bit absorbs the wing-pairing parity
20
+ * XOR the corner parity at the phase-2 → phase-3 bridge and flips on the
21
+ * wide doubles (`pmove`).
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.CENTER3_STATES = exports.CENTER3_BFS_MOVES = exports.CENTER3_MOVES = void 0;
25
+ exports.encodeCenter3 = encodeCenter3;
26
+ exports.generateCenter3Tables = generateCenter3Tables;
27
+ exports.verifyCenter3 = verifyCenter3;
28
+ const moves_js_1 = require("../moves.js");
29
+ // ---------------------------------------------------------------------------
30
+ // Constants
31
+ // ---------------------------------------------------------------------------
32
+ exports.CENTER3_MOVES = [
33
+ "U", "U2", "U'", "R2", "F", "F2", "F'", "D", "D2", "D'",
34
+ "L2", "B", "B2", "B'", "Uw2", "Rw2", "Fw2", "Dw2", "Lw2", "Bw2"
35
+ ];
36
+ /** The 17-move BFS subset (the reference's pruning loop uses m < 17). */
37
+ exports.CENTER3_BFS_MOVES = exports.CENTER3_MOVES.slice(0, 17);
38
+ /** Wide doubles flip the parity bit. */
39
+ const PARITY_FLIP = new Set(["Uw2", "Rw2", "Fw2", "Dw2", "Lw2", "Bw2"]);
40
+ /** Face-pair positions in this repo's numbering. */
41
+ const UD_POS = [0, 1, 2, 3, 12, 13, 14, 15];
42
+ const FB_POS = [8, 9, 10, 11, 20, 21, 22, 23];
43
+ const RL_POS = [4, 5, 6, 7, 16, 17, 18, 19];
44
+ /** The 12 standard rl ranks (reference rl2std). */
45
+ const RL2STD = [0, 9, 14, 23, 27, 28, 41, 42, 46, 55, 60, 69];
46
+ exports.CENTER3_STATES = 29400;
47
+ // Cnk table up to n=24.
48
+ const CNK = (() => {
49
+ const table = [];
50
+ for (let n = 0; n <= 24; n++) {
51
+ table[n] = [];
52
+ for (let k = 0; k <= 24; k++) {
53
+ if (k === 0 || k === n)
54
+ table[n][k] = 1;
55
+ else if (k > n)
56
+ table[n][k] = 0;
57
+ else
58
+ table[n][k] = table[n - 1][k - 1] + table[n - 1][k];
59
+ }
60
+ }
61
+ return table;
62
+ })();
63
+ // ---------------------------------------------------------------------------
64
+ // Half-class helpers
65
+ // ---------------------------------------------------------------------------
66
+ function halfClass(color) {
67
+ return (Math.floor(color / 3) ^ 1) & 1;
68
+ }
69
+ /** C(7,4) rank of the entries differing from the last one. */
70
+ function rank7(values) {
71
+ const last = values[7];
72
+ let idx = 0;
73
+ let r = 4;
74
+ for (let i = 6; i >= 0; i--) {
75
+ if (values[i] !== last)
76
+ idx += CNK[i][r--];
77
+ }
78
+ return idx;
79
+ }
80
+ /** C(8,4) rank of the entries differing from `check`. */
81
+ function rank8(values, check) {
82
+ let idx = 0;
83
+ let r = 4;
84
+ for (let i = 7; i >= 0; i--) {
85
+ if (values[i] !== check)
86
+ idx += CNK[i][r--];
87
+ }
88
+ return idx;
89
+ }
90
+ /**
91
+ * Encode a full cube state to the Center3 coordinate.
92
+ *
93
+ * `edgeXorCornerParity` = the $set_6 pairing parity XOR the corner
94
+ * permutation parity, computed at the phase-2 → phase-3 bridge.
95
+ */
96
+ function encodeCenter3(state, edgeXorCornerParity) {
97
+ const colors = state.centers;
98
+ // reference: parity = (ct[0]%3 > ct[8]%3) ^ (ct[8]%3 > ct[16]%3) ^ (ct[0]%3 > ct[16]%3) ? 0 : 1
99
+ const a = colors[0] % 3;
100
+ const b = colors[8] % 3;
101
+ const c = colors[16] % 3;
102
+ const xored = (a > b ? 1 : 0) ^ (b > c ? 1 : 0) ^ (a > c ? 1 : 0);
103
+ const parity = xored === 0 ? 1 : 0;
104
+ const ud = new Uint8Array(8);
105
+ const fb = new Uint8Array(8);
106
+ const rl = new Uint8Array(8);
107
+ for (let i = 0; i < 8; i++) {
108
+ ud[i] = halfClass(colors[UD_POS[i]]);
109
+ fb[i] = halfClass(colors[FB_POS[i]]);
110
+ rl[i] = halfClass(colors[RL_POS[i]]);
111
+ }
112
+ let idx = rank7(ud);
113
+ idx = idx * 35 + rank7(fb);
114
+ idx *= 12;
115
+ const check = fb[7] ^ ud[7];
116
+ const rlRank = rank8(rl, check);
117
+ const rlIndex = RL2STD.indexOf(rlRank);
118
+ const finalParity = (parity ^ edgeXorCornerParity);
119
+ return {
120
+ coordinate: finalParity + 2 * (idx + rlIndex),
121
+ parity: finalParity
122
+ };
123
+ }
124
+ // ---------------------------------------------------------------------------
125
+ // Move tables + pruning
126
+ // ---------------------------------------------------------------------------
127
+ function buildMovePositionMaps() {
128
+ const maps = new Int32Array(exports.CENTER3_MOVES.length * 24);
129
+ for (let m = 0; m < exports.CENTER3_MOVES.length; m++) {
130
+ const { face, turns } = (0, moves_js_1.parseMove)(exports.CENTER3_MOVES[m]);
131
+ const effect = moves_js_1.FACE_MOVE_EFFECTS[face];
132
+ let pos = Array.from({ length: 24 }, (_, i) => i);
133
+ for (let t = 0; t < turns; t++) {
134
+ const next = new Array(24);
135
+ for (let i = 0; i < 24; i++)
136
+ next[i] = pos[effect.ctperm[i]];
137
+ pos = next;
138
+ }
139
+ for (let i = 0; i < 24; i++)
140
+ maps[m * 24 + i] = pos[i];
141
+ }
142
+ return maps;
143
+ }
144
+ /**
145
+ * Decode a coordinate to canonical half-class arrays (for the move tables):
146
+ * the rank-0 pattern is "first four differ from the last four", so the
147
+ * canonical state is ud = [1,1,1,1,0,0,0,0], fb = [1,1,1,1,0,0,0,0],
148
+ * rl = [1,1,1,1,0,0,0,0] for coordinate 0.
149
+ */
150
+ function decodeCenter3(coordinate) {
151
+ const parity = coordinate & 1;
152
+ let value = coordinate >> 1;
153
+ const rlIndex = value % 12;
154
+ value = Math.floor(value / 12);
155
+ const fbRank = value % 35;
156
+ const udRank = Math.floor(value / 35);
157
+ const ud = new Uint8Array(8);
158
+ const fb = new Uint8Array(8);
159
+ const rl = new Uint8Array(8);
160
+ // unrank C(7,4) patterns
161
+ let idx = udRank;
162
+ let r = 4;
163
+ for (let i = 6; i >= 0; i--) {
164
+ if (idx >= CNK[i][r]) {
165
+ idx -= CNK[i][r];
166
+ r--;
167
+ ud[i] = 1;
168
+ }
169
+ }
170
+ idx = fbRank;
171
+ r = 4;
172
+ for (let i = 6; i >= 0; i--) {
173
+ if (idx >= CNK[i][r]) {
174
+ idx -= CNK[i][r];
175
+ r--;
176
+ fb[i] = 1;
177
+ }
178
+ }
179
+ // rl: the standard rank from the index
180
+ const rlRank = RL2STD[rlIndex];
181
+ idx = rlRank;
182
+ r = 4;
183
+ for (let i = 7; i >= 0; i--) {
184
+ if (idx >= CNK[i][r]) {
185
+ idx -= CNK[i][r];
186
+ r--;
187
+ rl[i] = 1;
188
+ }
189
+ }
190
+ return { ud, fb, rl, parity };
191
+ }
192
+ function generateCenter3Tables() {
193
+ const moveMaps = buildMovePositionMaps();
194
+ const moveTable = new Int32Array(exports.CENTER3_STATES * exports.CENTER3_MOVES.length).fill(-1);
195
+ // canonical full arrangements: half-class bits at the face-pair positions.
196
+ // The rl array stores the parity-XORed halves, so the decode undoes the XOR
197
+ // to recover the colors; the move evolution re-extracts the RAW halves and
198
+ // evolves the parity bit via pmove only (it is NOT re-derived from the
199
+ // centers, matching the reference's doMoveCenter3).
200
+ const full = new Uint8Array(24);
201
+ const moved = new Uint8Array(24);
202
+ const ud2 = new Uint8Array(8);
203
+ const fb2 = new Uint8Array(8);
204
+ const rl2 = new Uint8Array(8);
205
+ const coordinateOfMoved = (coordinate, m, parity) => {
206
+ const { ud, fb, rl } = decodeCenter3(coordinate);
207
+ // the half-class arrays live at the 24 face-pair positions; a move is a
208
+ // position permutation, so build the 24-array, permute, and re-extract.
209
+ for (let i = 0; i < 24; i++)
210
+ full[i] = 0;
211
+ for (let i = 0; i < 8; i++) {
212
+ full[UD_POS[i]] = ud[i];
213
+ full[FB_POS[i]] = fb[i];
214
+ full[RL_POS[i]] = rl[i];
215
+ }
216
+ const map = moveMaps;
217
+ for (let i = 0; i < 24; i++)
218
+ moved[i] = full[map[m * 24 + i]];
219
+ for (let i = 0; i < 8; i++) {
220
+ ud2[i] = moved[UD_POS[i]];
221
+ fb2[i] = moved[FB_POS[i]];
222
+ rl2[i] = moved[RL_POS[i]];
223
+ }
224
+ let idx = rank7(ud2);
225
+ idx = idx * 35 + rank7(fb2);
226
+ idx *= 12;
227
+ const check = fb2[7] ^ ud2[7];
228
+ const rlRank = rank8(rl2, check);
229
+ const rlIndex = RL2STD.indexOf(rlRank);
230
+ if (rlIndex < 0)
231
+ return -1;
232
+ const nextParity = (parity ^ (PARITY_FLIP.has(exports.CENTER3_MOVES[m]) ? 1 : 0));
233
+ return nextParity + 2 * (idx + rlIndex);
234
+ };
235
+ // BFS from coordinate 0 with the 17 BFS moves, computing the move-table
236
+ // entries on demand (only the reachable states' transitions are needed).
237
+ const pruning = new Uint8Array(exports.CENTER3_STATES).fill(0xff);
238
+ pruning[0] = 0;
239
+ const queue = [0];
240
+ let head = 0;
241
+ while (head < queue.length) {
242
+ const coord = queue[head++];
243
+ const d = pruning[coord];
244
+ for (let m = 0; m < exports.CENTER3_MOVES.length; m++) {
245
+ const next = coordinateOfMoved(coord, m, coord & 1);
246
+ if (next < 0)
247
+ continue;
248
+ moveTable[coord * exports.CENTER3_MOVES.length + m] = next;
249
+ if (m < exports.CENTER3_BFS_MOVES.length && pruning[next] === 0xff) {
250
+ pruning[next] = d + 1;
251
+ queue.push(next);
252
+ }
253
+ }
254
+ }
255
+ return { moveTable, pruning };
256
+ }
257
+ // ---------------------------------------------------------------------------
258
+ // Verification gates
259
+ // ---------------------------------------------------------------------------
260
+ function verifyCenter3(tables) {
261
+ const errors = [];
262
+ if (tables.pruning[0] !== 0) {
263
+ errors.push("Goal coordinate must have pruning 0.");
264
+ }
265
+ let maxDepth = 0;
266
+ for (let coord = 0; coord < exports.CENTER3_STATES; coord++) {
267
+ const d = tables.pruning[coord];
268
+ if (d === 0xff)
269
+ continue; // unreachable coordinates have no entries
270
+ if (d > maxDepth)
271
+ maxDepth = d;
272
+ for (let m = 0; m < exports.CENTER3_MOVES.length; m++) {
273
+ const next = tables.moveTable[coord * exports.CENTER3_MOVES.length + m];
274
+ if (next < 0)
275
+ continue;
276
+ const nd = tables.pruning[next];
277
+ if (nd === 0xff || nd < d - 1 || nd > d + 1) {
278
+ errors.push(`Pruning inconsistency at ${coord} move ${exports.CENTER3_MOVES[m]}: ${d} -> ${nd}.`);
279
+ break;
280
+ }
281
+ }
282
+ }
283
+ return errors;
284
+ }