@cubingcenter/scrambler 0.4.0 → 0.5.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 (174) hide show
  1. package/README.md +67 -3
  2. package/dist/core/api.d.ts.map +1 -1
  3. package/dist/core/api.js +18 -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/cube2/index.d.ts +1 -0
  12. package/dist/puzzles/cube2/index.d.ts.map +1 -1
  13. package/dist/puzzles/cube2/index.js +4 -0
  14. package/dist/puzzles/cube2/scrambler.d.ts.map +1 -1
  15. package/dist/puzzles/cube2/scrambler.js +4 -6
  16. package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
  17. package/dist/puzzles/cube2/solver/browser-loader.js +4 -12
  18. package/dist/puzzles/cube2/solver/index.d.ts +1 -1
  19. package/dist/puzzles/cube2/solver/index.d.ts.map +1 -1
  20. package/dist/puzzles/cube2/solver/index.js +1 -1
  21. package/dist/puzzles/cube2/solver/search.d.ts +2 -0
  22. package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
  23. package/dist/puzzles/cube2/solver/search.js +26 -0
  24. package/dist/puzzles/cube2/validation.d.ts.map +1 -1
  25. package/dist/puzzles/cube2/validation.js +15 -3
  26. package/dist/puzzles/cube3/index.d.ts +1 -0
  27. package/dist/puzzles/cube3/index.d.ts.map +1 -1
  28. package/dist/puzzles/cube3/index.js +4 -0
  29. package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
  30. package/dist/puzzles/cube3/solver/browser-loader.js +5 -29
  31. package/dist/puzzles/cube4/index.d.ts +1 -0
  32. package/dist/puzzles/cube4/index.d.ts.map +1 -1
  33. package/dist/puzzles/cube4/index.js +4 -0
  34. package/dist/puzzles/cube5x5/index.d.ts +1 -0
  35. package/dist/puzzles/cube5x5/index.d.ts.map +1 -1
  36. package/dist/puzzles/cube5x5/index.js +4 -0
  37. package/dist/puzzles/cube6x6/index.d.ts +1 -0
  38. package/dist/puzzles/cube6x6/index.d.ts.map +1 -1
  39. package/dist/puzzles/cube6x6/index.js +4 -0
  40. package/dist/puzzles/cube7x7/index.d.ts +1 -0
  41. package/dist/puzzles/cube7x7/index.d.ts.map +1 -1
  42. package/dist/puzzles/cube7x7/index.js +4 -0
  43. package/dist/puzzles/megaminx/index.d.ts +1 -0
  44. package/dist/puzzles/megaminx/index.d.ts.map +1 -1
  45. package/dist/puzzles/megaminx/index.js +4 -0
  46. package/dist/puzzles/pyraminx/index.d.ts +3 -1
  47. package/dist/puzzles/pyraminx/index.d.ts.map +1 -1
  48. package/dist/puzzles/pyraminx/index.js +6 -1
  49. package/dist/puzzles/pyraminx/scrambler.d.ts.map +1 -1
  50. package/dist/puzzles/pyraminx/scrambler.js +24 -20
  51. package/dist/puzzles/pyraminx/solver/browser-loader.d.ts +14 -0
  52. package/dist/puzzles/pyraminx/solver/browser-loader.d.ts.map +1 -0
  53. package/dist/puzzles/pyraminx/solver/browser-loader.js +63 -0
  54. package/dist/puzzles/pyraminx/solver/generated/centers-table.bin +0 -0
  55. package/dist/puzzles/pyraminx/solver/generated/manifest.json +26 -0
  56. package/dist/puzzles/pyraminx/solver/generated/orientation-table.bin +0 -0
  57. package/dist/puzzles/pyraminx/solver/generated/permutation-table.bin +0 -0
  58. package/dist/puzzles/pyraminx/solver/generated/policy.bin +0 -0
  59. package/dist/puzzles/pyraminx/solver/generated-assets.d.ts +7 -0
  60. package/dist/puzzles/pyraminx/solver/generated-assets.d.ts.map +1 -0
  61. package/dist/puzzles/pyraminx/solver/generated-assets.js +24 -0
  62. package/dist/puzzles/pyraminx/solver/index.d.ts +5 -0
  63. package/dist/puzzles/pyraminx/solver/index.d.ts.map +1 -0
  64. package/dist/puzzles/pyraminx/solver/index.js +4 -0
  65. package/dist/puzzles/pyraminx/solver/node-loader.d.ts +7 -0
  66. package/dist/puzzles/pyraminx/solver/node-loader.d.ts.map +1 -0
  67. package/dist/puzzles/pyraminx/solver/node-loader.js +73 -0
  68. package/dist/puzzles/pyraminx/solver/search.d.ts +10 -0
  69. package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -0
  70. package/dist/puzzles/pyraminx/solver/search.js +82 -0
  71. package/dist/puzzles/pyraminx/solver/table-metadata.d.ts +20 -0
  72. package/dist/puzzles/pyraminx/solver/table-metadata.d.ts.map +1 -0
  73. package/dist/puzzles/pyraminx/solver/table-metadata.js +19 -0
  74. package/dist/puzzles/pyraminx/solver/tables.d.ts +43 -0
  75. package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -0
  76. package/dist/puzzles/pyraminx/solver/tables.js +300 -0
  77. package/dist/puzzles/shared/compressed-fetch.d.ts +12 -0
  78. package/dist/puzzles/shared/compressed-fetch.d.ts.map +1 -0
  79. package/dist/puzzles/shared/compressed-fetch.js +68 -0
  80. package/dist/puzzles/skewb/facelets.d.ts.map +1 -1
  81. package/dist/puzzles/skewb/facelets.js +46 -23
  82. package/dist/puzzles/skewb/index.d.ts +3 -1
  83. package/dist/puzzles/skewb/index.d.ts.map +1 -1
  84. package/dist/puzzles/skewb/index.js +6 -1
  85. package/dist/puzzles/skewb/random-state.d.ts +1 -1
  86. package/dist/puzzles/skewb/random-state.d.ts.map +1 -1
  87. package/dist/puzzles/skewb/random-state.js +25 -18
  88. package/dist/puzzles/skewb/scrambler.d.ts.map +1 -1
  89. package/dist/puzzles/skewb/scrambler.js +10 -13
  90. package/dist/puzzles/skewb/solver/browser-loader.d.ts +20 -0
  91. package/dist/puzzles/skewb/solver/browser-loader.d.ts.map +1 -0
  92. package/dist/puzzles/skewb/solver/browser-loader.js +86 -0
  93. package/dist/puzzles/skewb/solver/generated/centers-table.bin +0 -0
  94. package/dist/puzzles/skewb/solver/generated/helpers.bin +0 -0
  95. package/dist/puzzles/skewb/solver/generated/manifest.json +31 -0
  96. package/dist/puzzles/skewb/solver/generated/orientation-table.bin +0 -0
  97. package/dist/puzzles/skewb/solver/generated/permutation-table.bin +0 -0
  98. package/dist/puzzles/skewb/solver/generated/policy.bin +0 -0
  99. package/dist/puzzles/skewb/solver/generated-assets.d.ts +10 -0
  100. package/dist/puzzles/skewb/solver/generated-assets.d.ts.map +1 -0
  101. package/dist/puzzles/skewb/solver/generated-assets.js +24 -0
  102. package/dist/puzzles/skewb/solver/index.d.ts +5 -0
  103. package/dist/puzzles/skewb/solver/index.d.ts.map +1 -0
  104. package/dist/puzzles/skewb/solver/index.js +4 -0
  105. package/dist/puzzles/skewb/solver/node-loader.d.ts +10 -0
  106. package/dist/puzzles/skewb/solver/node-loader.d.ts.map +1 -0
  107. package/dist/puzzles/skewb/solver/node-loader.js +91 -0
  108. package/dist/puzzles/skewb/solver/search.d.ts +11 -0
  109. package/dist/puzzles/skewb/solver/search.d.ts.map +1 -0
  110. package/dist/puzzles/skewb/solver/search.js +80 -0
  111. package/dist/puzzles/skewb/solver/table-metadata.d.ts +27 -0
  112. package/dist/puzzles/skewb/solver/table-metadata.d.ts.map +1 -0
  113. package/dist/puzzles/skewb/solver/table-metadata.js +26 -0
  114. package/dist/puzzles/skewb/solver/tables.d.ts +68 -0
  115. package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -0
  116. package/dist/puzzles/skewb/solver/tables.js +508 -0
  117. package/dist/random/prng.js +10 -1
  118. package/dist-cjs/core/api.js +51 -6
  119. package/dist-cjs/puzzles/clock/index.js +13 -4
  120. package/dist-cjs/puzzles/cube2/index.js +13 -4
  121. package/dist-cjs/puzzles/cube2/scrambler.js +2 -4
  122. package/dist-cjs/puzzles/cube2/solver/browser-loader.js +4 -12
  123. package/dist-cjs/puzzles/cube2/solver/index.js +3 -1
  124. package/dist-cjs/puzzles/cube2/solver/search.js +28 -0
  125. package/dist-cjs/puzzles/cube2/validation.js +14 -2
  126. package/dist-cjs/puzzles/cube3/index.js +13 -4
  127. package/dist-cjs/puzzles/cube3/solver/browser-loader.js +5 -29
  128. package/dist-cjs/puzzles/cube4/index.js +13 -4
  129. package/dist-cjs/puzzles/cube5x5/index.js +13 -4
  130. package/dist-cjs/puzzles/cube6x6/index.js +13 -4
  131. package/dist-cjs/puzzles/cube7x7/index.js +13 -4
  132. package/dist-cjs/puzzles/megaminx/index.js +13 -4
  133. package/dist-cjs/puzzles/pyraminx/index.js +50 -6
  134. package/dist-cjs/puzzles/pyraminx/scrambler.js +23 -19
  135. package/dist-cjs/puzzles/pyraminx/solver/browser-loader.js +68 -0
  136. package/dist-cjs/puzzles/pyraminx/solver/generated/centers-table.bin +0 -0
  137. package/dist-cjs/puzzles/pyraminx/solver/generated/manifest.json +26 -0
  138. package/dist-cjs/puzzles/pyraminx/solver/generated/orientation-table.bin +0 -0
  139. package/dist-cjs/puzzles/pyraminx/solver/generated/permutation-table.bin +0 -0
  140. package/dist-cjs/puzzles/pyraminx/solver/generated/policy.bin +0 -0
  141. package/dist-cjs/puzzles/pyraminx/solver/generated-assets.js +60 -0
  142. package/dist-cjs/puzzles/pyraminx/solver/index.js +23 -0
  143. package/dist-cjs/puzzles/pyraminx/solver/node-loader.js +79 -0
  144. package/dist-cjs/puzzles/pyraminx/solver/search.js +88 -0
  145. package/dist-cjs/puzzles/pyraminx/solver/table-metadata.js +22 -0
  146. package/dist-cjs/puzzles/pyraminx/solver/tables.js +327 -0
  147. package/dist-cjs/puzzles/shared/compressed-fetch.js +71 -0
  148. package/dist-cjs/puzzles/skewb/facelets.js +46 -23
  149. package/dist-cjs/puzzles/skewb/index.js +55 -8
  150. package/dist-cjs/puzzles/skewb/random-state.js +25 -18
  151. package/dist-cjs/puzzles/skewb/scrambler.js +9 -12
  152. package/dist-cjs/puzzles/skewb/solver/browser-loader.js +91 -0
  153. package/dist-cjs/puzzles/skewb/solver/generated/centers-table.bin +0 -0
  154. package/dist-cjs/puzzles/skewb/solver/generated/helpers.bin +0 -0
  155. package/dist-cjs/puzzles/skewb/solver/generated/manifest.json +31 -0
  156. package/dist-cjs/puzzles/skewb/solver/generated/orientation-table.bin +0 -0
  157. package/dist-cjs/puzzles/skewb/solver/generated/permutation-table.bin +0 -0
  158. package/dist-cjs/puzzles/skewb/solver/generated/policy.bin +0 -0
  159. package/dist-cjs/puzzles/skewb/solver/generated-assets.js +60 -0
  160. package/dist-cjs/puzzles/skewb/solver/index.js +23 -0
  161. package/dist-cjs/puzzles/skewb/solver/node-loader.js +97 -0
  162. package/dist-cjs/puzzles/skewb/solver/search.js +87 -0
  163. package/dist-cjs/puzzles/skewb/solver/table-metadata.js +29 -0
  164. package/dist-cjs/puzzles/skewb/solver/tables.js +539 -0
  165. package/dist-cjs/random/prng.js +10 -1
  166. package/package.json +20 -6
  167. package/dist/puzzles/pyraminx/solver.d.ts +0 -10
  168. package/dist/puzzles/pyraminx/solver.d.ts.map +0 -1
  169. package/dist/puzzles/pyraminx/solver.js +0 -160
  170. package/dist/puzzles/skewb/solver.d.ts +0 -11
  171. package/dist/puzzles/skewb/solver.d.ts.map +0 -1
  172. package/dist/puzzles/skewb/solver.js +0 -149
  173. package/dist-cjs/puzzles/pyraminx/solver.js +0 -170
  174. package/dist-cjs/puzzles/skewb/solver.js +0 -160
@@ -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,11 +0,0 @@
1
- import type { SkewbMove, SkewbState } 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 getCenterIndex(centers: readonly number[]): number;
7
- export declare function getCenterFromIndex(index: number): number[];
8
- export declare function getStateIndex(state: SkewbState): number;
9
- export declare function getStateFromIndex(index: number): SkewbState;
10
- export declare function solveSkewb(state: SkewbState): SkewbMove[];
11
- //# sourceMappingURL=solver.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"solver.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/solver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxD,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,CAOrE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAS/D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CASjE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE1D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAOvD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAY3D;AAID,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,EAAE,CA+CzD"}
@@ -1,149 +0,0 @@
1
- import { applySkewbMove } from "./moves.js";
2
- import { createSolvedSkewbState } from "./state.js";
3
- const FACT = [1, 1, 2, 6, 24, 120, 720, 5040, 40320];
4
- export function getPermutationIndex(perm) {
5
- // perm length 8, but pos0 is always 0 for WCA reachable states.
6
- // We encode full 8-perm via Lehmer code (0..40319), but for fixed corner it will be in subset.
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
- index += count * FACT[n - 1 - i];
15
- }
16
- return index;
17
- }
18
- export function getPermutationFromIndex(index, n) {
19
- const perm = Array(n).fill(0);
20
- const temp = Array.from({ length: n }, (_, i) => i);
21
- let val = index;
22
- for (let i = 0; i < n; i++) {
23
- const f = FACT[n - 1 - i];
24
- const choice = Math.floor(val / f);
25
- val %= f;
26
- perm[i] = temp[choice];
27
- temp.splice(choice, 1);
28
- }
29
- return perm;
30
- }
31
- export function getOrientationIndex(orient) {
32
- // orient length 8, index 0 is fixed 0, encode remaining 7 base3
33
- let index = 0;
34
- for (let i = 7; i >= 1; i--) {
35
- index = index * 3 + orient[i];
36
- }
37
- return index;
38
- }
39
- export function getOrientationFromIndex(index) {
40
- const orient = Array(8).fill(0);
41
- orient[0] = 0;
42
- let val = index;
43
- for (let i = 1; i < 8; i++) {
44
- orient[i] = val % 3;
45
- val = Math.floor(val / 3);
46
- }
47
- return orient;
48
- }
49
- export function getCenterIndex(centers) {
50
- let index = 0;
51
- const n = centers.length;
52
- for (let i = 0; i < n; i++) {
53
- let count = 0;
54
- for (let j = i + 1; j < n; j++)
55
- if (centers[j] < centers[i])
56
- count++;
57
- index += count * FACT[n - 1 - i];
58
- }
59
- return index;
60
- }
61
- export function getCenterFromIndex(index) {
62
- return getPermutationFromIndex(index, 6);
63
- }
64
- export function getStateIndex(state) {
65
- const p = getPermutationIndex(state.corners.permutation);
66
- const c = getCenterIndex(state.centers);
67
- const o = getOrientationIndex(state.corners.orientation);
68
- // p in 0..40319, c in 0..719, o in 0..2186
69
- // Combine: ((p * 720 + c) * 2187 + o) -> up to 63B fits in JS number (53-bit)
70
- return ((p * 720 + c) * 2187 + o);
71
- }
72
- export function getStateFromIndex(index) {
73
- const o = index % 2187;
74
- let val = Math.floor(index / 2187);
75
- const c = val % 720;
76
- const p = Math.floor(val / 720);
77
- return {
78
- corners: {
79
- permutation: getPermutationFromIndex(p, 8),
80
- orientation: getOrientationFromIndex(o),
81
- },
82
- centers: getCenterFromIndex(c),
83
- };
84
- }
85
- const MOVES = ["R", "R'", "U", "U'", "L", "L'", "B", "B'"];
86
- export function solveSkewb(state) {
87
- const startIdx = getStateIndex(state);
88
- const solvedIdx = getStateIndex(createSolvedSkewbState());
89
- if (startIdx === solvedIdx)
90
- return [];
91
- const forwardMap = new Map();
92
- const backwardMap = new Map();
93
- const forwardQueue = [startIdx];
94
- const backwardQueue = [solvedIdx];
95
- forwardMap.set(startIdx, { move: "", parent: -1 });
96
- backwardMap.set(solvedIdx, { move: "", parent: -1 });
97
- while (forwardQueue.length > 0 && backwardQueue.length > 0) {
98
- const fSize = forwardQueue.length;
99
- for (let i = 0; i < Math.min(fSize, 1000); i++) {
100
- const currIdx = forwardQueue.shift();
101
- const currState = getStateFromIndex(currIdx);
102
- for (const move of MOVES) {
103
- const nextState = applySkewbMove(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
- forwardQueue.push(nextIdx);
110
- }
111
- }
112
- }
113
- const bSize = backwardQueue.length;
114
- for (let i = 0; i < Math.min(bSize, 1000); i++) {
115
- const currIdx = backwardQueue.shift();
116
- const currState = getStateFromIndex(currIdx);
117
- for (const move of MOVES) {
118
- const nextState = applySkewbMove(currState, move);
119
- const nextIdx = getStateIndex(nextState);
120
- if (!backwardMap.has(nextIdx)) {
121
- const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
122
- backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
123
- if (forwardMap.has(nextIdx))
124
- return reconstructPath(nextIdx, forwardMap, backwardMap);
125
- backwardQueue.push(nextIdx);
126
- }
127
- }
128
- }
129
- }
130
- throw new Error("Skewb state is unsolvable");
131
- }
132
- function reconstructPath(meetingIdx, forwardMap, backwardMap) {
133
- const path = [];
134
- let curr = meetingIdx;
135
- while (curr !== -1) {
136
- const edge = forwardMap.get(curr);
137
- if (edge.parent !== -1)
138
- path.unshift(edge.move);
139
- curr = edge.parent;
140
- }
141
- curr = meetingIdx;
142
- while (curr !== -1) {
143
- const edge = backwardMap.get(curr);
144
- if (edge.parent !== -1)
145
- path.push(edge.move);
146
- curr = edge.parent;
147
- }
148
- return path;
149
- }
@@ -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
- }
@@ -1,160 +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.getCenterIndex = getCenterIndex;
8
- exports.getCenterFromIndex = getCenterFromIndex;
9
- exports.getStateIndex = getStateIndex;
10
- exports.getStateFromIndex = getStateFromIndex;
11
- exports.solveSkewb = solveSkewb;
12
- const moves_js_1 = require("./moves.js");
13
- const state_js_1 = require("./state.js");
14
- const FACT = [1, 1, 2, 6, 24, 120, 720, 5040, 40320];
15
- function getPermutationIndex(perm) {
16
- // perm length 8, but pos0 is always 0 for WCA reachable states.
17
- // We encode full 8-perm via Lehmer code (0..40319), but for fixed corner it will be in subset.
18
- let index = 0;
19
- const n = perm.length;
20
- for (let i = 0; i < n; i++) {
21
- let count = 0;
22
- for (let j = i + 1; j < n; j++)
23
- if (perm[j] < perm[i])
24
- count++;
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
- // orient length 8, index 0 is fixed 0, encode remaining 7 base3
44
- let index = 0;
45
- for (let i = 7; i >= 1; i--) {
46
- index = index * 3 + orient[i];
47
- }
48
- return index;
49
- }
50
- function getOrientationFromIndex(index) {
51
- const orient = Array(8).fill(0);
52
- orient[0] = 0;
53
- let val = index;
54
- for (let i = 1; i < 8; i++) {
55
- orient[i] = val % 3;
56
- val = Math.floor(val / 3);
57
- }
58
- return orient;
59
- }
60
- function getCenterIndex(centers) {
61
- let index = 0;
62
- const n = centers.length;
63
- for (let i = 0; i < n; i++) {
64
- let count = 0;
65
- for (let j = i + 1; j < n; j++)
66
- if (centers[j] < centers[i])
67
- count++;
68
- index += count * FACT[n - 1 - i];
69
- }
70
- return index;
71
- }
72
- function getCenterFromIndex(index) {
73
- return getPermutationFromIndex(index, 6);
74
- }
75
- function getStateIndex(state) {
76
- const p = getPermutationIndex(state.corners.permutation);
77
- const c = getCenterIndex(state.centers);
78
- const o = getOrientationIndex(state.corners.orientation);
79
- // p in 0..40319, c in 0..719, o in 0..2186
80
- // Combine: ((p * 720 + c) * 2187 + o) -> up to 63B fits in JS number (53-bit)
81
- return ((p * 720 + c) * 2187 + o);
82
- }
83
- function getStateFromIndex(index) {
84
- const o = index % 2187;
85
- let val = Math.floor(index / 2187);
86
- const c = val % 720;
87
- const p = Math.floor(val / 720);
88
- return {
89
- corners: {
90
- permutation: getPermutationFromIndex(p, 8),
91
- orientation: getOrientationFromIndex(o),
92
- },
93
- centers: getCenterFromIndex(c),
94
- };
95
- }
96
- const MOVES = ["R", "R'", "U", "U'", "L", "L'", "B", "B'"];
97
- function solveSkewb(state) {
98
- const startIdx = getStateIndex(state);
99
- const solvedIdx = getStateIndex((0, state_js_1.createSolvedSkewbState)());
100
- if (startIdx === solvedIdx)
101
- return [];
102
- const forwardMap = new Map();
103
- const backwardMap = new Map();
104
- const forwardQueue = [startIdx];
105
- const backwardQueue = [solvedIdx];
106
- forwardMap.set(startIdx, { move: "", parent: -1 });
107
- backwardMap.set(solvedIdx, { move: "", parent: -1 });
108
- while (forwardQueue.length > 0 && backwardQueue.length > 0) {
109
- const fSize = forwardQueue.length;
110
- for (let i = 0; i < Math.min(fSize, 1000); i++) {
111
- const currIdx = forwardQueue.shift();
112
- const currState = getStateFromIndex(currIdx);
113
- for (const move of MOVES) {
114
- const nextState = (0, moves_js_1.applySkewbMove)(currState, move);
115
- const nextIdx = getStateIndex(nextState);
116
- if (!forwardMap.has(nextIdx)) {
117
- forwardMap.set(nextIdx, { move, parent: currIdx });
118
- if (backwardMap.has(nextIdx))
119
- return reconstructPath(nextIdx, forwardMap, backwardMap);
120
- forwardQueue.push(nextIdx);
121
- }
122
- }
123
- }
124
- const bSize = backwardQueue.length;
125
- for (let i = 0; i < Math.min(bSize, 1000); i++) {
126
- const currIdx = backwardQueue.shift();
127
- const currState = getStateFromIndex(currIdx);
128
- for (const move of MOVES) {
129
- const nextState = (0, moves_js_1.applySkewbMove)(currState, move);
130
- const nextIdx = getStateIndex(nextState);
131
- if (!backwardMap.has(nextIdx)) {
132
- const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
133
- backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
134
- if (forwardMap.has(nextIdx))
135
- return reconstructPath(nextIdx, forwardMap, backwardMap);
136
- backwardQueue.push(nextIdx);
137
- }
138
- }
139
- }
140
- }
141
- throw new Error("Skewb state is unsolvable");
142
- }
143
- function reconstructPath(meetingIdx, forwardMap, backwardMap) {
144
- const path = [];
145
- let curr = meetingIdx;
146
- while (curr !== -1) {
147
- const edge = forwardMap.get(curr);
148
- if (edge.parent !== -1)
149
- path.unshift(edge.move);
150
- curr = edge.parent;
151
- }
152
- curr = meetingIdx;
153
- while (curr !== -1) {
154
- const edge = backwardMap.get(curr);
155
- if (edge.parent !== -1)
156
- path.push(edge.move);
157
- curr = edge.parent;
158
- }
159
- return path;
160
- }