@cubingcenter/scrambler 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +2 -0
  2. package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
  3. package/dist/puzzles/cube2/solver/search.js +3 -3
  4. package/dist/puzzles/cube2/solver/tables.d.ts +6 -0
  5. package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
  6. package/dist/puzzles/cube2/solver/tables.js +16 -2
  7. package/dist/puzzles/cube3/index.d.ts +1 -0
  8. package/dist/puzzles/cube3/index.d.ts.map +1 -1
  9. package/dist/puzzles/cube3/moves.d.ts.map +1 -1
  10. package/dist/puzzles/cube3/moves.js +104 -18
  11. package/dist/puzzles/cube3/scrambler.d.ts +16 -1
  12. package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
  13. package/dist/puzzles/cube3/scrambler.js +1 -1
  14. package/dist/puzzles/cube3/solver/browser-loader.js +6 -2
  15. package/dist/puzzles/cube3/solver/index.d.ts +5 -3
  16. package/dist/puzzles/cube3/solver/index.d.ts.map +1 -1
  17. package/dist/puzzles/cube3/solver/index.js +2 -1
  18. package/dist/puzzles/cube3/solver/node-loader.js +9 -2
  19. package/dist/puzzles/cube3/solver/phase1.d.ts +18 -0
  20. package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
  21. package/dist/puzzles/cube3/solver/phase1.js +132 -14
  22. package/dist/puzzles/cube3/solver/phase2.d.ts +47 -0
  23. package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
  24. package/dist/puzzles/cube3/solver/phase2.js +236 -66
  25. package/dist/puzzles/cube3/solver/search-utils.d.ts +1 -1
  26. package/dist/puzzles/cube3/solver/search-utils.d.ts.map +1 -1
  27. package/dist/puzzles/cube3/solver/symmetry.d.ts +24 -0
  28. package/dist/puzzles/cube3/solver/symmetry.d.ts.map +1 -0
  29. package/dist/puzzles/cube3/solver/symmetry.js +74 -0
  30. package/dist/puzzles/cube3/solver/tables.d.ts +6 -1
  31. package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
  32. package/dist/puzzles/cube3/validation.d.ts.map +1 -1
  33. package/dist/puzzles/cube3/validation.js +15 -7
  34. package/dist/puzzles/cube4/index.d.ts +3 -2
  35. package/dist/puzzles/cube4/index.d.ts.map +1 -1
  36. package/dist/puzzles/cube4/index.js +2 -2
  37. package/dist/puzzles/cube4/moves.d.ts +5 -0
  38. package/dist/puzzles/cube4/moves.d.ts.map +1 -1
  39. package/dist/puzzles/cube4/moves.js +120 -11
  40. package/dist/puzzles/cube4/reduction/browser-loader.d.ts +3 -0
  41. package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
  42. package/dist/puzzles/cube4/reduction/browser-loader.js +34 -3
  43. package/dist/puzzles/cube4/reduction/center2.d.ts +20 -3
  44. package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
  45. package/dist/puzzles/cube4/reduction/center2.js +53 -9
  46. package/dist/puzzles/cube4/reduction/edge3.d.ts +4 -0
  47. package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -1
  48. package/dist/puzzles/cube4/reduction/edge3.js +23 -3
  49. package/dist/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
  50. package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
  51. package/dist/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
  52. package/dist/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
  53. package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
  54. package/dist/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
  55. package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +50 -0
  56. package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -0
  57. package/dist/puzzles/cube4/reduction/hc-pdb.js +202 -0
  58. package/dist/puzzles/cube4/reduction/node-loader.d.ts +5 -0
  59. package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
  60. package/dist/puzzles/cube4/reduction/node-loader.js +48 -8
  61. package/dist/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
  62. package/dist/puzzles/cube4/reduction/phase3-search.d.ts +111 -5
  63. package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
  64. package/dist/puzzles/cube4/reduction/phase3-search.js +341 -22
  65. package/dist/puzzles/cube4/reduction/solve.d.ts +112 -1
  66. package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
  67. package/dist/puzzles/cube4/reduction/solve.js +920 -181
  68. package/dist/puzzles/cube4/scrambler.d.ts +105 -4
  69. package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
  70. package/dist/puzzles/cube4/scrambler.js +221 -161
  71. package/dist/puzzles/cube4/state.d.ts.map +1 -1
  72. package/dist/puzzles/cube4/state.js +4 -1
  73. package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -1
  74. package/dist/puzzles/pyraminx/solver/search.js +3 -6
  75. package/dist/puzzles/pyraminx/solver/tables.d.ts +6 -0
  76. package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -1
  77. package/dist/puzzles/pyraminx/solver/tables.js +17 -0
  78. package/dist/puzzles/skewb/solver/search.js +3 -3
  79. package/dist/puzzles/skewb/solver/tables.d.ts +6 -0
  80. package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
  81. package/dist/puzzles/skewb/solver/tables.js +17 -0
  82. package/dist-cjs/puzzles/cube2/solver/search.js +2 -2
  83. package/dist-cjs/puzzles/cube2/solver/tables.js +17 -3
  84. package/dist-cjs/puzzles/cube3/moves.js +104 -18
  85. package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
  86. package/dist-cjs/puzzles/cube3/solver/browser-loader.js +6 -2
  87. package/dist-cjs/puzzles/cube3/solver/index.js +8 -1
  88. package/dist-cjs/puzzles/cube3/solver/node-loader.js +9 -2
  89. package/dist-cjs/puzzles/cube3/solver/phase1.js +133 -14
  90. package/dist-cjs/puzzles/cube3/solver/phase2.js +233 -63
  91. package/dist-cjs/puzzles/cube3/solver/symmetry.js +80 -0
  92. package/dist-cjs/puzzles/cube3/validation.js +15 -7
  93. package/dist-cjs/puzzles/cube4/index.js +3 -1
  94. package/dist-cjs/puzzles/cube4/moves.js +121 -11
  95. package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +34 -3
  96. package/dist-cjs/puzzles/cube4/reduction/center2.js +54 -9
  97. package/dist-cjs/puzzles/cube4/reduction/edge3.js +24 -3
  98. package/dist-cjs/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
  99. package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
  100. package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
  101. package/dist-cjs/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
  102. package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
  103. package/dist-cjs/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
  104. package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +213 -0
  105. package/dist-cjs/puzzles/cube4/reduction/node-loader.js +48 -8
  106. package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
  107. package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +343 -23
  108. package/dist-cjs/puzzles/cube4/reduction/solve.js +918 -173
  109. package/dist-cjs/puzzles/cube4/scrambler.js +219 -158
  110. package/dist-cjs/puzzles/cube4/state.js +4 -1
  111. package/dist-cjs/puzzles/pyraminx/solver/search.js +2 -5
  112. package/dist-cjs/puzzles/pyraminx/solver/tables.js +18 -1
  113. package/dist-cjs/puzzles/skewb/solver/search.js +2 -2
  114. package/dist-cjs/puzzles/skewb/solver/tables.js +18 -1
  115. package/package.json +14 -5
@@ -3,13 +3,114 @@
3
3
  * the reduction solver (phases 1-4), and invert the solution. The scramble
4
4
  * always reproduces the sampled target state and facelets exactly.
5
5
  *
6
- * If the solver fails after 5 attempts it falls back to cubing.js
7
- * `randomScrambleForEvent("444")` (also random-state). If that also fails,
8
- * a WCA-compatible random-moves sequence (40 moves) is returned.
6
+ * Reduction-only, no resampling: each call runs one round of up to `bestOf`
7
+ * independent attempts and returns the shortest success (ties keep the
8
+ * lowest job index). If every attempt fails, the last error is thrown.
9
9
  */
10
10
  import type { ScrambleGenerator, ScrambleOptions, ScrambleResult } from "../../core/index.js";
11
11
  export declare const cube4ScrambleGenerator: ScrambleGenerator;
12
- export declare function generateCube4Scramble(options?: ScrambleOptions & {
12
+ /**
13
+ * 444-specific scramble options (pass-through; extra keys are ignored by
14
+ * the generic `generateScramble` API surface).
15
+ */
16
+ export interface Cube4ScrambleOptions {
17
+ /**
18
+ * Number of reduction passes to run on the SAME sampled state (alias for `restarts`).
19
+ * `1` (default): single deterministic pass.
20
+ * Higher values reshuffle the search traversal order on the same physical cube,
21
+ * returning the shortest valid scramble while strictly preserving uniform random-state
22
+ * distribution (WCA compliant).
23
+ */
24
+ bestOf?: number;
25
+ /**
26
+ * Last-resort effort for hard states: widens every solver work cap
27
+ * (phase-2 depth/nodes, phase-3 budgets/lengths, pool caps).
28
+ * Default false — the fast caps solve essentially everything at the
29
+ * same length (measured: identical totals on 54 states, ~-19% time),
30
+ * and a failed fast attempt automatically retries with `deep: true`
31
+ * (bestOf 1), so hard states still resolve.
32
+ */
33
+ deep?: boolean;
34
+ /**
35
+ * Search all 3 axial views (UD, RL, FB) of the same physical cube.
36
+ * Shaves ~1-2 moves on average without resampling.
37
+ */
38
+ threeAxes?: boolean;
39
+ /**
40
+ * Phase-4 attempts among valid reductions (default centersBeam * edgesPerCenter, i.e. 9).
41
+ * Passed through to the reduction solver: the first N reductions each get a 3x3
42
+ * finish and the shortest simplified total wins.
43
+ */
44
+ finishTries?: number;
45
+ /**
46
+ * Number of distinct center candidates from phase 2 to explore in phase 3
47
+ * (default 3). Part of hierarchical beam search.
48
+ */
49
+ centersBeam?: number;
50
+ /**
51
+ * Maximum number of distinct edge pairings to collect per center candidate
52
+ * in phase 3 (default 3). Part of hierarchical beam search.
53
+ */
54
+ edgesPerCenter?: number;
55
+ /**
56
+ * F1 enumeration slack beyond the per-axis optimum (default 3) and
57
+ * collection cap (default 60). Passed through to the reduction
58
+ * solver. Reversible A/B knob for the diversity-vs-length trade-off
59
+ * of phase 1.
60
+ */
61
+ phase1ExtraDepths?: number;
62
+ phase1Cap?: number;
63
+ /**
64
+ * Phase-2 wide move set: search all 28 center2 moves (adds
65
+ * Dw2/Lw/Lw2/Lw'/Bw2) instead of the default 23. Default false
66
+ * (measured ~-0.2 moves for ~+15% time on typical states; opt-in).
67
+ * Caution: on some hard states the wider branching can blow a single
68
+ * attempt past 100 s (no in-search cancellation), delaying every later
69
+ * bestOf job — prefer `restarts` for length.
70
+ */
71
+ center2Wide?: boolean;
72
+ /**
73
+ * Deep multi-candidate polish pass in phase 3 (top-3 reductions).
74
+ * Defaults to the value of `threeAxes`.
75
+ */
76
+ deepPolish?: boolean;
77
+ /**
78
+ * Full-pipeline restarts over the SAME sampled state (default 1).
79
+ * Passed through to the reduction solver: each restart reshuffles the
80
+ * search order deterministically and the shortest total wins.
81
+ * Same-state diversity (uniformity-preserving), unlike `bestOf`.
82
+ */
83
+ restarts?: number;
84
+ /**
85
+ * Tuning for the 3x3 finish (cube3 two-phase solver). All fields fall
86
+ * back to the production defaults, which prioritize short finishes:
87
+ * `orientations: 6`, `phase1ExtraDepth: 1`, `phase1SolutionLimit: 48`,
88
+ * `targetLength: 17`, budgets 350/100 ms with one 600/150 ms retry.
89
+ * A cheaper finish (e.g. `orientations: 3`, `phase1SolutionLimit: 24`)
90
+ * is much faster per call at a small length cost — the finish runs
91
+ * dozens of times per attempt, so this dominates attempt latency.
92
+ */
93
+ finish?: {
94
+ orientations?: number;
95
+ phase1ExtraDepth?: number;
96
+ phase1SolutionLimit?: number;
97
+ targetLength?: number;
98
+ timeoutMs?: number;
99
+ phase2TimeoutMs?: number;
100
+ retryTimeoutMs?: number;
101
+ retryPhase2TimeoutMs?: number;
102
+ };
103
+ }
104
+ export declare function generateCube4Scramble(options?: ScrambleOptions & Cube4ScrambleOptions & {
105
+ skipValidation?: boolean;
106
+ }): Promise<ScrambleResult>;
107
+ /**
108
+ * Single-attempt 444 solve: samples ONE state (from `options.seed`) and
109
+ * solves it with the reduction solver. Throws on failure — no resampling.
110
+ * Fan-out primitive for hosts: run with seeds `seed`, `seed:bestN`, ...
111
+ * across workers and keep the shortest valid result.
112
+ */
113
+ export declare function generateCube4Attempt(tables: any, pairTables: any, options?: ScrambleOptions & Cube4ScrambleOptions & {
13
114
  skipValidation?: boolean;
14
115
  }): Promise<ScrambleResult>;
15
116
  //# sourceMappingURL=scrambler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube4/scrambler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAmJ9F,eAAO,MAAM,sBAAsB,EAAE,iBAYpC,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CAyFzB"}
1
+ {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube4/scrambler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAiD9F,eAAO,MAAM,sBAAsB,EAAE,iBAYpC,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE;QACP,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;CACH;AAuCD,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,eAAe,GAAG,oBAAoB,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAClF,OAAO,CAAC,cAAc,CAAC,CA+CzB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,GAAG,EACX,UAAU,EAAE,GAAG,EACf,OAAO,GAAE,eAAe,GAAG,oBAAoB,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAClF,OAAO,CAAC,cAAc,CAAC,CAgKzB"}
@@ -3,104 +3,18 @@
3
3
  * the reduction solver (phases 1-4), and invert the solution. The scramble
4
4
  * always reproduces the sampled target state and facelets exactly.
5
5
  *
6
- * If the solver fails after 5 attempts it falls back to cubing.js
7
- * `randomScrambleForEvent("444")` (also random-state). If that also fails,
8
- * a WCA-compatible random-moves sequence (40 moves) is returned.
6
+ * Reduction-only, no resampling: each call runs one round of up to `bestOf`
7
+ * independent attempts and returns the shortest success (ties keep the
8
+ * lowest job index). If every attempt fails, the last error is thrown.
9
9
  */
10
- import { formatCube4Algorithm, applyCube4Algorithm } from "./moves.js";
10
+ import { formatCube4Algorithm, applyCube4Algorithm, invertCube4Algorithm } from "./moves.js";
11
11
  import { generateRandomCube4State } from "./random-state.js";
12
- import { createSolvedCube4State, cube4StatesEqual } from "./state.js";
12
+ import { createSolvedCube4State, isSolvedCube4State } from "./state.js";
13
13
  import { formatCube4Facelets, toCube4Facelets } from "./facelets.js";
14
- import { solveCube4State } from "./reduction/solve.js";
14
+ import { solveCube4State, applyCubeRotation, rotateAlgorithm } from "./reduction/solve.js";
15
15
  import { solveCube3State } from "../cube3/solver/index.js";
16
- import { createRandomSource } from "../../random/index.js";
17
- // ────────────────────────────────────────────────────────────
18
- // cubing.js fallback (random-state, WCA-compliant)
19
- // ────────────────────────────────────────────────────────────
20
- /**
21
- * Try to generate a 4x4 scramble using cubing.js `randomScrambleForEvent`.
22
- * Uses a dynamic import so browser bundles can tree-shake it when unused.
23
- * Returns null if cubing.js is unavailable.
24
- */
25
- async function generateCube4WithCubingJs() {
26
- try {
27
- const { randomScrambleForEvent } = await import(
28
- /* webpackIgnore: true */
29
- /* @vite-ignore */
30
- "cubing/scramble");
31
- const alg = await randomScrambleForEvent("444");
32
- const scramble = alg.toString();
33
- const moves = scramble.trim().split(/\s+/);
34
- return {
35
- eventId: "444",
36
- scramble,
37
- moves,
38
- quality: "random-state",
39
- generator: "cubing-js",
40
- metadata: {
41
- generator: "cubing-js",
42
- distribution: "random-state",
43
- note: "Generated by cubing.js randomScrambleForEvent as fallback."
44
- }
45
- };
46
- }
47
- catch {
48
- return null;
49
- }
50
- }
51
- // ────────────────────────────────────────────────────────────
52
- // Last-resort: random-moves (no external dep, always works)
53
- // ────────────────────────────────────────────────────────────
54
- const CUBE4_FACES = ["U", "R", "F", "D", "L", "B"];
55
- // Opposite face indices (U↔D, R↔L, F↔B)
56
- const CUBE4_OPPOSITE = { U: "D", D: "U", R: "L", L: "R", F: "B", B: "F" };
57
- const CUBE4_SUFFIXES = ["", "2", "'"];
58
- const CUBE4_WIDE_FACES = ["Uw", "Rw", "Fw", "Dw", "Lw", "Bw"];
59
- // Opposite wide-move faces
60
- const CUBE4_WIDE_OPPOSITE = {
61
- Uw: "Dw", Dw: "Uw", Rw: "Lw", Lw: "Rw", Fw: "Bw", Bw: "Fw"
62
- };
63
- // All available move bases (outer + wide). Outer and wide turns are treated
64
- // independently for the same-face/opposite-face check using their base letter.
65
- const ALL_MOVE_BASES = [...CUBE4_FACES, ...CUBE4_WIDE_FACES];
66
- function generateCube4RandomMoves(options = {}) {
67
- const rng = createRandomSource(options.seed);
68
- const moveCount = 40;
69
- const moves = [];
70
- let lastFace = null;
71
- let secondLastFace = null;
72
- const getBaseLetter = (face) => face.length > 1 ? face[0] : face;
73
- for (let i = 0; i < moveCount; i++) {
74
- let face;
75
- // Reject same face as last or opposite face when the last two moves
76
- // share the same axis (to avoid redundant move pairs like R L R).
77
- do {
78
- face = ALL_MOVE_BASES[rng.nextInt(ALL_MOVE_BASES.length)];
79
- } while (face === lastFace ||
80
- (lastFace !== null &&
81
- (CUBE4_OPPOSITE[face] === lastFace || CUBE4_WIDE_OPPOSITE[face] === lastFace) &&
82
- secondLastFace !== null &&
83
- getBaseLetter(secondLastFace) === getBaseLetter(face)));
84
- const suffix = CUBE4_SUFFIXES[rng.nextInt(3)];
85
- moves.push(`${face}${suffix}`);
86
- secondLastFace = lastFace;
87
- lastFace = face;
88
- }
89
- const scramble = moves.join(" ");
90
- return {
91
- eventId: "444",
92
- scramble,
93
- moves,
94
- quality: "random-moves",
95
- generator: "cube4-random-moves-fallback",
96
- metadata: {
97
- generator: "cube4-random-moves-fallback",
98
- distribution: "random-moves",
99
- note: "Reduction solver and cubing.js both failed; using random-moves.",
100
- ...options.metadata
101
- }
102
- };
103
- }
16
+ import { loadCube3Phase1Tables } from "../cube3/solver/tables.js";
17
+ import { loadCube3PairTables } from "../cube3/solver/pair-tables.js";
104
18
  // ────────────────────────────────────────────────────────────
105
19
  let cachedTables;
106
20
  async function loadCube4Tables(baseUrl) {
@@ -140,88 +54,234 @@ export const cube4ScrambleGenerator = {
140
54
  puzzle: "cube-4x4",
141
55
  quality: "random-state",
142
56
  generator: "cube4-reduction",
143
- description: "Random-state 4x4 scramble via the reduction solver (centers + pairing + 3x3 finish). Falls back to random-moves if the solver fails."
57
+ description: "Random-state 4x4 scramble via the reduction solver (centers + pairing + 3x3 finish)."
144
58
  },
145
59
  generate(options = {}) {
146
60
  return generateCube4Scramble(options);
147
61
  }
148
62
  };
63
+ function invertRotationSequence(rotSeq) {
64
+ return rotSeq.slice().reverse().map((r) => (r.endsWith("'") ? r.slice(0, -1) : r.endsWith("2") ? r : `${r}'`));
65
+ }
66
+ /** Shortest-first pick (ties keep `a`, i.e. the lowest job index). */
67
+ function shorterScramble(a, b) {
68
+ if (!a || b.moves.length < a.moves.length)
69
+ return b;
70
+ return a;
71
+ }
72
+ function seedForBestJob(options, job) {
73
+ if (job === 0)
74
+ return options;
75
+ const next = { ...options };
76
+ if (options.seed !== undefined) {
77
+ next.seed = `${options.seed}:best${job}`;
78
+ }
79
+ else {
80
+ delete next.seed;
81
+ }
82
+ return next;
83
+ }
84
+ function isRetryableCube4Error(error) {
85
+ const msg = error instanceof Error ? error.message : String(error);
86
+ const isPhase2Error = typeof error?.name === "string" &&
87
+ error.name.includes("Cube3Phase2");
88
+ return (error instanceof Error &&
89
+ (msg.includes("reduction failed") ||
90
+ msg.includes("failed to convert") ||
91
+ msg.includes("no valid phase 2") ||
92
+ msg.includes("timeout") ||
93
+ isPhase2Error ||
94
+ msg.includes("Phase 2 solution not found")));
95
+ }
149
96
  export async function generateCube4Scramble(options = {}) {
150
- const tables = await loadCube4Tables();
97
+ const bestOf = Math.max(1, Math.floor(options.bestOf ?? 1) || 1);
98
+ let tables;
99
+ let pairTables;
100
+ try {
101
+ const [loadedTables, cube3P1Tables, loadedPairTables] = await Promise.all([
102
+ loadCube4Tables(),
103
+ loadCube3Phase1Tables(),
104
+ loadCube3PairTables()
105
+ ]);
106
+ tables = loadedTables;
107
+ tables.cube3Phase1 = cube3P1Tables;
108
+ tables.pairTables = loadedPairTables;
109
+ pairTables = loadedPairTables;
110
+ }
111
+ catch (error) {
112
+ throw new Error("[cube4-scrambler] Failed to load reduction tables; run pnpm cube4:center1:tables etc. " +
113
+ `(${error instanceof Error ? error.message : String(error)})`);
114
+ }
115
+ const totalRestarts = Math.max(1, Math.floor(options.restarts ?? options.bestOf ?? 1) || 1);
151
116
  let lastError;
152
- // Retry with different states if the solver fails to find a physical
153
- // reduction (some random states are outside the solver's effective
154
- // horizon with the current candidate/length caps).
155
- for (let attempt = 0; attempt < 5; attempt++) {
156
- let attemptOptions;
157
- if (attempt === 0) {
158
- attemptOptions = options;
117
+ try {
118
+ return await generateCube4Attempt(tables, pairTables, {
119
+ ...options,
120
+ restarts: totalRestarts
121
+ });
122
+ }
123
+ catch (error) {
124
+ if (!isRetryableCube4Error(error))
125
+ throw error;
126
+ lastError = error;
127
+ }
128
+ if (!options.deep) {
129
+ try {
130
+ return await generateCube4Attempt(tables, pairTables, {
131
+ ...options,
132
+ restarts: totalRestarts,
133
+ deep: true
134
+ });
159
135
  }
160
- else {
161
- attemptOptions = { ...options };
162
- if (options.seed !== undefined) {
163
- attemptOptions.seed = `${options.seed}:retry${attempt}`;
164
- }
165
- else {
166
- delete attemptOptions.seed;
167
- }
136
+ catch (error) {
137
+ if (isRetryableCube4Error(error))
138
+ lastError = error;
139
+ else
140
+ throw error;
168
141
  }
169
- const attemptState = generateRandomCube4State(attemptOptions);
142
+ }
143
+ throw lastError instanceof Error
144
+ ? lastError
145
+ : new Error(`[cube4-scrambler] Reduction solver failed for restarts=${totalRestarts}: ${String(lastError)}`);
146
+ }
147
+ /**
148
+ * Single-attempt 444 solve: samples ONE state (from `options.seed`) and
149
+ * solves it with the reduction solver. Throws on failure — no resampling.
150
+ * Fan-out primitive for hosts: run with seeds `seed`, `seed:bestN`, ...
151
+ * across workers and keep the shortest valid result.
152
+ */
153
+ export async function generateCube4Attempt(tables, pairTables, options = {}) {
154
+ const attemptState = generateRandomCube4State(options);
155
+ const axes = options.threeAxes ? [[], ["z"], ["y'"]] : [[]];
156
+ let bestScrambleMoves = null;
157
+ let bestSolutionMoves = null;
158
+ let bestPhases;
159
+ let bestNodes;
160
+ let bestTimings;
161
+ let bestReductionLen;
162
+ let lastError;
163
+ const tAttemptStart = performance.now();
164
+ const finishOpts = options.finish ?? {};
165
+ for (const rot of axes) {
170
166
  try {
171
- const solvePromise = solveCube4State(attemptState, tables, (cube3State) => solveCube3State(cube3State));
172
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("4x4 solve: timeout")), 20000));
173
- const { scramble: scrambleMoves } = await Promise.race([solvePromise, timeoutPromise]);
174
- if (!options.skipValidation) {
175
- const scrambledState = applyCube4Algorithm(createSolvedCube4State(), scrambleMoves);
176
- if (!cube4StatesEqual(scrambledState, attemptState)) {
177
- throw new Error("Generated 4x4 scramble does not reproduce the target random state.");
167
+ const sRot = rot.length === 0 ? attemptState : applyCubeRotation(attemptState, rot);
168
+ // The reduction search is bounded by deterministic work caps (see
169
+ // solve.ts), so these timeouts are only wall-clock backstops for
170
+ // pathological cases.
171
+ const solvePromise = solveCube4State(sRot, tables, async (cube3State) => {
172
+ // Single solver-side best-of-orientations finish call with
173
+ // extra phase-1 improvement: same lengths as the former
174
+ // hand-rolled UD/X/Z triple at a fraction of the cost.
175
+ const solveFinish = async (timeBudget, phase2Budget) => {
176
+ const solution = await solveCube3State(cube3State, {
177
+ orientations: finishOpts.orientations ?? 3,
178
+ phase1ExtraDepth: finishOpts.phase1ExtraDepth ?? 1,
179
+ phase1SolutionLimit: finishOpts.phase1SolutionLimit ?? 24,
180
+ targetLength: finishOpts.targetLength ?? 20,
181
+ timeoutMs: timeBudget,
182
+ // The 54MB pair tables are skipped for the 444 finish: pair
183
+ // pruning changes nothing measurable here (identical lengths
184
+ // on a 44-state corpus, zero extra finish retries), and
185
+ // loading them dominates cold-start I/O. Hosts that already
186
+ // hold pairTables can still pass them via generateCube4Attempt.
187
+ phase2: { pairTables, skipPairTables: pairTables === undefined, timeoutMs: phase2Budget }
188
+ });
189
+ return { moves: solution.moves };
190
+ };
191
+ // The first call seeds everything, so a flaky finish gets one
192
+ // budgeted retry before the whole finish is declared failed.
193
+ try {
194
+ return await solveFinish(finishOpts.timeoutMs ?? 150, finishOpts.phase2TimeoutMs ?? 50);
195
+ }
196
+ catch {
197
+ return await solveFinish(finishOpts.retryTimeoutMs ?? 300, finishOpts.retryPhase2TimeoutMs ?? 100);
178
198
  }
199
+ }, {
200
+ timeoutMs: 75000,
201
+ deep: options.deep === true,
202
+ deepPolish: options.deepPolish ?? options.threeAxes,
203
+ ...(options.finishTries !== undefined ? { finishTries: options.finishTries } : {}),
204
+ ...(options.centersBeam !== undefined ? { centersBeam: options.centersBeam } : {}),
205
+ ...(options.edgesPerCenter !== undefined ? { edgesPerCenter: options.edgesPerCenter } : {}),
206
+ ...(options.phase1ExtraDepths !== undefined ? { phase1ExtraDepths: options.phase1ExtraDepths } : {}),
207
+ ...(options.phase1Cap !== undefined ? { phase1Cap: options.phase1Cap } : {}),
208
+ ...(options.center2Wide !== undefined ? { center2Wide: options.center2Wide } : {}),
209
+ ...(options.restarts !== undefined ? { restarts: options.restarts } : {}),
210
+ ...(options.prepCap !== undefined ? { prepCap: options.prepCap } : {}),
211
+ ...(options.p1CandCap !== undefined ? { p1CandCap: options.p1CandCap } : {}),
212
+ ...(options.stagnationCut !== undefined ? { stagnationCut: options.stagnationCut } : {}),
213
+ maxReductionLen: bestReductionLen
214
+ });
215
+ let timeoutHandle;
216
+ const timeoutPromise = new Promise((_, reject) => {
217
+ timeoutHandle = setTimeout(() => reject(new Error("4x4 solve: timeout")), 90000);
218
+ });
219
+ let solveOutcome;
220
+ try {
221
+ solveOutcome = await Promise.race([solvePromise, timeoutPromise]);
222
+ }
223
+ finally {
224
+ // The search is work-capped and always settles first: clearing the
225
+ // backstop avoids leaking a live 90s timer per axis (which kept the
226
+ // event loop — and CLI/test processes — alive needlessly).
227
+ clearTimeout(timeoutHandle);
179
228
  }
180
- const facelets = toCube4Facelets(attemptState);
181
- const result = {
182
- eventId: "444",
183
- scramble: formatCube4Algorithm(scrambleMoves),
184
- moves: scrambleMoves,
185
- quality: "random-state",
186
- generator: "cube4-reduction",
187
- metadata: {
188
- generator: "cube4-reduction",
189
- state: attemptState,
190
- facelets,
191
- faceletString: formatCube4Facelets(facelets),
192
- distribution: "random-state",
193
- ...options.metadata
229
+ const { scramble: scrambleMoves, moves: solutionMoves, phases, timings, nodes } = solveOutcome;
230
+ const invRot = rot.length === 0 ? [] : invertRotationSequence(rot);
231
+ const fullScramble = rot.length === 0 ? scrambleMoves : rotateAlgorithm(scrambleMoves, invRot);
232
+ const fullSolution = rot.length === 0 ? solutionMoves : rotateAlgorithm(solutionMoves, invRot);
233
+ if (!bestScrambleMoves || fullScramble.length < bestScrambleMoves.length) {
234
+ bestScrambleMoves = fullScramble;
235
+ bestSolutionMoves = fullSolution;
236
+ bestPhases = phases;
237
+ bestTimings = timings;
238
+ bestNodes = nodes;
239
+ if (phases) {
240
+ bestReductionLen = phases.length12 + phases.length3;
194
241
  }
195
- };
196
- if (options.seed !== undefined) {
197
- result.seed = options.seed;
198
242
  }
199
- return result;
200
243
  }
201
- catch (error) {
202
- lastError = error;
203
- // Retry on deterministic reduction / 3x3 failures (some random states are
204
- // outside the solver's horizon with the current caps).
205
- const msg = error instanceof Error ? error.message : String(error);
206
- const isPhase2Error = typeof error?.name === "string" &&
207
- error.name.includes("Cube3Phase2");
208
- if (error instanceof Error &&
209
- (msg.includes("reduction failed") ||
210
- msg.includes("failed to convert") ||
211
- msg.includes("no valid phase 2") ||
212
- msg.includes("timeout") ||
213
- isPhase2Error ||
214
- msg.includes("Phase 2 solution not found"))) {
215
- continue;
216
- }
217
- throw error;
244
+ catch (err) {
245
+ lastError = err;
246
+ }
247
+ }
248
+ if (!bestScrambleMoves || !bestSolutionMoves) {
249
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
250
+ }
251
+ const scrambleMoves = bestScrambleMoves;
252
+ const solutionMoves = bestSolutionMoves;
253
+ const scrambledState = applyCube4Algorithm(createSolvedCube4State(), scrambleMoves);
254
+ if (!options.skipValidation) {
255
+ const solvedCheck = applyCube4Algorithm(scrambledState, solutionMoves);
256
+ if (!isSolvedCube4State(solvedCheck)) {
257
+ throw new Error("Generated 4x4 scramble does not solve back to solved state.");
258
+ }
259
+ }
260
+ const facelets = toCube4Facelets(scrambledState);
261
+ const result = {
262
+ eventId: "444",
263
+ scramble: formatCube4Algorithm(scrambleMoves),
264
+ moves: scrambleMoves,
265
+ quality: "random-state",
266
+ generator: "cube4-reduction",
267
+ metadata: {
268
+ generator: "cube4-reduction",
269
+ state: scrambledState,
270
+ facelets,
271
+ faceletString: formatCube4Facelets(facelets),
272
+ distribution: "random-state",
273
+ solutionMoves: invertCube4Algorithm(scrambleMoves),
274
+ // Winning-reduction breakdown (unsimplified lengths) + wall-clock
275
+ // split, for tuning and A/B comparisons.
276
+ phases: bestPhases,
277
+ phaseTimings: bestTimings,
278
+ nodes: bestNodes,
279
+ attemptMs: performance.now() - tAttemptStart,
280
+ ...options.metadata
218
281
  }
282
+ };
283
+ if (options.seed !== undefined) {
284
+ result.seed = options.seed;
219
285
  }
220
- // All solver attempts exhausted — try cubing.js first, then random-moves.
221
- console.warn("[cube4-scrambler] Reduction solver failed after 5 attempts; trying cubing.js fallback.", lastError);
222
- const cubingJsResult = await generateCube4WithCubingJs();
223
- if (cubingJsResult)
224
- return cubingJsResult;
225
- console.warn("[cube4-scrambler] cubing.js fallback also failed; using random-moves.");
226
- return generateCube4RandomMoves(options);
286
+ return result;
227
287
  }
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube4/state.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,wBAAgB,sBAAsB,IAAI,UAAU,CAanD;AAMD,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,GAAG,UAAU,CAOzD;AAMD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAOtE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAE7D;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAS5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAUzD"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube4/state.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,wBAAgB,sBAAsB,IAAI,UAAU,CAanD;AAMD,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,GAAG,UAAU,CAOzD;AAMD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAOtE;AAMD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAE7D;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAS5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAUzD"}
@@ -36,8 +36,11 @@ export function cube4StatesEqual(a, b) {
36
36
  typedArrayEqual(a.wp, b.wp) &&
37
37
  typedArrayEqual(a.centers, b.centers));
38
38
  }
39
+ // Read-only canonical solved state for comparisons (never mutated, so a
40
+ // single shared instance is safe and avoids allocating 4 arrays per call).
41
+ const SOLVED_STATE = createSolvedCube4State();
39
42
  export function isSolvedCube4State(state) {
40
- return cube4StatesEqual(state, createSolvedCube4State());
43
+ return cube4StatesEqual(state, SOLVED_STATE);
41
44
  }
42
45
  // ---------------------------------------------------------------------------
43
46
  // Helpers
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAe/D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAGjF;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAG3F;AAMD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGlF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAGvE;AAuCD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,EAAE,CAGtE;AAaD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAsCzG;AAKD,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,OAAO,CAmCT"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgB/D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAGjF;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAG3F;AAMD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGlF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAGvE;AAoCD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,EAAE,CAGtE;AAaD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAsCzG;AAKD,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,OAAO,CAmCT"}
@@ -1,4 +1,4 @@
1
- import { POLICY_TABLE, CENTERS_TABLE, PERMUTATION_TABLE, ORIENTATION_TABLE, PYRAMINX_MOVES, MOVE_COUNT, PERMUTATION_COUNT, getCentersIndex, getOrientationIndex, getPermutationCompactIndex, ensureTablesLoaded } from "./tables.js";
1
+ import { POLICY_TABLE, POLICY_TABLE_EXPANDED, CENTERS_TABLE, PERMUTATION_TABLE, ORIENTATION_TABLE, PYRAMINX_MOVES, MOVE_COUNT, PERMUTATION_COUNT, getCentersIndex, getOrientationIndex, getPermutationCompactIndex, ensureTablesLoaded } from "./tables.js";
2
2
  export async function solvePyraminx(state) {
3
3
  await ensureTablesLoaded();
4
4
  return solveWithTables(state).moves;
@@ -29,7 +29,7 @@ function solveWithTablesIndices(state) {
29
29
  const centersTable = CENTERS_TABLE;
30
30
  const permTable = PERMUTATION_TABLE;
31
31
  const orientTable = ORIENTATION_TABLE;
32
- const policy = POLICY_TABLE;
32
+ const policy = POLICY_TABLE_EXPANDED;
33
33
  let c = getCentersIndex(state.centers);
34
34
  let p = getPermutationCompactIndex(state.edgesPerm);
35
35
  let o = getOrientationIndex(state.edgesOrient);
@@ -38,10 +38,7 @@ function solveWithTablesIndices(state) {
38
38
  return [];
39
39
  const moves = [];
40
40
  while (stateIndex !== 0) {
41
- const bits = stateIndex * 3;
42
- const byteIndex = bits >> 3;
43
- const offset = bits & 7;
44
- const m = ((policy[byteIndex] | ((policy[byteIndex + 1] ?? 0) << 8)) >> offset) & 0x07;
41
+ const m = policy[stateIndex];
45
42
  moves.push(m);
46
43
  c = centersTable[c * MOVE_COUNT + m];
47
44
  p = permTable[p * MOVE_COUNT + m];
@@ -34,6 +34,12 @@ export declare let CENTERS_TABLE: Uint8Array | null;
34
34
  export declare let PERMUTATION_TABLE: Uint16Array | null;
35
35
  export declare let ORIENTATION_TABLE: Uint8Array | null;
36
36
  export declare let POLICY_TABLE: Uint8Array | null;
37
+ /**
38
+ * Byte-expanded policy (one optimal move per state, no bit-unpacking in
39
+ * the hot walk). Built at load from the 3-bit packed table: +0.9 MB RAM,
40
+ * zero wire/format change.
41
+ */
42
+ export declare let POLICY_TABLE_EXPANDED: Uint8Array | null;
37
43
  export declare function ensureTablesLoaded(): Promise<void>;
38
44
  export declare function arePyraminxTablesLoaded(): boolean;
39
45
  export declare function getPolicyMove(stateIndex: number): number;
@@ -1 +1 @@
1
- {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/tables.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/tables.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ/D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAWnE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAY1E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMrE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAY/D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAElE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ3D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAIjE;AAGD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,eAAe,yBAAkD,CAAC;AAC/E,eAAO,MAAM,eAAe,0BAAqC,CAAC;AAalE,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAK1E;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlE;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAK1D;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAatE;AAMD,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,WAAW,QAA6C,CAAC;AACtE,eAAO,MAAM,qBAAqB,QAAmC,CAAC;AAGtE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMtF;AAED,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAEjD,CAAC;AAMF,wBAAgB,oBAAoB,IAAI,UAAU,CAgBjD;AAED,wBAAgB,wBAAwB,IAAI,WAAW,CAkBtD;AAED,wBAAgB,wBAAwB,IAAI,UAAU,CAgBrD;AAKD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,UAAU,EACxB,SAAS,EAAE,WAAW,EACtB,WAAW,EAAE,UAAU,GACtB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA8C1C;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAO1D;AAOD,eAAO,IAAI,aAAa,EAAE,UAAU,GAAG,IAAW,CAAC;AACnD,eAAO,IAAI,iBAAiB,EAAE,WAAW,GAAG,IAAW,CAAC;AACxD,eAAO,IAAI,iBAAiB,EAAE,UAAU,GAAG,IAAW,CAAC;AACvD,eAAO,IAAI,YAAY,EAAE,UAAU,GAAG,IAAW,CAAC;AAClD;;;;GAIG;AACH,eAAO,IAAI,qBAAqB,EAAE,UAAU,GAAG,IAAW,CAAC;AAE3D,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CASxD;AAYD,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG5E;AACD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9E;AACD,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAO1C"}