@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
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.lookupCube3MoveTable = exports.loadCube3SolverTables = exports.loadCube3Phase2Tables = exports.loadCube3Phase1Tables = exports.generateCube3SolverTables = exports.generateCube3PruningTable = exports.generateCube3MoveTable = exports.generateCube3Phase2Tables = exports.generateCube3Phase1Tables = exports.checksum = exports.CUBE3_PHASE2_MOVES = exports.CUBE3_PHASE1_MOVES = exports.CUBE3_SOLVER_TABLE_METADATA = exports.moveCoordinate = exports.encodeUdSlice = exports.encodeUdEdgePermutation = exports.encodeSlicePermutation = exports.encodePermutation = exports.encodeEdgeOrientation = exports.encodeCube3Coordinates = exports.encodeCornerOrientation = exports.encodeCube3Coordinate = exports.decodeUdSlice = exports.decodeUdEdgePermutation = exports.decodeSlicePermutation = exports.decodePermutation = exports.decodeEdgeOrientation = exports.decodeCornerOrientation = exports.createRepresentativeStateForCoordinate = exports.CUBE3_COORDINATE_RANGES = exports.Cube3Phase1SearchError = exports.solveCube3Phase1 = exports.isCube3Phase1Solved = exports.encodeCube3Phase1Coordinates = exports.applyCube3Phase1Moves = exports.Cube3Phase2SearchError = exports.solveCube3State = exports.solveCube3Phase2 = exports.isCube3Phase2Solved = exports.encodeCube3Phase2Coordinates = exports.applyCube3Phase2Moves = void 0;
3
+ exports.lookupCube3MoveTable = exports.loadCube3SolverTables = exports.loadCube3Phase2Tables = exports.loadCube3Phase1Tables = exports.generateCube3SolverTables = exports.generateCube3PruningTable = exports.generateCube3MoveTable = exports.generateCube3Phase2Tables = exports.generateCube3Phase1Tables = exports.checksum = exports.CUBE3_PHASE2_MOVES = exports.CUBE3_PHASE1_MOVES = exports.CUBE3_SOLVER_TABLE_METADATA = exports.moveCoordinate = exports.encodeUdSlice = exports.encodeUdEdgePermutation = exports.encodeSlicePermutation = exports.encodePermutation = exports.encodeEdgeOrientation = exports.encodeCube3Coordinates = exports.encodeCornerOrientation = exports.encodeCube3Coordinate = exports.decodeUdSlice = exports.decodeUdEdgePermutation = exports.decodeSlicePermutation = exports.decodePermutation = exports.decodeEdgeOrientation = exports.decodeCornerOrientation = exports.createRepresentativeStateForCoordinate = exports.CUBE3_COORDINATE_RANGES = exports.rotateCube3AlgorithmBySequence = exports.rotateCube3Algorithm = exports.invertCube3RotationSequence = exports.CUBE3_ROTATION_INVERSE = exports.CUBE3_ORIENTATIONS_24 = exports.Cube3Phase1SearchError = exports.solveCube3Phase1 = exports.isCube3Phase1Solved = exports.encodeCube3Phase1Coordinates = exports.collectCube3Phase1Solutions = exports.applyCube3Phase1Moves = exports.Cube3Phase2SearchError = exports.solveCube3State = exports.solveCube3Phase2 = exports.isCube3Phase2Solved = exports.encodeCube3Phase2Coordinates = exports.applyCube3Phase2Moves = void 0;
4
4
  var phase2_js_1 = require("./phase2.js");
5
5
  Object.defineProperty(exports, "applyCube3Phase2Moves", { enumerable: true, get: function () { return phase2_js_1.applyCube3Phase2Moves; } });
6
6
  Object.defineProperty(exports, "encodeCube3Phase2Coordinates", { enumerable: true, get: function () { return phase2_js_1.encodeCube3Phase2Coordinates; } });
@@ -10,10 +10,17 @@ Object.defineProperty(exports, "solveCube3State", { enumerable: true, get: funct
10
10
  Object.defineProperty(exports, "Cube3Phase2SearchError", { enumerable: true, get: function () { return phase2_js_1.Cube3Phase2SearchError; } });
11
11
  var phase1_js_1 = require("./phase1.js");
12
12
  Object.defineProperty(exports, "applyCube3Phase1Moves", { enumerable: true, get: function () { return phase1_js_1.applyCube3Phase1Moves; } });
13
+ Object.defineProperty(exports, "collectCube3Phase1Solutions", { enumerable: true, get: function () { return phase1_js_1.collectCube3Phase1Solutions; } });
13
14
  Object.defineProperty(exports, "encodeCube3Phase1Coordinates", { enumerable: true, get: function () { return phase1_js_1.encodeCube3Phase1Coordinates; } });
14
15
  Object.defineProperty(exports, "isCube3Phase1Solved", { enumerable: true, get: function () { return phase1_js_1.isCube3Phase1Solved; } });
15
16
  Object.defineProperty(exports, "solveCube3Phase1", { enumerable: true, get: function () { return phase1_js_1.solveCube3Phase1; } });
16
17
  Object.defineProperty(exports, "Cube3Phase1SearchError", { enumerable: true, get: function () { return phase1_js_1.Cube3Phase1SearchError; } });
18
+ var symmetry_js_1 = require("./symmetry.js");
19
+ Object.defineProperty(exports, "CUBE3_ORIENTATIONS_24", { enumerable: true, get: function () { return symmetry_js_1.CUBE3_ORIENTATIONS_24; } });
20
+ Object.defineProperty(exports, "CUBE3_ROTATION_INVERSE", { enumerable: true, get: function () { return symmetry_js_1.CUBE3_ROTATION_INVERSE; } });
21
+ Object.defineProperty(exports, "invertCube3RotationSequence", { enumerable: true, get: function () { return symmetry_js_1.invertCube3RotationSequence; } });
22
+ Object.defineProperty(exports, "rotateCube3Algorithm", { enumerable: true, get: function () { return symmetry_js_1.rotateCube3Algorithm; } });
23
+ Object.defineProperty(exports, "rotateCube3AlgorithmBySequence", { enumerable: true, get: function () { return symmetry_js_1.rotateCube3AlgorithmBySequence; } });
17
24
  var coordinates_js_1 = require("./coordinates.js");
18
25
  Object.defineProperty(exports, "CUBE3_COORDINATE_RANGES", { enumerable: true, get: function () { return coordinates_js_1.CUBE3_COORDINATE_RANGES; } });
19
26
  Object.defineProperty(exports, "createRepresentativeStateForCoordinate", { enumerable: true, get: function () { return coordinates_js_1.createRepresentativeStateForCoordinate; } });
@@ -71,9 +71,16 @@ function readMoveTable(assetDirectory, entry) {
71
71
  if (buffer.length !== expectedBytes) {
72
72
  throw new Error(`Invalid byte size for ${entry.coordinate} move table.`);
73
73
  }
74
- const values = new Int32Array(entry.range * entry.moves.length);
74
+ // Every coordinate fits in 16 bits (max range 40320): store half the
75
+ // bytes the int32 wire format uses. Checksums are order-sensitive FNV
76
+ // over the same numeric sequence, so they still match the manifest.
77
+ const values = new Uint16Array(entry.range * entry.moves.length);
75
78
  for (let index = 0; index < values.length; index += 1) {
76
- values[index] = buffer.readInt32LE(index * 4);
79
+ const value = buffer.readInt32LE(index * 4);
80
+ if (value < 0 || value > 0xffff) {
81
+ throw new Error(`Move table value out of range for ${entry.coordinate}: ${value}.`);
82
+ }
83
+ values[index] = value;
77
84
  }
78
85
  const table = {
79
86
  coordinate: entry.coordinate,
@@ -5,6 +5,7 @@ exports.solveCube3Phase1 = solveCube3Phase1;
5
5
  exports.encodeCube3Phase1Coordinates = encodeCube3Phase1Coordinates;
6
6
  exports.isCube3Phase1Solved = isCube3Phase1Solved;
7
7
  exports.applyCube3Phase1Moves = applyCube3Phase1Moves;
8
+ exports.collectCube3Phase1Solutions = collectCube3Phase1Solutions;
8
9
  const moves_js_1 = require("../moves.js");
9
10
  const coordinates_js_1 = require("./coordinates.js");
10
11
  const tables_js_1 = require("./tables.js");
@@ -36,14 +37,7 @@ async function solveCube3Phase1(state, options = {}) {
36
37
  const maxDepth = options.maxDepth ?? 12;
37
38
  const start = encodeCube3Phase1Coordinates(state);
38
39
  const deadline = options.timeoutMs === undefined ? undefined : performance.now() + options.timeoutMs;
39
- const context = {
40
- tables,
41
- jointTables,
42
- maxDepth,
43
- deadline,
44
- visitedNodes: 0,
45
- timedOut: false
46
- };
40
+ const context = createPhase1SearchContext(tables, jointTables, maxDepth, deadline, options.maxNodes);
47
41
  if (await isCube3Phase1Solved(start, tables)) {
48
42
  return {
49
43
  moves: [],
@@ -85,6 +79,9 @@ async function solveCube3Phase1(state, options = {}) {
85
79
  visitedNodes: context.visitedNodes
86
80
  };
87
81
  }
82
+ if (context.nodesExceeded) {
83
+ throw new Cube3Phase1SearchError(`3x3 Phase 1 node budget exceeded (${options.maxNodes} nodes).`, context.visitedNodes);
84
+ }
88
85
  if (context.timedOut) {
89
86
  throw new Cube3Phase1SearchError(`3x3 Phase 1 search timed out after ${options.timeoutMs}ms.`, context.visitedNodes);
90
87
  }
@@ -115,8 +112,17 @@ const PHASE1_MOVE_FACES = tables_js_1.CUBE3_PHASE1_MOVES.map((move) => {
115
112
  });
116
113
  function searchPhase1(cornerOrientation, edgeOrientation, udSlice, previousFace, previousPreviousFace, remainingDepth, path, context) {
117
114
  context.visitedNodes += 1;
118
- if (context.deadline !== undefined && (context.visitedNodes & 1023) === 0 && performance.now() > context.deadline) {
115
+ if (context.nodeCap !== undefined &&
116
+ context.visitedNodes > context.nodeCap) {
117
+ context.nodesExceeded = true;
118
+ }
119
+ if (!context.nodesExceeded &&
120
+ context.deadline !== undefined &&
121
+ (context.visitedNodes & 1023) === 0 &&
122
+ performance.now() > context.deadline) {
119
123
  context.timedOut = true;
124
+ }
125
+ if (context.timedOut || context.nodesExceeded) {
120
126
  return false;
121
127
  }
122
128
  if (remainingDepth === 0) {
@@ -124,6 +130,68 @@ function searchPhase1(cornerOrientation, edgeOrientation, udSlice, previousFace,
124
130
  edgeOrientation === 0 &&
125
131
  udSlice === context.tables.moveTables.udSlice.solvedCoordinate;
126
132
  }
133
+ const moveCount = context.tables.phase1Moves.length;
134
+ const childCount = collectPhase1Children(cornerOrientation, edgeOrientation, udSlice, previousFace, previousPreviousFace, remainingDepth, context);
135
+ const slot = remainingDepth * moveCount;
136
+ const scratchMove = context.scratchMove;
137
+ const scratchCo = context.scratchCo;
138
+ const scratchEo = context.scratchEo;
139
+ const scratchUd = context.scratchUd;
140
+ for (let i = 0; i < childCount; i += 1) {
141
+ const moveIndex = scratchMove[slot + i];
142
+ const face = PHASE1_MOVE_FACES[moveIndex];
143
+ path.push(context.tables.phase1Moves[moveIndex]);
144
+ if (searchPhase1(scratchCo[slot + i], scratchEo[slot + i], scratchUd[slot + i], face, previousFace, remainingDepth - 1, path, context)) {
145
+ return true;
146
+ }
147
+ path.pop();
148
+ if (context.timedOut || context.nodesExceeded) {
149
+ return false;
150
+ }
151
+ }
152
+ return false;
153
+ }
154
+ /**
155
+ * Enumerates up to `limit` phase-1 solutions of exactly `depth` moves for
156
+ * the given state, most promising first (same ordered DFS as the search).
157
+ * Used to try several G1 landing states and keep the best phase-1+phase-2
158
+ * total — a slightly longer phase 1 often collapses phase 2.
159
+ */
160
+ async function collectCube3Phase1Solutions(state, depth, options = {}) {
161
+ const tables = options.tables ?? await (0, tables_js_1.loadCube3Phase1Tables)();
162
+ const jointTables = options.jointTables ?? tables.jointTables;
163
+ const limit = options.limit ?? 32;
164
+ const deadline = options.timeoutMs === undefined ? undefined : performance.now() + options.timeoutMs;
165
+ const context = createPhase1SearchContext(tables, jointTables, depth, deadline, options.maxNodes);
166
+ const start = encodeCube3Phase1Coordinates(state);
167
+ const solutions = [];
168
+ searchPhase1Collect(start.cornerOrientation, start.edgeOrientation, start.udSlice, -1, -1, depth, [], solutions, limit, context);
169
+ return { solutions, visitedNodes: context.visitedNodes };
170
+ }
171
+ function createPhase1SearchContext(tables, jointTables, maxDepth, deadline, nodeCap) {
172
+ const scratchLevels = maxDepth + 1;
173
+ const scratchSize = scratchLevels * tables_js_1.CUBE3_PHASE1_MOVES.length;
174
+ return {
175
+ tables,
176
+ jointTables,
177
+ maxDepth,
178
+ deadline,
179
+ nodeCap,
180
+ visitedNodes: 0,
181
+ timedOut: false,
182
+ nodesExceeded: false,
183
+ scratchMove: new Int32Array(scratchSize),
184
+ scratchBound: new Int32Array(scratchSize),
185
+ scratchCo: new Int32Array(scratchSize),
186
+ scratchEo: new Int32Array(scratchSize),
187
+ scratchUd: new Int32Array(scratchSize)
188
+ };
189
+ }
190
+ /**
191
+ * Fills the scratch slot for `remainingDepth` with the surviving children
192
+ * in ascending lower-bound order (stable). Returns the child count.
193
+ */
194
+ function collectPhase1Children(cornerOrientation, edgeOrientation, udSlice, previousFace, previousPreviousFace, remainingDepth, context) {
127
195
  const moveCount = context.tables.phase1Moves.length;
128
196
  const validMoves = PHASE1_VALID_MOVES[previousFace + 1][previousPreviousFace + 1];
129
197
  const coTable = context.tables.moveTables.cornerOrientation.values;
@@ -131,9 +199,17 @@ function searchPhase1(cornerOrientation, edgeOrientation, udSlice, previousFace,
131
199
  const udTable = context.tables.moveTables.udSlice.values;
132
200
  const coeoTable = context.tables.pruningTables.cornerOrientationEdgeOrientation.values;
133
201
  const udPruningTable = context.tables.pruningTables.udSlice.values;
202
+ const jointTables = context.jointTables;
134
203
  const coOffset = cornerOrientation * moveCount;
135
204
  const eoOffset = edgeOrientation * moveCount;
136
205
  const udOffset = udSlice * moveCount;
206
+ const slot = remainingDepth * moveCount;
207
+ const scratchMove = context.scratchMove;
208
+ const scratchBound = context.scratchBound;
209
+ const scratchCo = context.scratchCo;
210
+ const scratchEo = context.scratchEo;
211
+ const scratchUd = context.scratchUd;
212
+ let childCount = 0;
137
213
  for (let i = 0; i < validMoves.length; i += 1) {
138
214
  const moveIndex = validMoves[i];
139
215
  const nextCornerOrientation = coTable[coOffset + moveIndex];
@@ -146,7 +222,6 @@ function searchPhase1(cornerOrientation, edgeOrientation, udSlice, previousFace,
146
222
  if (nextLowerBound > remainingDepth - 1) {
147
223
  continue;
148
224
  }
149
- const jointTables = context.jointTables;
150
225
  if (jointTables) {
151
226
  const udCoIndex = nextUdSlice * 2187 + nextCornerOrientation;
152
227
  const jc = (jointTables.jointUdCo[udCoIndex >> 1] >> ((udCoIndex & 1) << 2)) & 0x0f;
@@ -162,14 +237,81 @@ function searchPhase1(cornerOrientation, edgeOrientation, udSlice, previousFace,
162
237
  continue;
163
238
  }
164
239
  }
240
+ scratchMove[slot + childCount] = moveIndex;
241
+ scratchBound[slot + childCount] = nextLowerBound;
242
+ scratchCo[slot + childCount] = nextCornerOrientation;
243
+ scratchEo[slot + childCount] = nextEdgeOrientation;
244
+ scratchUd[slot + childCount] = nextUdSlice;
245
+ childCount += 1;
246
+ }
247
+ // Stable insertion sort by bound (n <= 18; ties keep reference order).
248
+ for (let i = 1; i < childCount; i += 1) {
249
+ const move = scratchMove[slot + i];
250
+ const bound = scratchBound[slot + i];
251
+ const co = scratchCo[slot + i];
252
+ const eo = scratchEo[slot + i];
253
+ const ud = scratchUd[slot + i];
254
+ let j = i - 1;
255
+ while (j >= 0 && scratchBound[slot + j] > bound) {
256
+ scratchMove[slot + j + 1] = scratchMove[slot + j];
257
+ scratchBound[slot + j + 1] = scratchBound[slot + j];
258
+ scratchCo[slot + j + 1] = scratchCo[slot + j];
259
+ scratchEo[slot + j + 1] = scratchEo[slot + j];
260
+ scratchUd[slot + j + 1] = scratchUd[slot + j];
261
+ j -= 1;
262
+ }
263
+ scratchMove[slot + j + 1] = move;
264
+ scratchBound[slot + j + 1] = bound;
265
+ scratchCo[slot + j + 1] = co;
266
+ scratchEo[slot + j + 1] = eo;
267
+ scratchUd[slot + j + 1] = ud;
268
+ }
269
+ return childCount;
270
+ }
271
+ /**
272
+ * Ordered exact-depth DFS that collects solutions instead of stopping at
273
+ * the first one. Returns true when collection should stop (limit reached
274
+ * or timed out).
275
+ */
276
+ function searchPhase1Collect(cornerOrientation, edgeOrientation, udSlice, previousFace, previousPreviousFace, remainingDepth, path, solutions, limit, context) {
277
+ context.visitedNodes += 1;
278
+ if (context.nodeCap !== undefined &&
279
+ context.visitedNodes > context.nodeCap) {
280
+ context.nodesExceeded = true;
281
+ }
282
+ if (!context.nodesExceeded &&
283
+ context.deadline !== undefined &&
284
+ (context.visitedNodes & 1023) === 0 &&
285
+ performance.now() > context.deadline) {
286
+ context.timedOut = true;
287
+ }
288
+ if (context.timedOut || context.nodesExceeded) {
289
+ return true;
290
+ }
291
+ if (remainingDepth === 0) {
292
+ if (cornerOrientation === 0 &&
293
+ edgeOrientation === 0 &&
294
+ udSlice === context.tables.moveTables.udSlice.solvedCoordinate) {
295
+ solutions.push([...path]);
296
+ return solutions.length >= limit;
297
+ }
298
+ return false;
299
+ }
300
+ const moveCount = context.tables.phase1Moves.length;
301
+ const childCount = collectPhase1Children(cornerOrientation, edgeOrientation, udSlice, previousFace, previousPreviousFace, remainingDepth, context);
302
+ const slot = remainingDepth * moveCount;
303
+ const scratchMove = context.scratchMove;
304
+ const scratchCo = context.scratchCo;
305
+ const scratchEo = context.scratchEo;
306
+ const scratchUd = context.scratchUd;
307
+ for (let i = 0; i < childCount; i += 1) {
308
+ const moveIndex = scratchMove[slot + i];
165
309
  const face = PHASE1_MOVE_FACES[moveIndex];
166
310
  path.push(context.tables.phase1Moves[moveIndex]);
167
- if (searchPhase1(nextCornerOrientation, nextEdgeOrientation, nextUdSlice, face, previousFace, remainingDepth - 1, path, context)) {
168
- return true;
169
- }
311
+ const stop = searchPhase1Collect(scratchCo[slot + i], scratchEo[slot + i], scratchUd[slot + i], face, previousFace, remainingDepth - 1, path, solutions, limit, context);
170
312
  path.pop();
171
- if (context.timedOut) {
172
- return false;
313
+ if (stop) {
314
+ return true;
173
315
  }
174
316
  }
175
317
  return false;