@cubingcenter/scrambler 0.6.3 → 0.8.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 (191) hide show
  1. package/README.md +17 -4
  2. package/dist/core/api.d.ts.map +1 -1
  3. package/dist/core/api.js +10 -2
  4. package/dist/puzzles/cube2/solver/browser-loader.d.ts +4 -7
  5. package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
  6. package/dist/puzzles/cube2/solver/browser-loader.js +42 -14
  7. package/dist/puzzles/cube2/solver/generated-assets.d.ts.map +1 -1
  8. package/dist/puzzles/cube2/solver/generated-assets.js +8 -3
  9. package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
  10. package/dist/puzzles/cube2/solver/search.js +3 -3
  11. package/dist/puzzles/cube2/solver/tables.d.ts +6 -0
  12. package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
  13. package/dist/puzzles/cube2/solver/tables.js +16 -2
  14. package/dist/puzzles/cube3/index.d.ts +1 -0
  15. package/dist/puzzles/cube3/index.d.ts.map +1 -1
  16. package/dist/puzzles/cube3/moves.d.ts.map +1 -1
  17. package/dist/puzzles/cube3/moves.js +104 -18
  18. package/dist/puzzles/cube3/scrambler.d.ts +16 -1
  19. package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
  20. package/dist/puzzles/cube3/scrambler.js +1 -1
  21. package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
  22. package/dist/puzzles/cube3/solver/browser-loader.js +48 -22
  23. package/dist/puzzles/cube3/solver/generated-assets.d.ts.map +1 -1
  24. package/dist/puzzles/cube3/solver/generated-assets.js +9 -3
  25. package/dist/puzzles/cube3/solver/index.d.ts +5 -3
  26. package/dist/puzzles/cube3/solver/index.d.ts.map +1 -1
  27. package/dist/puzzles/cube3/solver/index.js +2 -1
  28. package/dist/puzzles/cube3/solver/node-loader.js +9 -2
  29. package/dist/puzzles/cube3/solver/phase1.d.ts +37 -0
  30. package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
  31. package/dist/puzzles/cube3/solver/phase1.js +156 -15
  32. package/dist/puzzles/cube3/solver/phase2.d.ts +75 -0
  33. package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
  34. package/dist/puzzles/cube3/solver/phase2.js +279 -68
  35. package/dist/puzzles/cube3/solver/search-utils.d.ts +1 -1
  36. package/dist/puzzles/cube3/solver/search-utils.d.ts.map +1 -1
  37. package/dist/puzzles/cube3/solver/symmetry.d.ts +24 -0
  38. package/dist/puzzles/cube3/solver/symmetry.d.ts.map +1 -0
  39. package/dist/puzzles/cube3/solver/symmetry.js +74 -0
  40. package/dist/puzzles/cube3/solver/tables.d.ts +6 -1
  41. package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
  42. package/dist/puzzles/cube3/solver/tables.js +14 -12
  43. package/dist/puzzles/cube3/validation.d.ts.map +1 -1
  44. package/dist/puzzles/cube3/validation.js +15 -7
  45. package/dist/puzzles/cube4/browser-worker-pool.d.ts +82 -0
  46. package/dist/puzzles/cube4/browser-worker-pool.d.ts.map +1 -0
  47. package/dist/puzzles/cube4/browser-worker-pool.js +205 -0
  48. package/dist/puzzles/cube4/browser-worker.d.ts +2 -0
  49. package/dist/puzzles/cube4/browser-worker.d.ts.map +1 -0
  50. package/dist/puzzles/cube4/browser-worker.js +31 -0
  51. package/dist/puzzles/cube4/index.d.ts +10 -2
  52. package/dist/puzzles/cube4/index.d.ts.map +1 -1
  53. package/dist/puzzles/cube4/index.js +6 -2
  54. package/dist/puzzles/cube4/moves.d.ts +5 -0
  55. package/dist/puzzles/cube4/moves.d.ts.map +1 -1
  56. package/dist/puzzles/cube4/moves.js +212 -11
  57. package/dist/puzzles/cube4/reduction/browser-loader.d.ts +29 -1
  58. package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
  59. package/dist/puzzles/cube4/reduction/browser-loader.js +227 -32
  60. package/dist/puzzles/cube4/reduction/center2.d.ts +44 -3
  61. package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
  62. package/dist/puzzles/cube4/reduction/center2.js +152 -10
  63. package/dist/puzzles/cube4/reduction/edge3.d.ts +4 -0
  64. package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -1
  65. package/dist/puzzles/cube4/reduction/edge3.js +23 -3
  66. package/dist/puzzles/cube4/reduction/finish3.d.ts +53 -0
  67. package/dist/puzzles/cube4/reduction/finish3.d.ts.map +1 -0
  68. package/dist/puzzles/cube4/reduction/finish3.js +393 -0
  69. package/dist/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
  70. package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
  71. package/dist/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
  72. package/dist/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
  73. package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +44 -0
  74. package/dist/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
  75. package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +52 -0
  76. package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -0
  77. package/dist/puzzles/cube4/reduction/hc-pdb.js +220 -0
  78. package/dist/puzzles/cube4/reduction/node-loader.d.ts +15 -1
  79. package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
  80. package/dist/puzzles/cube4/reduction/node-loader.js +199 -25
  81. package/dist/puzzles/cube4/reduction/pair-transversal.d.ts +28 -0
  82. package/dist/puzzles/cube4/reduction/pair-transversal.d.ts.map +1 -0
  83. package/dist/puzzles/cube4/reduction/pair-transversal.js +107 -0
  84. package/dist/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
  85. package/dist/puzzles/cube4/reduction/phase3-search.d.ts +116 -7
  86. package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
  87. package/dist/puzzles/cube4/reduction/phase3-search.js +458 -32
  88. package/dist/puzzles/cube4/reduction/rotation-fix.d.ts +28 -0
  89. package/dist/puzzles/cube4/reduction/rotation-fix.d.ts.map +1 -0
  90. package/dist/puzzles/cube4/reduction/rotation-fix.js +212 -0
  91. package/dist/puzzles/cube4/reduction/solve.d.ts +172 -2
  92. package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
  93. package/dist/puzzles/cube4/reduction/solve.js +1201 -180
  94. package/dist/puzzles/cube4/scramble-cache.d.ts +93 -0
  95. package/dist/puzzles/cube4/scramble-cache.d.ts.map +1 -0
  96. package/dist/puzzles/cube4/scramble-cache.js +150 -0
  97. package/dist/puzzles/cube4/scrambler.d.ts +201 -6
  98. package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
  99. package/dist/puzzles/cube4/scrambler.js +414 -176
  100. package/dist/puzzles/cube4/state.d.ts.map +1 -1
  101. package/dist/puzzles/cube4/state.js +4 -1
  102. package/dist/puzzles/cube4/worker-pool.d.ts +139 -0
  103. package/dist/puzzles/cube4/worker-pool.d.ts.map +1 -0
  104. package/dist/puzzles/cube4/worker-pool.js +405 -0
  105. package/dist/puzzles/cube4/worker-protocol.d.ts +58 -0
  106. package/dist/puzzles/cube4/worker-protocol.d.ts.map +1 -0
  107. package/dist/puzzles/cube4/worker-protocol.js +58 -0
  108. package/dist/puzzles/cube4/worker.d.ts +26 -0
  109. package/dist/puzzles/cube4/worker.d.ts.map +1 -0
  110. package/dist/puzzles/cube4/worker.js +49 -0
  111. package/dist/puzzles/pyraminx/solver/browser-loader.d.ts +4 -8
  112. package/dist/puzzles/pyraminx/solver/browser-loader.d.ts.map +1 -1
  113. package/dist/puzzles/pyraminx/solver/browser-loader.js +44 -15
  114. package/dist/puzzles/pyraminx/solver/generated-assets.d.ts.map +1 -1
  115. package/dist/puzzles/pyraminx/solver/generated-assets.js +8 -3
  116. package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -1
  117. package/dist/puzzles/pyraminx/solver/search.js +3 -6
  118. package/dist/puzzles/pyraminx/solver/tables.d.ts +6 -0
  119. package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -1
  120. package/dist/puzzles/pyraminx/solver/tables.js +17 -0
  121. package/dist/puzzles/shared/compressed-fetch.d.ts +37 -1
  122. package/dist/puzzles/shared/compressed-fetch.d.ts.map +1 -1
  123. package/dist/puzzles/shared/compressed-fetch.js +226 -31
  124. package/dist/puzzles/shared/load-once.d.ts +16 -0
  125. package/dist/puzzles/shared/load-once.d.ts.map +1 -0
  126. package/dist/puzzles/shared/load-once.js +11 -0
  127. package/dist/puzzles/skewb/solver/browser-loader.d.ts +4 -11
  128. package/dist/puzzles/skewb/solver/browser-loader.d.ts.map +1 -1
  129. package/dist/puzzles/skewb/solver/browser-loader.js +44 -16
  130. package/dist/puzzles/skewb/solver/generated-assets.d.ts.map +1 -1
  131. package/dist/puzzles/skewb/solver/generated-assets.js +8 -3
  132. package/dist/puzzles/skewb/solver/search.js +3 -3
  133. package/dist/puzzles/skewb/solver/tables.d.ts +6 -0
  134. package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
  135. package/dist/puzzles/skewb/solver/tables.js +17 -0
  136. package/dist/puzzles/sq1/solver/browser-loader.d.ts.map +1 -1
  137. package/dist/puzzles/sq1/solver/browser-loader.js +58 -26
  138. package/dist-cjs/core/api.js +10 -2
  139. package/dist-cjs/puzzles/cube2/solver/browser-loader.js +42 -14
  140. package/dist-cjs/puzzles/cube2/solver/generated-assets.js +8 -3
  141. package/dist-cjs/puzzles/cube2/solver/search.js +2 -2
  142. package/dist-cjs/puzzles/cube2/solver/tables.js +17 -3
  143. package/dist-cjs/puzzles/cube3/moves.js +104 -18
  144. package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
  145. package/dist-cjs/puzzles/cube3/solver/browser-loader.js +48 -22
  146. package/dist-cjs/puzzles/cube3/solver/generated-assets.js +9 -3
  147. package/dist-cjs/puzzles/cube3/solver/index.js +8 -1
  148. package/dist-cjs/puzzles/cube3/solver/node-loader.js +9 -2
  149. package/dist-cjs/puzzles/cube3/solver/phase1.js +157 -15
  150. package/dist-cjs/puzzles/cube3/solver/phase2.js +276 -65
  151. package/dist-cjs/puzzles/cube3/solver/symmetry.js +80 -0
  152. package/dist-cjs/puzzles/cube3/solver/tables.js +14 -12
  153. package/dist-cjs/puzzles/cube3/validation.js +15 -7
  154. package/dist-cjs/puzzles/cube4/browser-worker-pool.js +211 -0
  155. package/dist-cjs/puzzles/cube4/index.js +23 -1
  156. package/dist-cjs/puzzles/cube4/moves.js +213 -11
  157. package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +227 -32
  158. package/dist-cjs/puzzles/cube4/reduction/center2.js +155 -10
  159. package/dist-cjs/puzzles/cube4/reduction/edge3.js +24 -3
  160. package/dist-cjs/puzzles/cube4/reduction/finish3.js +398 -0
  161. package/dist-cjs/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
  162. package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
  163. package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
  164. package/dist-cjs/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
  165. package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +44 -0
  166. package/dist-cjs/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
  167. package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +232 -0
  168. package/dist-cjs/puzzles/cube4/reduction/node-loader.js +200 -25
  169. package/dist-cjs/puzzles/cube4/reduction/pair-transversal.js +112 -0
  170. package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
  171. package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +460 -33
  172. package/dist-cjs/puzzles/cube4/reduction/rotation-fix.js +216 -0
  173. package/dist-cjs/puzzles/cube4/reduction/solve.js +1203 -172
  174. package/dist-cjs/puzzles/cube4/scramble-cache.js +156 -0
  175. package/dist-cjs/puzzles/cube4/scrambler.js +416 -174
  176. package/dist-cjs/puzzles/cube4/state.js +4 -1
  177. package/dist-cjs/puzzles/cube4/worker-pool.js +447 -0
  178. package/dist-cjs/puzzles/cube4/worker-protocol.js +62 -0
  179. package/dist-cjs/puzzles/pyraminx/solver/browser-loader.js +44 -15
  180. package/dist-cjs/puzzles/pyraminx/solver/generated-assets.js +8 -3
  181. package/dist-cjs/puzzles/pyraminx/solver/search.js +2 -5
  182. package/dist-cjs/puzzles/pyraminx/solver/tables.js +18 -1
  183. package/dist-cjs/puzzles/shared/compressed-fetch.js +229 -31
  184. package/dist-cjs/puzzles/shared/load-once.js +14 -0
  185. package/dist-cjs/puzzles/skewb/solver/browser-loader.js +44 -16
  186. package/dist-cjs/puzzles/skewb/solver/generated-assets.js +8 -3
  187. package/dist-cjs/puzzles/skewb/solver/search.js +2 -2
  188. package/dist-cjs/puzzles/skewb/solver/tables.js +18 -1
  189. package/dist-cjs/puzzles/sq1/solver/browser-loader.js +58 -26
  190. package/docs/development.md +19 -7
  191. package/package.json +17 -7
@@ -12,7 +12,9 @@
12
12
  * - goal: ct == 0 and rl in the 6 reference goal patterns (even parity);
13
13
  * - the 28-move set keeps the ct and rl position sets separate, so the move
14
14
  * tables factor: ctmv (6,435×28) and rlmv (70×28);
15
- * - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw').
15
+ * - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw')
16
+ * by default; the wide set (`CENTER2_SEARCH_MOVES_WIDE`, all 28, with
17
+ * the `pruningWide` table) additionally tries Dw2/Lw/Lw2/Lw'/Bw2.
16
18
  *
17
19
  * The phase-1 → phase-2 bridge (alignment + encode) is in `reduction.ts`.
18
20
  */
@@ -21,6 +23,12 @@ import type { Cube4State, Cube4Move } from "../types.js";
21
23
  export declare const CENTER2_MOVES: readonly Cube4Move[];
22
24
  /** The search's exploration set (the first 23 of CENTER2_MOVES). */
23
25
  export declare const CENTER2_SEARCH_MOVES: readonly Cube4Move[];
26
+ /**
27
+ * The wide exploration set: all 28 moves (adds Dw2/Lw/Lw2/Lw'/Bw2).
28
+ * Searches over this set must use the `pruningWide` table — the
29
+ * 23-move pruning distances are inadmissible here (they overestimate).
30
+ */
31
+ export declare const CENTER2_SEARCH_MOVES_WIDE: readonly Cube4Move[];
24
32
  /** The 6 reference goal rl patterns (full 70-space values, even parity). */
25
33
  export declare const CENTER2_GOAL_RL: readonly number[];
26
34
  export declare const CENTER2_CT_STATES = 6435;
@@ -34,9 +42,12 @@ export declare function wingPermutationParity(wp: Uint8Array): 0 | 1;
34
42
  /** Encode a full 4x4 state to the (ct, rl) coordinate (0..450,449). */
35
43
  export declare function encodeCenter2(state: Cube4State): Center2Encoded;
36
44
  export declare function isCenter2Goal(ct: number, rl: number): boolean;
45
+ export declare const ALIGNMENT_ROTATIONS: readonly (readonly string[])[];
37
46
  export interface Center2BridgeResult {
38
47
  /** Alignment moves (0-2). */
39
48
  alignment: Cube4Move[];
49
+ /** Alignment rotation sequence (0-1 rotations: [], ["z"], or ["y"]). */
50
+ rotation: string[];
40
51
  /** The aligned state (invariant). */
41
52
  state: Cube4State;
42
53
  /** The (ct, rl) coordinate of the aligned state. */
@@ -57,10 +68,39 @@ export interface Center2Tables {
57
68
  ctMove: Int32Array;
58
69
  /** 70 × 28 — rl rank (parity included) after each move. */
59
70
  rlMove: Int32Array;
60
- /** 450,450 exact BFS distances from the goal. */
71
+ /** 450,450 exact BFS distances from the goal (23-move set). */
61
72
  pruning: Uint8Array;
73
+ /**
74
+ * 450,450 exact BFS distances from the goal (wide 28-move set).
75
+ * Optional in memory (older assets); required for wide searches.
76
+ */
77
+ pruningWide?: Uint8Array | undefined;
62
78
  }
63
79
  export declare function generateCenter2Tables(): Center2Tables;
80
+ /**
81
+ * The ct rank above is RELATIVE to ct[15], so `ct == 0` accepts both
82
+ * assignments of the two non-R/L axes to the U/D and F/B face-pairs. Only
83
+ * one of them survives the downstream chirality gate (`axisDet`: the U, R, F
84
+ * axes must form a right-handed frame, i.e. U/D must hold axis (a + 2) % 3
85
+ * when R/L holds axis a). The chiral coordinate ranks the ABSOLUTE pattern
86
+ * "which of the 16 U/D/F/B positions hold the U/D-bound axis" (C(16,8) =
87
+ * 12,870) and its pruning measures the distance to the chirality-correct
88
+ * goals only, so the phase-2 search never walks wrong-chirality goal paths.
89
+ * Same goal set as `ct == 0 && axisDet == 1`; generated at runtime (~1.6 MB).
90
+ */
91
+ export declare const CENTER2_CHIRAL_CT_STATES = 12870;
92
+ export declare const CENTER2_CHIRAL_STATES: number;
93
+ export interface Center2ChiralTables {
94
+ /** 12,870 × 28 — chiral ct rank after each move. */
95
+ ctMove: Uint16Array;
96
+ /** 900,900 exact BFS distances to the chiral goals (23-move set). */
97
+ pruning: Uint8Array;
98
+ /** Chiral ct rank of the goal pattern (U/D positions all U/D-bound). */
99
+ goalCt: number;
100
+ }
101
+ /** Chiral ct rank of a coordinate-invariant (bridged) phase-2 state. */
102
+ export declare function encodeCenter2ChiralCt(state: Cube4State): number;
103
+ export declare function generateCenter2ChiralTables(rlMove: Int32Array): Center2ChiralTables;
64
104
  export interface Center2Phase2Result {
65
105
  /** Phase-2 solution moves (standard 4x4 moves). */
66
106
  moves: Cube4Move[];
@@ -77,6 +117,7 @@ export declare function solveCenter2(startCt: number, startRl: number, tables: C
77
117
  * (transversal + even wing permutation), which most states fail.
78
118
  */
79
119
  export declare function solveCenter2All(startCt: number, startRl: number, tables: Center2Tables, maxLength?: number, cap?: number): Center2Phase2Result[];
120
+ export declare function getWingMoveMaps(): Int32Array;
80
121
  /**
81
122
  * Solve Center 2 gated for an exact target length.
82
123
  */
@@ -87,5 +128,5 @@ export declare function solveCenter2GatedLength(startCt: number, startRl: number
87
128
  * transversal (the phase-3 entry gate).
88
129
  */
89
130
  export declare function solveCenter2Gated(startCt: number, startRl: number, startWp: Uint8Array, tables: Center2Tables, isGateEligible: (wp: Uint8Array) => boolean, maxLength?: number): Center2Phase2Result | null;
90
- export declare function verifyCenter2(tables: Center2Tables): string[];
131
+ export declare function verifyCenter2(tables: Center2Tables, pruning?: Uint8Array, moves?: readonly Cube4Move[]): string[];
91
132
  //# sourceMappingURL=center2.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"center2.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/center2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"center2.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/center2.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,9 @@
12
12
  * - goal: ct == 0 and rl in the 6 reference goal patterns (even parity);
13
13
  * - the 28-move set keeps the ct and rl position sets separate, so the move
14
14
  * tables factor: ctmv (6,435×28) and rlmv (70×28);
15
- * - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw').
15
+ * - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw')
16
+ * by default; the wide set (`CENTER2_SEARCH_MOVES_WIDE`, all 28, with
17
+ * the `pruningWide` table) additionally tries Dw2/Lw/Lw2/Lw'/Bw2.
16
18
  *
17
19
  * The phase-1 → phase-2 bridge (alignment + encode) is in `reduction.ts`.
18
20
  */
@@ -28,11 +30,23 @@ export const CENTER2_MOVES = [
28
30
  ];
29
31
  /** The search's exploration set (the first 23 of CENTER2_MOVES). */
30
32
  export const CENTER2_SEARCH_MOVES = CENTER2_MOVES.slice(0, 23);
33
+ /**
34
+ * The wide exploration set: all 28 moves (adds Dw2/Lw/Lw2/Lw'/Bw2).
35
+ * Searches over this set must use the `pruningWide` table — the
36
+ * 23-move pruning distances are inadmissible here (they overestimate).
37
+ */
38
+ export const CENTER2_SEARCH_MOVES_WIDE = CENTER2_MOVES;
31
39
  /** The 6 reference goal rl patterns (full 70-space values, even parity). */
32
40
  export const CENTER2_GOAL_RL = [0, 18, 28, 46, 54, 56];
33
41
  export const CENTER2_CT_STATES = 6435;
34
42
  export const CENTER2_RL_STATES = 70;
35
43
  export const CENTER2_STATES = CENTER2_CT_STATES * CENTER2_RL_STATES;
44
+ const CENTER2_GOAL_FLAGS = (() => {
45
+ const flags = new Uint8Array(CENTER2_RL_STATES);
46
+ for (const rl of CENTER2_GOAL_RL)
47
+ flags[rl] = 1;
48
+ return flags;
49
+ })();
36
50
  // ct positions: U(0-3), D(12-15), F(8-11), B(20-23) — the reference's face
37
51
  // order {U, D, F, B}, in this repo's face-major numbering.
38
52
  const CT_POS = [0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11, 20, 21, 22, 23];
@@ -96,7 +110,7 @@ export function encodeCenter2(state) {
96
110
  return { ct: ctRank, rl: rlRank };
97
111
  }
98
112
  export function isCenter2Goal(ct, rl) {
99
- return ct === 0 && CENTER2_GOAL_RL.includes(rl);
113
+ return ct === 0 && CENTER2_GOAL_FLAGS[rl] === 1;
100
114
  }
101
115
  /**
102
116
  * The phase-2 coordinate is only valid for states where exactly 8 of the
@@ -112,6 +126,11 @@ const ALIGNMENT_CANDIDATES = [
112
126
  ["Uw", "Dw'"]
113
127
  ];
114
128
  function center2InvariantDiffs(centers) {
129
+ const rlAxis = centers[RL_POS[7]] % 3;
130
+ for (let i = 0; i < 7; i++) {
131
+ if (centers[RL_POS[i]] % 3 !== rlAxis)
132
+ return { ctDiff: -1, rlDiff: -1 };
133
+ }
115
134
  let ctDiff = 0;
116
135
  let rlDiff = 0;
117
136
  for (let i = 0; i < 15; i++) {
@@ -124,12 +143,18 @@ function center2InvariantDiffs(centers) {
124
143
  }
125
144
  return { ctDiff, rlDiff };
126
145
  }
146
+ export const ALIGNMENT_ROTATIONS = [
147
+ [],
148
+ ["z"],
149
+ ["y"]
150
+ ];
127
151
  /**
128
152
  * Phase-1 → phase-2 bridge: apply the shortest alignment candidate that
129
153
  * makes the state coordinate-invariant, then encode.
130
154
  */
131
155
  export function center2Bridge(state) {
132
- for (const alignment of ALIGNMENT_CANDIDATES) {
156
+ for (let idx = 0; idx < ALIGNMENT_CANDIDATES.length; idx++) {
157
+ const alignment = ALIGNMENT_CANDIDATES[idx];
133
158
  const aligned = alignment.length === 0
134
159
  ? state
135
160
  : applyCube4Algorithm(state, alignment);
@@ -137,6 +162,7 @@ export function center2Bridge(state) {
137
162
  if (ctDiff === 8 && rlDiff === 4) {
138
163
  return {
139
164
  alignment: [...alignment],
165
+ rotation: [...ALIGNMENT_ROTATIONS[idx]],
140
166
  state: aligned,
141
167
  encoded: encodeCenter2(aligned)
142
168
  };
@@ -246,7 +272,123 @@ export function generateCenter2Tables() {
246
272
  }
247
273
  }
248
274
  }
249
- return { ctMove, rlMove, pruning };
275
+ // Wide pruning BFS: same goals, all 28 moves (exact distances for the
276
+ // wide search; the 23-move table overestimates there).
277
+ const pruningWide = new Uint8Array(CENTER2_STATES).fill(0xff);
278
+ const wideQueue = [];
279
+ for (const rl of CENTER2_GOAL_RL) {
280
+ pruningWide[rl] = 0;
281
+ wideQueue.push(rl);
282
+ }
283
+ let wideHead = 0;
284
+ while (wideHead < wideQueue.length) {
285
+ const idx = wideQueue[wideHead++];
286
+ const ct = Math.floor(idx / CENTER2_RL_STATES);
287
+ const rl = idx % CENTER2_RL_STATES;
288
+ const d = pruningWide[idx];
289
+ for (let m = 0; m < CENTER2_SEARCH_MOVES_WIDE.length; m++) {
290
+ const nextCt = ctMove[ct * CENTER2_MOVES.length + m];
291
+ const nextRl = rlMove[rl * CENTER2_MOVES.length + m];
292
+ const next = nextCt * CENTER2_RL_STATES + nextRl;
293
+ if (pruningWide[next] === 0xff) {
294
+ pruningWide[next] = d + 1;
295
+ wideQueue.push(next);
296
+ }
297
+ }
298
+ }
299
+ return { ctMove, rlMove, pruning, pruningWide };
300
+ }
301
+ // ---------------------------------------------------------------------------
302
+ // Chiral (absolute-ct) phase-2 tables
303
+ // ---------------------------------------------------------------------------
304
+ /**
305
+ * The ct rank above is RELATIVE to ct[15], so `ct == 0` accepts both
306
+ * assignments of the two non-R/L axes to the U/D and F/B face-pairs. Only
307
+ * one of them survives the downstream chirality gate (`axisDet`: the U, R, F
308
+ * axes must form a right-handed frame, i.e. U/D must hold axis (a + 2) % 3
309
+ * when R/L holds axis a). The chiral coordinate ranks the ABSOLUTE pattern
310
+ * "which of the 16 U/D/F/B positions hold the U/D-bound axis" (C(16,8) =
311
+ * 12,870) and its pruning measures the distance to the chirality-correct
312
+ * goals only, so the phase-2 search never walks wrong-chirality goal paths.
313
+ * Same goal set as `ct == 0 && axisDet == 1`; generated at runtime (~1.6 MB).
314
+ */
315
+ export const CENTER2_CHIRAL_CT_STATES = 12870;
316
+ export const CENTER2_CHIRAL_STATES = CENTER2_CHIRAL_CT_STATES * CENTER2_RL_STATES;
317
+ function rankSubset16(bits) {
318
+ let idx = 0;
319
+ let r = 8;
320
+ for (let i = 15; i >= 0 && r > 0; i--) {
321
+ if (bits[i] === 1) {
322
+ idx += CNK[i][r];
323
+ r--;
324
+ }
325
+ }
326
+ return idx;
327
+ }
328
+ function unrankSubset16(idx) {
329
+ const bits = new Uint8Array(16);
330
+ let r = 8;
331
+ for (let i = 15; i >= 0 && r > 0; i--) {
332
+ if (idx >= CNK[i][r]) {
333
+ idx -= CNK[i][r];
334
+ bits[i] = 1;
335
+ r--;
336
+ }
337
+ }
338
+ return bits;
339
+ }
340
+ /** Chiral ct rank of a coordinate-invariant (bridged) phase-2 state. */
341
+ export function encodeCenter2ChiralCt(state) {
342
+ const rlAxis = state.centers[RL_POS[0]] % 3;
343
+ const udAxis = (rlAxis + 2) % 3;
344
+ const bits = new Uint8Array(16);
345
+ for (let i = 0; i < 16; i++)
346
+ bits[i] = state.centers[CT_POS[i]] % 3 === udAxis ? 1 : 0;
347
+ return rankSubset16(bits);
348
+ }
349
+ export function generateCenter2ChiralTables(rlMove) {
350
+ const moveMaps = buildMovePositionMaps();
351
+ const nMoves = CENTER2_MOVES.length;
352
+ const ctMove = new Uint16Array(CENTER2_CHIRAL_CT_STATES * nMoves);
353
+ const full = new Uint8Array(24);
354
+ const bits = new Uint8Array(16);
355
+ for (let ct = 0; ct < CENTER2_CHIRAL_CT_STATES; ct++) {
356
+ const pattern = unrankSubset16(ct);
357
+ full.fill(0);
358
+ for (let i = 0; i < 16; i++)
359
+ full[CT_POS[i]] = pattern[i];
360
+ for (let m = 0; m < nMoves; m++) {
361
+ for (let i = 0; i < 16; i++)
362
+ bits[i] = full[moveMaps[m * 24 + CT_POS[i]]];
363
+ ctMove[ct * nMoves + m] = rankSubset16(bits);
364
+ }
365
+ }
366
+ const goalBits = new Uint8Array(16);
367
+ for (let i = 0; i < 8; i++)
368
+ goalBits[i] = 1; // CT_POS[0..7] = U and D faces
369
+ const goalCt = rankSubset16(goalBits);
370
+ const pruning = new Uint8Array(CENTER2_CHIRAL_STATES).fill(0xff);
371
+ const queue = new Int32Array(CENTER2_CHIRAL_STATES);
372
+ let tail = 0;
373
+ for (const rl of CENTER2_GOAL_RL) {
374
+ const idx = goalCt * CENTER2_RL_STATES + rl;
375
+ pruning[idx] = 0;
376
+ queue[tail++] = idx;
377
+ }
378
+ for (let head = 0; head < tail; head++) {
379
+ const idx = queue[head];
380
+ const ct = (idx / CENTER2_RL_STATES) | 0;
381
+ const rl = idx - ct * CENTER2_RL_STATES;
382
+ const d = pruning[idx] + 1;
383
+ for (let m = 0; m < CENTER2_SEARCH_MOVES.length; m++) {
384
+ const next = ctMove[ct * nMoves + m] * CENTER2_RL_STATES + rlMove[rl * nMoves + m];
385
+ if (pruning[next] === 0xff) {
386
+ pruning[next] = d;
387
+ queue[tail++] = next;
388
+ }
389
+ }
390
+ }
391
+ return { ctMove, pruning, goalCt };
250
392
  }
251
393
  // The reference's cancellation rule (ckmv over move2std): skip the same base
252
394
  // move, or the same axis-class when the previous move's standard index is
@@ -320,7 +462,7 @@ export function solveCenter2All(startCt, startRl, tables, maxLength = 40, cap =
320
462
  }
321
463
  }
322
464
  let cachedWingMaps = null;
323
- function getWingMoveMaps() {
465
+ export function getWingMoveMaps() {
324
466
  if (!cachedWingMaps) {
325
467
  cachedWingMaps = buildWingMoveMaps();
326
468
  }
@@ -421,24 +563,24 @@ function buildWingMoveMaps() {
421
563
  // ---------------------------------------------------------------------------
422
564
  // Verification gates
423
565
  // ---------------------------------------------------------------------------
424
- export function verifyCenter2(tables) {
566
+ export function verifyCenter2(tables, pruning = tables.pruning, moves = CENTER2_SEARCH_MOVES) {
425
567
  const errors = [];
426
568
  for (const rl of CENTER2_GOAL_RL) {
427
- if (tables.pruning[rl] !== 0) {
569
+ if (pruning[rl] !== 0) {
428
570
  errors.push(`Goal rl ${rl} must have pruning 0.`);
429
571
  }
430
572
  }
431
573
  let maxDepth = 0;
432
574
  for (let idx = 0; idx < CENTER2_STATES; idx++) {
433
- const d = tables.pruning[idx];
575
+ const d = pruning[idx];
434
576
  if (d > maxDepth)
435
577
  maxDepth = d;
436
578
  const ct = Math.floor(idx / CENTER2_RL_STATES);
437
579
  const rl = idx % CENTER2_RL_STATES;
438
- for (let m = 0; m < CENTER2_SEARCH_MOVES.length; m++) {
580
+ for (let m = 0; m < moves.length; m++) {
439
581
  const nc = tables.ctMove[ct * CENTER2_MOVES.length + m];
440
582
  const nr = tables.rlMove[rl * CENTER2_MOVES.length + m];
441
- const nd = tables.pruning[nc * CENTER2_RL_STATES + nr];
583
+ const nd = pruning[nc * CENTER2_RL_STATES + nr];
442
584
  if (nd < d - 1 || nd > d + 1) {
443
585
  errors.push(`Pruning inconsistency at ${idx} move ${CENTER2_MOVES[m]}: ${d} -> ${nd}.`);
444
586
  break;
@@ -80,6 +80,10 @@ export interface Edge3Tables {
80
80
  * `maxDepthCap` stops the BFS early (validation only).
81
81
  */
82
82
  export declare function generateEdge3Tables(maxDepthCap?: number): Edge3Tables;
83
+ /**
84
+ * Unpack 4-bit nibble-packed distances into a byte-expanded Uint8Array (1 byte per state).
85
+ */
86
+ export declare function unpackEdge3Distances(packed: Uint8Array): Uint8Array;
83
87
  /**
84
88
  * The distance lookup over a loaded distances buffer: builds the sym
85
89
  * machinery once (cached) and returns a closure from the std-form edge
@@ -1 +1 @@
1
- {"version":3,"file":"edge3.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/edge3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAWH,mEAAmE;AACnE,eAAO,MAAM,WAAW,WAAa,CAAC;AACtC,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,eAAO,MAAM,WAAW,QAAS,CAAC;AAGlC,qEAAqE;AACrE,eAAO,MAAM,eAAe,KAAK,CAAC;AAUlC,+EAA+E;AAC/E,eAAO,MAAM,SAAS,EAAE,SAAS,MAAM,EAEtC,CAAC;AAaF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAkCD;;;;;GAKG;AACH,iBAAS,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CA2G3E;AAkCD,iFAAiF;AACjF,iBAAS,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAO3E;AAMD;;;;GAIG;AACH,iBAAS,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,MAAM,CAS3E;AAED;;;GAGG;AACH,iBAAS,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAmBhD;AAOD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,WAAW,CAAC;IACtB,gDAAgD;IAChD,OAAO,EAAE,WAAW,CAAC;IACrB,iFAAiF;IACjF,QAAQ,EAAE,WAAW,CAAC;IACtB,qFAAqF;IACrF,OAAO,EAAE,WAAW,CAAC;CACtB;AAID,wBAAgB,YAAY,IAAI,SAAS,CAKxC;AAED,wBAAgB,cAAc,IAAI,SAAS,CAoE1C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CA6BR;AAMD,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,SAAS,EAAE,UAAU,CAAC;IACtB,0DAA0D;IAC1D,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,SAAK,GAAG,WAAW,CAkEjE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,UAAU,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CASvF;AAMD,uBAAuB;AACvB,wBAAgB,gBAAgB;;;;;;;EAE/B;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAgBzD"}
1
+ {"version":3,"file":"edge3.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/edge3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAWH,mEAAmE;AACnE,eAAO,MAAM,WAAW,WAAa,CAAC;AACtC,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,eAAO,MAAM,WAAW,QAAS,CAAC;AAGlC,qEAAqE;AACrE,eAAO,MAAM,eAAe,KAAK,CAAC;AAUlC,+EAA+E;AAC/E,eAAO,MAAM,SAAS,EAAE,SAAS,MAAM,EAEtC,CAAC;AAaF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAkCD;;;;;GAKG;AACH,iBAAS,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CA2G3E;AAkCD,iFAAiF;AACjF,iBAAS,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAO3E;AAMD;;;;GAIG;AACH,iBAAS,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,MAAM,CAS3E;AAED;;;GAGG;AACH,iBAAS,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAmBhD;AAOD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,WAAW,CAAC;IACtB,gDAAgD;IAChD,OAAO,EAAE,WAAW,CAAC;IACrB,iFAAiF;IACjF,QAAQ,EAAE,WAAW,CAAC;IACtB,qFAAqF;IACrF,OAAO,EAAE,WAAW,CAAC;CACtB;AAID,wBAAgB,YAAY,IAAI,SAAS,CAKxC;AAED,wBAAgB,cAAc,IAAI,SAAS,CAoE1C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CA6BR;AAMD,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,SAAS,EAAE,UAAU,CAAC;IACtB,0DAA0D;IAC1D,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,SAAK,GAAG,WAAW,CAmEjE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CASnE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,UAAU,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAWvF;AAMD,uBAAuB;AACvB,wBAAgB,gBAAgB;;;;;;;EAE/B;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAkBzD"}
@@ -468,8 +468,23 @@ export function generateEdge3Tables(maxDepthCap = -1) {
468
468
  frontier = next;
469
469
  depth++;
470
470
  }
471
- const distanceOfEdge = edge3DistanceLookup(distances);
472
- return { distances, distanceOfEdge };
471
+ const unpacked = unpackEdge3Distances(distances);
472
+ const distanceOfEdge = edge3DistanceLookup(unpacked);
473
+ return { distances: unpacked, distanceOfEdge };
474
+ }
475
+ /**
476
+ * Unpack 4-bit nibble-packed distances into a byte-expanded Uint8Array (1 byte per state).
477
+ */
478
+ export function unpackEdge3Distances(packed) {
479
+ if (packed.length >= EDGE3_TOTAL)
480
+ return packed;
481
+ const unpacked = new Uint8Array(EDGE3_TOTAL);
482
+ for (let i = 0; i < packed.length; i++) {
483
+ const b = packed[i];
484
+ unpacked[i << 1] = b & 0x0f;
485
+ unpacked[(i << 1) | 1] = b >> 4;
486
+ }
487
+ return unpacked;
473
488
  }
474
489
  /**
475
490
  * The distance lookup over a loaded distances buffer: builds the sym
@@ -480,9 +495,12 @@ export function edge3DistanceLookup(distances) {
480
495
  const t = symTables ?? buildSymTables();
481
496
  const { sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto } = t;
482
497
  const identity = Uint8Array.from({ length: 12 }, (_, i) => i);
498
+ const isUnpacked = distances.length >= EDGE3_TOTAL;
483
499
  return (e) => {
484
500
  const std = normalizePairingState(e, identity).edge;
485
501
  const idx = getMvSymFrom(std, identity, 20, sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto) >> 3;
502
+ if (isUnpacked)
503
+ return distances[idx];
486
504
  return (distances[idx >> 1] >> ((idx & 1) * 4)) & 0x0f;
487
505
  };
488
506
  }
@@ -500,8 +518,10 @@ export function verifyEdge3(tables) {
500
518
  errors.push("Solved state must have distance 0.");
501
519
  }
502
520
  let seen = 0;
521
+ const isUnpacked = tables.distances.length >= EDGE3_TOTAL;
503
522
  for (let i = 0; i < EDGE3_TOTAL; i++) {
504
- if (((tables.distances[i >> 1] >> ((i & 1) * 4)) & 0x0f) !== 0x0f)
523
+ const d = isUnpacked ? tables.distances[i] : ((tables.distances[i >> 1] >> ((i & 1) * 4)) & 0x0f);
524
+ if (d !== 0x0f)
505
525
  seen++;
506
526
  }
507
527
  if (seen !== EDGE3_TOTAL) {
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Continuous two-phase 3x3 solver for the 4x4 finish (Kociemba-style).
3
+ *
4
+ * Unlike the batch solver in `cube3/solver` (collect phase-1 solutions,
5
+ * then solve phase 2 for each), this is the classic continuous search: an
6
+ * iterative-deepening phase 1 where EVERY phase-1 solution immediately runs
7
+ * phase 2 under the remaining length budget, and every solution found
8
+ * tightens the bound for the rest of the search. Optional legal views are
9
+ * searched interleaved by phase-1 depth — up to 3 relabelled axes
10
+ * (identity, x, z) × {state, inverse} — which is what makes short solutions
11
+ * cheap to find (the existing cube3 solver's rotation/inverse trick).
12
+ *
13
+ * Tables: the already-loaded cube3 tables (phase-1: twist/flip/slice move
14
+ * tables + twist×flip, slice×twist, slice×flip pruning; phase-2: cp/ep/sp
15
+ * move tables + cp×sp, ep×sp pruning). Nothing is generated here.
16
+ *
17
+ * Deterministic: the only stopping rules are node counts and lengths, so
18
+ * the result is a pure function of (state, options).
19
+ */
20
+ import type { Cube3Move, Cube3State } from "../../cube3/types.js";
21
+ import { type Cube3Phase1Tables, type Cube3Phase2Tables } from "../../cube3/solver/tables.js";
22
+ export interface Finish3Tables {
23
+ phase1: Cube3Phase1Tables;
24
+ phase2: Cube3Phase2Tables;
25
+ }
26
+ export interface Finish3Options {
27
+ /** Stop as soon as a solution of at most this length is found (default 0 = never). */
28
+ targetLength?: number;
29
+ /**
30
+ * Node budget (phase-1 + phase-2 nodes) after which the best solution so
31
+ * far is returned (default 200_000). The search always runs until a first
32
+ * solution exists, bounded by `hardMaxNodes`.
33
+ */
34
+ maxNodes?: number;
35
+ /** Absolute node cap; exceeding it without any solution throws (default 20M). */
36
+ hardMaxNodes?: number;
37
+ /** Views searched: 1 (as is), 2 (+inverse), 6 (3 axes × inverse). */
38
+ views?: 1 | 2 | 6;
39
+ /** @deprecated Ignored: views are built by cubie conjugation. */
40
+ viewScramble?: readonly Cube3Move[];
41
+ /** Longest phase-2 segment considered (default 12). */
42
+ maxPhase2Length?: number;
43
+ }
44
+ export interface Finish3Result {
45
+ moves: Cube3Move[];
46
+ nodes: number;
47
+ }
48
+ export declare class Finish3SearchError extends Error {
49
+ readonly code: "cube4-finish3-cap";
50
+ constructor(message: string);
51
+ }
52
+ export declare function solveFinish3(state: Cube3State, tables: Finish3Tables, options?: Finish3Options): Finish3Result;
53
+ //# sourceMappingURL=finish3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finish3.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/finish3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAalE,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,8BAA8B,CAAC;AAMtC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClB,iEAAiE;IACjE,YAAY,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACpC,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAG,mBAAmB,CAAU;gBAEjC,OAAO,EAAE,MAAM;CAI5B;AAsKD,wBAAgB,YAAY,CAC1B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,cAAmB,GAC3B,aAAa,CAuMf"}