@cubingcenter/scrambler 0.3.0 → 0.4.1

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 (124) hide show
  1. package/README.md +46 -3
  2. package/dist/core/api.d.ts.map +1 -1
  3. package/dist/core/api.js +13 -6
  4. package/dist/core/index.d.ts +1 -1
  5. package/dist/core/index.d.ts.map +1 -1
  6. package/dist/core/types.d.ts +7 -0
  7. package/dist/core/types.d.ts.map +1 -1
  8. package/dist/puzzles/clock/index.d.ts +1 -0
  9. package/dist/puzzles/clock/index.d.ts.map +1 -1
  10. package/dist/puzzles/clock/index.js +4 -0
  11. package/dist/puzzles/clock/scrambler.js +2 -2
  12. package/dist/puzzles/cube2/index.d.ts +1 -0
  13. package/dist/puzzles/cube2/index.d.ts.map +1 -1
  14. package/dist/puzzles/cube2/index.js +4 -0
  15. package/dist/puzzles/cube2/scrambler.d.ts.map +1 -1
  16. package/dist/puzzles/cube2/scrambler.js +4 -6
  17. package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
  18. package/dist/puzzles/cube2/solver/browser-loader.js +4 -12
  19. package/dist/puzzles/cube2/solver/index.d.ts +1 -1
  20. package/dist/puzzles/cube2/solver/index.d.ts.map +1 -1
  21. package/dist/puzzles/cube2/solver/index.js +1 -1
  22. package/dist/puzzles/cube2/solver/search.d.ts +2 -0
  23. package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
  24. package/dist/puzzles/cube2/solver/search.js +26 -0
  25. package/dist/puzzles/cube2/validation.d.ts.map +1 -1
  26. package/dist/puzzles/cube2/validation.js +15 -3
  27. package/dist/puzzles/cube3/index.d.ts +1 -0
  28. package/dist/puzzles/cube3/index.d.ts.map +1 -1
  29. package/dist/puzzles/cube3/index.js +4 -0
  30. package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
  31. package/dist/puzzles/cube3/solver/browser-loader.js +5 -29
  32. package/dist/puzzles/cube4/index.d.ts +1 -0
  33. package/dist/puzzles/cube4/index.d.ts.map +1 -1
  34. package/dist/puzzles/cube4/index.js +4 -0
  35. package/dist/puzzles/cube5x5/index.d.ts +1 -0
  36. package/dist/puzzles/cube5x5/index.d.ts.map +1 -1
  37. package/dist/puzzles/cube5x5/index.js +4 -0
  38. package/dist/puzzles/cube6x6/index.d.ts +1 -0
  39. package/dist/puzzles/cube6x6/index.d.ts.map +1 -1
  40. package/dist/puzzles/cube6x6/index.js +4 -0
  41. package/dist/puzzles/cube7x7/index.d.ts +1 -0
  42. package/dist/puzzles/cube7x7/index.d.ts.map +1 -1
  43. package/dist/puzzles/cube7x7/index.js +4 -0
  44. package/dist/puzzles/megaminx/index.d.ts +1 -0
  45. package/dist/puzzles/megaminx/index.d.ts.map +1 -1
  46. package/dist/puzzles/megaminx/index.js +4 -0
  47. package/dist/puzzles/megaminx/scrambler.js +2 -2
  48. package/dist/puzzles/pyraminx/index.d.ts +3 -1
  49. package/dist/puzzles/pyraminx/index.d.ts.map +1 -1
  50. package/dist/puzzles/pyraminx/index.js +6 -1
  51. package/dist/puzzles/pyraminx/scrambler.d.ts.map +1 -1
  52. package/dist/puzzles/pyraminx/scrambler.js +26 -22
  53. package/dist/puzzles/pyraminx/solver/browser-loader.d.ts +14 -0
  54. package/dist/puzzles/pyraminx/solver/browser-loader.d.ts.map +1 -0
  55. package/dist/puzzles/pyraminx/solver/browser-loader.js +63 -0
  56. package/dist/puzzles/pyraminx/solver/generated/centers-table.bin +0 -0
  57. package/dist/puzzles/pyraminx/solver/generated/manifest.json +26 -0
  58. package/dist/puzzles/pyraminx/solver/generated/orientation-table.bin +0 -0
  59. package/dist/puzzles/pyraminx/solver/generated/permutation-table.bin +0 -0
  60. package/dist/puzzles/pyraminx/solver/generated/policy.bin +0 -0
  61. package/dist/puzzles/pyraminx/solver/generated-assets.d.ts +7 -0
  62. package/dist/puzzles/pyraminx/solver/generated-assets.d.ts.map +1 -0
  63. package/dist/puzzles/pyraminx/solver/generated-assets.js +24 -0
  64. package/dist/puzzles/pyraminx/solver/index.d.ts +5 -0
  65. package/dist/puzzles/pyraminx/solver/index.d.ts.map +1 -0
  66. package/dist/puzzles/pyraminx/solver/index.js +4 -0
  67. package/dist/puzzles/pyraminx/solver/node-loader.d.ts +7 -0
  68. package/dist/puzzles/pyraminx/solver/node-loader.d.ts.map +1 -0
  69. package/dist/puzzles/pyraminx/solver/node-loader.js +73 -0
  70. package/dist/puzzles/pyraminx/solver/search.d.ts +10 -0
  71. package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -0
  72. package/dist/puzzles/pyraminx/solver/search.js +82 -0
  73. package/dist/puzzles/pyraminx/solver/table-metadata.d.ts +20 -0
  74. package/dist/puzzles/pyraminx/solver/table-metadata.d.ts.map +1 -0
  75. package/dist/puzzles/pyraminx/solver/table-metadata.js +19 -0
  76. package/dist/puzzles/pyraminx/solver/tables.d.ts +43 -0
  77. package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -0
  78. package/dist/puzzles/pyraminx/solver/tables.js +300 -0
  79. package/dist/puzzles/shared/compressed-fetch.d.ts +12 -0
  80. package/dist/puzzles/shared/compressed-fetch.d.ts.map +1 -0
  81. package/dist/puzzles/shared/compressed-fetch.js +68 -0
  82. package/dist/puzzles/skewb/index.d.ts +1 -0
  83. package/dist/puzzles/skewb/index.d.ts.map +1 -1
  84. package/dist/puzzles/skewb/index.js +4 -0
  85. package/dist/puzzles/skewb/scrambler.js +2 -2
  86. package/dist-cjs/core/api.js +46 -6
  87. package/dist-cjs/puzzles/clock/index.js +13 -4
  88. package/dist-cjs/puzzles/clock/scrambler.js +2 -2
  89. package/dist-cjs/puzzles/cube2/index.js +13 -4
  90. package/dist-cjs/puzzles/cube2/scrambler.js +2 -4
  91. package/dist-cjs/puzzles/cube2/solver/browser-loader.js +4 -12
  92. package/dist-cjs/puzzles/cube2/solver/index.js +3 -1
  93. package/dist-cjs/puzzles/cube2/solver/search.js +28 -0
  94. package/dist-cjs/puzzles/cube2/validation.js +14 -2
  95. package/dist-cjs/puzzles/cube3/index.js +13 -4
  96. package/dist-cjs/puzzles/cube3/solver/browser-loader.js +5 -29
  97. package/dist-cjs/puzzles/cube4/index.js +13 -4
  98. package/dist-cjs/puzzles/cube5x5/index.js +13 -4
  99. package/dist-cjs/puzzles/cube6x6/index.js +13 -4
  100. package/dist-cjs/puzzles/cube7x7/index.js +13 -4
  101. package/dist-cjs/puzzles/megaminx/index.js +13 -4
  102. package/dist-cjs/puzzles/megaminx/scrambler.js +2 -2
  103. package/dist-cjs/puzzles/pyraminx/index.js +50 -6
  104. package/dist-cjs/puzzles/pyraminx/scrambler.js +25 -21
  105. package/dist-cjs/puzzles/pyraminx/solver/browser-loader.js +68 -0
  106. package/dist-cjs/puzzles/pyraminx/solver/generated/centers-table.bin +0 -0
  107. package/dist-cjs/puzzles/pyraminx/solver/generated/manifest.json +26 -0
  108. package/dist-cjs/puzzles/pyraminx/solver/generated/orientation-table.bin +0 -0
  109. package/dist-cjs/puzzles/pyraminx/solver/generated/permutation-table.bin +0 -0
  110. package/dist-cjs/puzzles/pyraminx/solver/generated/policy.bin +0 -0
  111. package/dist-cjs/puzzles/pyraminx/solver/generated-assets.js +60 -0
  112. package/dist-cjs/puzzles/pyraminx/solver/index.js +23 -0
  113. package/dist-cjs/puzzles/pyraminx/solver/node-loader.js +79 -0
  114. package/dist-cjs/puzzles/pyraminx/solver/search.js +88 -0
  115. package/dist-cjs/puzzles/pyraminx/solver/table-metadata.js +22 -0
  116. package/dist-cjs/puzzles/pyraminx/solver/tables.js +327 -0
  117. package/dist-cjs/puzzles/shared/compressed-fetch.js +71 -0
  118. package/dist-cjs/puzzles/skewb/index.js +13 -4
  119. package/dist-cjs/puzzles/skewb/scrambler.js +2 -2
  120. package/package.json +17 -6
  121. package/dist/puzzles/pyraminx/solver.d.ts +0 -10
  122. package/dist/puzzles/pyraminx/solver.d.ts.map +0 -1
  123. package/dist/puzzles/pyraminx/solver.js +0 -160
  124. package/dist-cjs/puzzles/pyraminx/solver.js +0 -170
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.skewbScrambleGenerator = exports.generateSkewbScramble = exports.getStateFromIndex = exports.getStateIndex = exports.solveSkewb = exports.toSkewbFacelets = exports.getSkewbFaceOrder = exports.formatSkewbFacelets = exports.createSolvedSkewbFacelets = exports.generateRandomSkewbState = exports.isOneMoveFromSolvedSkewbState = exports.isAllowedRandomSkewbState = exports.validateSkewbState = exports.permutationParity = exports.skewbStatesEqual = exports.isSolvedSkewbState = exports.createSolvedSkewbState = exports.cloneSkewbState = exports.parseSkewbMove = exports.parseSkewbAlgorithm = exports.invertSkewbMove = exports.invertSkewbAlgorithm = exports.formatSkewbAlgorithm = exports.applySkewbMove = exports.applySkewbAlgorithm = exports.SKEWB_FACES = exports.SKEWB_MOVES = void 0;
3
+ exports.initializeScrambler = exports.getSupportedEvents = exports.getEventInfo = exports.generateScrambles = exports.generateScramble = exports.skewbScrambleGenerator = exports.generateSkewbScramble = exports.getStateFromIndex = exports.getStateIndex = exports.solveSkewb = exports.toSkewbFacelets = exports.getSkewbFaceOrder = exports.formatSkewbFacelets = exports.createSolvedSkewbFacelets = exports.generateRandomSkewbState = exports.isOneMoveFromSolvedSkewbState = exports.isAllowedRandomSkewbState = exports.validateSkewbState = exports.permutationParity = exports.skewbStatesEqual = exports.isSolvedSkewbState = exports.createSolvedSkewbState = exports.cloneSkewbState = exports.parseSkewbMove = exports.parseSkewbAlgorithm = exports.invertSkewbMove = exports.invertSkewbAlgorithm = exports.formatSkewbAlgorithm = exports.applySkewbMove = exports.applySkewbAlgorithm = exports.SKEWB_FACES = exports.SKEWB_MOVES = void 0;
4
+ const index_js_1 = require("../../core/index.js");
5
+ const scrambler_js_1 = require("./scrambler.js");
6
+ (0, index_js_1.registerScrambleGenerator)(scrambler_js_1.skewbScrambleGenerator);
4
7
  var types_js_1 = require("./types.js");
5
8
  Object.defineProperty(exports, "SKEWB_MOVES", { enumerable: true, get: function () { return types_js_1.SKEWB_MOVES; } });
6
9
  Object.defineProperty(exports, "SKEWB_FACES", { enumerable: true, get: function () { return types_js_1.SKEWB_FACES; } });
@@ -33,6 +36,12 @@ var solver_js_1 = require("./solver.js");
33
36
  Object.defineProperty(exports, "solveSkewb", { enumerable: true, get: function () { return solver_js_1.solveSkewb; } });
34
37
  Object.defineProperty(exports, "getStateIndex", { enumerable: true, get: function () { return solver_js_1.getStateIndex; } });
35
38
  Object.defineProperty(exports, "getStateFromIndex", { enumerable: true, get: function () { return solver_js_1.getStateFromIndex; } });
36
- var scrambler_js_1 = require("./scrambler.js");
37
- Object.defineProperty(exports, "generateSkewbScramble", { enumerable: true, get: function () { return scrambler_js_1.generateSkewbScramble; } });
38
- Object.defineProperty(exports, "skewbScrambleGenerator", { enumerable: true, get: function () { return scrambler_js_1.skewbScrambleGenerator; } });
39
+ var scrambler_js_2 = require("./scrambler.js");
40
+ Object.defineProperty(exports, "generateSkewbScramble", { enumerable: true, get: function () { return scrambler_js_2.generateSkewbScramble; } });
41
+ Object.defineProperty(exports, "skewbScrambleGenerator", { enumerable: true, get: function () { return scrambler_js_2.skewbScrambleGenerator; } });
42
+ var index_js_2 = require("../../core/index.js");
43
+ Object.defineProperty(exports, "generateScramble", { enumerable: true, get: function () { return index_js_2.generateScramble; } });
44
+ Object.defineProperty(exports, "generateScrambles", { enumerable: true, get: function () { return index_js_2.generateScrambles; } });
45
+ Object.defineProperty(exports, "getEventInfo", { enumerable: true, get: function () { return index_js_2.getEventInfo; } });
46
+ Object.defineProperty(exports, "getSupportedEvents", { enumerable: true, get: function () { return index_js_2.getSupportedEvents; } });
47
+ Object.defineProperty(exports, "initializeScrambler", { enumerable: true, get: function () { return index_js_2.initializeScrambler; } });
@@ -9,7 +9,7 @@ const solver_js_1 = require("./solver.js");
9
9
  const facelets_js_1 = require("./facelets.js");
10
10
  exports.skewbScrambleGenerator = {
11
11
  info: {
12
- eventId: "skewb",
12
+ eventId: "skwb",
13
13
  name: "Skewb",
14
14
  puzzle: "skewb",
15
15
  quality: "random-state",
@@ -37,7 +37,7 @@ async function generateSkewbScramble(options = {}) {
37
37
  }
38
38
  const facelets = (0, facelets_js_1.toSkewbFacelets)(state);
39
39
  const result = {
40
- eventId: "skewb",
40
+ eventId: "skwb",
41
41
  scramble: (0, moves_js_1.formatSkewbAlgorithm)(scrambleMoves),
42
42
  moves: scrambleMoves,
43
43
  quality: "random-state",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubingcenter/scrambler",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Extensible scramble generation toolkit for CubingCenter projects.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,7 +13,13 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js",
15
15
  "require": "./dist-cjs/index.js"
16
- }
16
+ },
17
+ "./puzzles/*": {
18
+ "types": "./dist/puzzles/*/index.d.ts",
19
+ "import": "./dist/puzzles/*/index.js",
20
+ "require": "./dist-cjs/puzzles/*/index.js"
21
+ },
22
+ "./package.json": "./package.json"
17
23
  },
18
24
  "types": "./dist/index.d.ts",
19
25
  "files": [
@@ -28,17 +34,22 @@
28
34
  "test": "node --test --import tsx test/*.test.ts",
29
35
  "lint": "tsc -p tsconfig.json --noEmit",
30
36
  "package:check": "pnpm build && node scripts/check-package.cjs",
31
- "verify": "pnpm lint && pnpm test && pnpm build && pnpm cube3:tables:check && pnpm cube4:tables:check && pnpm cube2:tables:check && pnpm package:check",
37
+ "verify": "pnpm lint && pnpm test && pnpm build && pnpm cube3:tables:check && pnpm cube2:tables:check && pnpm pyraminx:tables:check && pnpm package:check",
32
38
  "dev": "tsx src/cli/index.ts",
33
39
  "cube3:tables": "node --import tsx scripts/generate-cube3-solver-tables.ts",
34
40
  "cube3:tables:check": "node --import tsx scripts/check-cube3-solver-tables.ts",
35
- "cube4:tables": "node --import tsx scripts/generate-cube4-reduction-tables.ts",
36
- "cube4:tables:check": "node --import tsx scripts/check-cube4-reduction-tables.ts",
37
41
  "cube2:tables": "node --import tsx scripts/generate-cube2-solver-tables.ts",
38
42
  "cube2:tables:check": "node --import tsx scripts/check-cube2-solver-tables.ts",
43
+ "pyraminx:tables": "node --import tsx scripts/generate-pyraminx-solver-tables.ts",
44
+ "pyraminx:tables:check": "node --import tsx scripts/check-pyraminx-solver-tables.ts",
45
+ "tables:web:sync": "node --import tsx scripts/sync-web-tables.ts",
46
+ "verify:scrambles": "node --import tsx scripts/verify-scrambles.ts",
47
+ "verify:pyraminx:exhaustive": "node --import tsx scripts/verify-pyraminx-exhaustive.ts",
39
48
  "bench": "node --import tsx bench.ts",
40
49
  "bench:cube2": "node --import tsx bench-cube2.ts",
41
- "bench:cube3": "node --import tsx bench-cube3.ts"
50
+ "bench:cube3": "node --import tsx bench-cube3.ts",
51
+ "bench:skewb": "node --import tsx bench-skewb.ts",
52
+ "bench:pyraminx": "node --import tsx bench-pyraminx.ts"
42
53
  },
43
54
  "devDependencies": {
44
55
  "@cubingcenter/viz": "link:../cubingcenter-viz",
@@ -1,10 +0,0 @@
1
- import type { PyraminxState, PyraminxMove } from "./types.js";
2
- export declare function getPermutationIndex(perm: readonly number[]): number;
3
- export declare function getPermutationFromIndex(index: number, n: number): number[];
4
- export declare function getOrientationIndex(orient: readonly number[]): number;
5
- export declare function getOrientationFromIndex(index: number): number[];
6
- export declare function getCentersIndex(centers: readonly number[]): number;
7
- export declare function getCentersFromIndex(index: number): number[];
8
- export declare function getStateIndex(state: PyraminxState): number;
9
- export declare function solvePyraminx(state: PyraminxState): PyraminxMove[];
10
- //# sourceMappingURL=solver.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"solver.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/solver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS9D,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,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAM1D;AAKD,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,EAAE,CA8DlE"}
@@ -1,160 +0,0 @@
1
- import { applyPyraminxMove } from "./moves.js";
2
- import { createSolvedPyraminxState } from "./state.js";
3
- // Fast state-to-index encoder/decoder to allow optimal BFS solving
4
- // Factorials for permutation encoding
5
- const FACT = [1, 1, 2, 6, 24, 120, 720];
6
- export function getPermutationIndex(perm) {
7
- let index = 0;
8
- const n = perm.length;
9
- for (let i = 0; i < n; i++) {
10
- let count = 0;
11
- for (let j = i + 1; j < n; j++) {
12
- if (perm[j] < perm[i])
13
- count++;
14
- }
15
- index += count * FACT[n - 1 - i];
16
- }
17
- return index;
18
- }
19
- export function getPermutationFromIndex(index, n) {
20
- const perm = Array(n).fill(0);
21
- const temp = Array.from({ length: n }, (_, i) => i);
22
- let val = index;
23
- for (let i = 0; i < n; i++) {
24
- const f = FACT[n - 1 - i];
25
- const choice = Math.floor(val / f);
26
- val %= f;
27
- perm[i] = temp[choice];
28
- temp.splice(choice, 1);
29
- }
30
- return perm;
31
- }
32
- export function getOrientationIndex(orient) {
33
- let index = 0;
34
- for (let i = 0; i < 5; i++) {
35
- index = (index << 1) | orient[i];
36
- }
37
- return index;
38
- }
39
- export function getOrientationFromIndex(index) {
40
- const orient = Array(6).fill(0);
41
- let temp = index;
42
- let sum = 0;
43
- for (let i = 4; i >= 0; i--) {
44
- const bit = temp & 1;
45
- orient[i] = bit;
46
- sum += bit;
47
- temp >>= 1;
48
- }
49
- orient[5] = sum % 2 === 0 ? 0 : 1;
50
- return orient;
51
- }
52
- export function getCentersIndex(centers) {
53
- return centers[0] + 3 * centers[1] + 9 * centers[2] + 27 * centers[3];
54
- }
55
- export function getCentersFromIndex(index) {
56
- let temp = index;
57
- const centers = Array(4).fill(0);
58
- for (let i = 0; i < 4; i++) {
59
- centers[i] = temp % 3;
60
- temp = Math.floor(temp / 3);
61
- }
62
- return centers;
63
- }
64
- export function getStateIndex(state) {
65
- const c = getCentersIndex(state.centers);
66
- const p = getPermutationIndex(state.edgesPerm);
67
- const o = getOrientationIndex(state.edgesOrient);
68
- // c is 0..80, p is 0..719, o is 0..31
69
- return c + 81 * (p + 720 * o);
70
- }
71
- // Bidirectional BFS solver
72
- const MOVES = ["U", "U'", "L", "L'", "R", "R'", "B", "B'"];
73
- export function solvePyraminx(state) {
74
- const startIdx = getStateIndex(state);
75
- const solvedIdx = getStateIndex(createSolvedPyraminxState());
76
- if (startIdx === solvedIdx)
77
- return [];
78
- // Bidirectional BFS:
79
- // forwardMap and backwardMap store the move that led to this index and the parent index
80
- const forwardMap = new Map();
81
- const backwardMap = new Map();
82
- const forwardQueue = [startIdx];
83
- const backwardQueue = [solvedIdx];
84
- forwardMap.set(startIdx, { move: "", parent: -1 });
85
- backwardMap.set(solvedIdx, { move: "", parent: -1 });
86
- while (forwardQueue.length > 0 && backwardQueue.length > 0) {
87
- // Expand forward
88
- const fSize = forwardQueue.length;
89
- for (let i = 0; i < Math.min(fSize, 1000); i++) {
90
- const currIdx = forwardQueue.shift();
91
- const currState = getPyraminxStateFromIndex(currIdx);
92
- for (const move of MOVES) {
93
- const nextState = applyPyraminxMove(currState, move);
94
- const nextIdx = getStateIndex(nextState);
95
- if (!forwardMap.has(nextIdx)) {
96
- forwardMap.set(nextIdx, { move, parent: currIdx });
97
- if (backwardMap.has(nextIdx)) {
98
- return reconstructPath(nextIdx, forwardMap, backwardMap);
99
- }
100
- forwardQueue.push(nextIdx);
101
- }
102
- }
103
- }
104
- // Expand backward
105
- const bSize = backwardQueue.length;
106
- for (let i = 0; i < Math.min(bSize, 1000); i++) {
107
- const currIdx = backwardQueue.shift();
108
- const currState = getPyraminxStateFromIndex(currIdx);
109
- for (const move of MOVES) {
110
- const nextState = applyPyraminxMove(currState, move);
111
- const nextIdx = getStateIndex(nextState);
112
- if (!backwardMap.has(nextIdx)) {
113
- // Note: we record the inverse move since we are searching from solved
114
- const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
115
- backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
116
- if (forwardMap.has(nextIdx)) {
117
- return reconstructPath(nextIdx, forwardMap, backwardMap);
118
- }
119
- backwardQueue.push(nextIdx);
120
- }
121
- }
122
- }
123
- }
124
- throw new Error("Pyraminx state is unsolvable");
125
- }
126
- function getPyraminxStateFromIndex(index) {
127
- let val = index;
128
- const centersIdx = val % 81;
129
- val = Math.floor(val / 81);
130
- const permIdx = val % 720;
131
- const orientIdx = Math.floor(val / 720);
132
- return {
133
- centers: getCentersFromIndex(centersIdx),
134
- edgesPerm: getPermutationFromIndex(permIdx, 6),
135
- edgesOrient: getOrientationFromIndex(orientIdx),
136
- tips: [0, 0, 0, 0] // tips are solved separately
137
- };
138
- }
139
- function reconstructPath(meetingIdx, forwardMap, backwardMap) {
140
- const path = [];
141
- // Reconstruct forward path
142
- let curr = meetingIdx;
143
- while (curr !== -1) {
144
- const edge = forwardMap.get(curr);
145
- if (edge.parent !== -1) {
146
- path.unshift(edge.move);
147
- }
148
- curr = edge.parent;
149
- }
150
- // Reconstruct backward path
151
- curr = meetingIdx;
152
- while (curr !== -1) {
153
- const edge = backwardMap.get(curr);
154
- if (edge.parent !== -1) {
155
- path.push(edge.move);
156
- }
157
- curr = edge.parent;
158
- }
159
- return path;
160
- }
@@ -1,170 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPermutationIndex = getPermutationIndex;
4
- exports.getPermutationFromIndex = getPermutationFromIndex;
5
- exports.getOrientationIndex = getOrientationIndex;
6
- exports.getOrientationFromIndex = getOrientationFromIndex;
7
- exports.getCentersIndex = getCentersIndex;
8
- exports.getCentersFromIndex = getCentersFromIndex;
9
- exports.getStateIndex = getStateIndex;
10
- exports.solvePyraminx = solvePyraminx;
11
- const moves_js_1 = require("./moves.js");
12
- const state_js_1 = require("./state.js");
13
- // Fast state-to-index encoder/decoder to allow optimal BFS solving
14
- // Factorials for permutation encoding
15
- const FACT = [1, 1, 2, 6, 24, 120, 720];
16
- function getPermutationIndex(perm) {
17
- let index = 0;
18
- const n = perm.length;
19
- for (let i = 0; i < n; i++) {
20
- let count = 0;
21
- for (let j = i + 1; j < n; j++) {
22
- if (perm[j] < perm[i])
23
- count++;
24
- }
25
- index += count * FACT[n - 1 - i];
26
- }
27
- return index;
28
- }
29
- function getPermutationFromIndex(index, n) {
30
- const perm = Array(n).fill(0);
31
- const temp = Array.from({ length: n }, (_, i) => i);
32
- let val = index;
33
- for (let i = 0; i < n; i++) {
34
- const f = FACT[n - 1 - i];
35
- const choice = Math.floor(val / f);
36
- val %= f;
37
- perm[i] = temp[choice];
38
- temp.splice(choice, 1);
39
- }
40
- return perm;
41
- }
42
- function getOrientationIndex(orient) {
43
- let index = 0;
44
- for (let i = 0; i < 5; i++) {
45
- index = (index << 1) | orient[i];
46
- }
47
- return index;
48
- }
49
- function getOrientationFromIndex(index) {
50
- const orient = Array(6).fill(0);
51
- let temp = index;
52
- let sum = 0;
53
- for (let i = 4; i >= 0; i--) {
54
- const bit = temp & 1;
55
- orient[i] = bit;
56
- sum += bit;
57
- temp >>= 1;
58
- }
59
- orient[5] = sum % 2 === 0 ? 0 : 1;
60
- return orient;
61
- }
62
- function getCentersIndex(centers) {
63
- return centers[0] + 3 * centers[1] + 9 * centers[2] + 27 * centers[3];
64
- }
65
- function getCentersFromIndex(index) {
66
- let temp = index;
67
- const centers = Array(4).fill(0);
68
- for (let i = 0; i < 4; i++) {
69
- centers[i] = temp % 3;
70
- temp = Math.floor(temp / 3);
71
- }
72
- return centers;
73
- }
74
- function getStateIndex(state) {
75
- const c = getCentersIndex(state.centers);
76
- const p = getPermutationIndex(state.edgesPerm);
77
- const o = getOrientationIndex(state.edgesOrient);
78
- // c is 0..80, p is 0..719, o is 0..31
79
- return c + 81 * (p + 720 * o);
80
- }
81
- // Bidirectional BFS solver
82
- const MOVES = ["U", "U'", "L", "L'", "R", "R'", "B", "B'"];
83
- function solvePyraminx(state) {
84
- const startIdx = getStateIndex(state);
85
- const solvedIdx = getStateIndex((0, state_js_1.createSolvedPyraminxState)());
86
- if (startIdx === solvedIdx)
87
- return [];
88
- // Bidirectional BFS:
89
- // forwardMap and backwardMap store the move that led to this index and the parent index
90
- const forwardMap = new Map();
91
- const backwardMap = new Map();
92
- const forwardQueue = [startIdx];
93
- const backwardQueue = [solvedIdx];
94
- forwardMap.set(startIdx, { move: "", parent: -1 });
95
- backwardMap.set(solvedIdx, { move: "", parent: -1 });
96
- while (forwardQueue.length > 0 && backwardQueue.length > 0) {
97
- // Expand forward
98
- const fSize = forwardQueue.length;
99
- for (let i = 0; i < Math.min(fSize, 1000); i++) {
100
- const currIdx = forwardQueue.shift();
101
- const currState = getPyraminxStateFromIndex(currIdx);
102
- for (const move of MOVES) {
103
- const nextState = (0, moves_js_1.applyPyraminxMove)(currState, move);
104
- const nextIdx = getStateIndex(nextState);
105
- if (!forwardMap.has(nextIdx)) {
106
- forwardMap.set(nextIdx, { move, parent: currIdx });
107
- if (backwardMap.has(nextIdx)) {
108
- return reconstructPath(nextIdx, forwardMap, backwardMap);
109
- }
110
- forwardQueue.push(nextIdx);
111
- }
112
- }
113
- }
114
- // Expand backward
115
- const bSize = backwardQueue.length;
116
- for (let i = 0; i < Math.min(bSize, 1000); i++) {
117
- const currIdx = backwardQueue.shift();
118
- const currState = getPyraminxStateFromIndex(currIdx);
119
- for (const move of MOVES) {
120
- const nextState = (0, moves_js_1.applyPyraminxMove)(currState, move);
121
- const nextIdx = getStateIndex(nextState);
122
- if (!backwardMap.has(nextIdx)) {
123
- // Note: we record the inverse move since we are searching from solved
124
- const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
125
- backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
126
- if (forwardMap.has(nextIdx)) {
127
- return reconstructPath(nextIdx, forwardMap, backwardMap);
128
- }
129
- backwardQueue.push(nextIdx);
130
- }
131
- }
132
- }
133
- }
134
- throw new Error("Pyraminx state is unsolvable");
135
- }
136
- function getPyraminxStateFromIndex(index) {
137
- let val = index;
138
- const centersIdx = val % 81;
139
- val = Math.floor(val / 81);
140
- const permIdx = val % 720;
141
- const orientIdx = Math.floor(val / 720);
142
- return {
143
- centers: getCentersFromIndex(centersIdx),
144
- edgesPerm: getPermutationFromIndex(permIdx, 6),
145
- edgesOrient: getOrientationFromIndex(orientIdx),
146
- tips: [0, 0, 0, 0] // tips are solved separately
147
- };
148
- }
149
- function reconstructPath(meetingIdx, forwardMap, backwardMap) {
150
- const path = [];
151
- // Reconstruct forward path
152
- let curr = meetingIdx;
153
- while (curr !== -1) {
154
- const edge = forwardMap.get(curr);
155
- if (edge.parent !== -1) {
156
- path.unshift(edge.move);
157
- }
158
- curr = edge.parent;
159
- }
160
- // Reconstruct backward path
161
- curr = meetingIdx;
162
- while (curr !== -1) {
163
- const edge = backwardMap.get(curr);
164
- if (edge.parent !== -1) {
165
- path.push(edge.move);
166
- }
167
- curr = edge.parent;
168
- }
169
- return path;
170
- }