cubing 0.27.0 → 0.28.2

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 (112) hide show
  1. package/README.md +3 -1
  2. package/dist/esm/.DS_Store +0 -0
  3. package/dist/esm/alg/index.js +4 -4
  4. package/dist/esm/bluetooth/index.js +228 -92
  5. package/dist/esm/bluetooth/index.js.map +3 -3
  6. package/dist/esm/{chunk-WQK6XWML.js → chunk-2IZUSAXQ.js} +2 -2
  7. package/dist/esm/{chunk-WQK6XWML.js.map → chunk-2IZUSAXQ.js.map} +1 -1
  8. package/dist/esm/{chunk-VY7VF4MA.js → chunk-5744RHHG.js} +145 -58
  9. package/dist/esm/chunk-5744RHHG.js.map +7 -0
  10. package/dist/esm/{chunk-KJYODR27.js → chunk-76H7SSCY.js} +28 -12
  11. package/dist/esm/{chunk-KJYODR27.js.map → chunk-76H7SSCY.js.map} +1 -1
  12. package/dist/esm/chunk-76UZ2QTB.js +1137 -0
  13. package/dist/esm/chunk-76UZ2QTB.js.map +7 -0
  14. package/dist/esm/{chunk-LNUPGLIU.js → chunk-D4YYXJDB.js} +175 -72
  15. package/dist/esm/{chunk-LNUPGLIU.js.map → chunk-D4YYXJDB.js.map} +3 -3
  16. package/dist/esm/{chunk-3Y4PK4XI.js → chunk-FEIKQ7FV.js} +6 -6
  17. package/dist/esm/chunk-FEIKQ7FV.js.map +7 -0
  18. package/dist/esm/{chunk-HIMSRIID.js → chunk-LOTZ7ZO7.js} +8 -4
  19. package/dist/esm/{chunk-HIMSRIID.js.map → chunk-LOTZ7ZO7.js.map} +1 -1
  20. package/dist/esm/{chunk-YBDBUTYE.js → chunk-OX6O2ZO5.js} +1 -1
  21. package/dist/esm/{chunk-YBDBUTYE.js.map → chunk-OX6O2ZO5.js.map} +1 -1
  22. package/dist/esm/{chunk-NQORDEXF.js → chunk-PCR6JT2W.js} +466 -322
  23. package/dist/esm/chunk-PCR6JT2W.js.map +7 -0
  24. package/dist/esm/{chunk-AU3UW5N4.js → chunk-PTUPP5AW.js} +22 -8
  25. package/dist/esm/{chunk-AU3UW5N4.js.map → chunk-PTUPP5AW.js.map} +1 -1
  26. package/dist/esm/{chunk-BEXHMXCT.js → chunk-RHC3DIN3.js} +1 -1
  27. package/dist/esm/{chunk-BEXHMXCT.js.map → chunk-RHC3DIN3.js.map} +1 -1
  28. package/dist/esm/{chunk-DSAZCGT2.js → chunk-RTFKKZPH.js} +22 -13
  29. package/dist/esm/{chunk-DSAZCGT2.js.map → chunk-RTFKKZPH.js.map} +2 -2
  30. package/dist/esm/{chunk-MGJA5U5O.js → chunk-SBZRVSPK.js} +1 -12
  31. package/dist/esm/{chunk-MGJA5U5O.js.map → chunk-SBZRVSPK.js.map} +0 -0
  32. package/dist/esm/{chunk-VYMKSHDI.js → chunk-TX2AQ4XW.js} +35 -13
  33. package/dist/esm/{chunk-VYMKSHDI.js.map → chunk-TX2AQ4XW.js.map} +2 -2
  34. package/dist/esm/{chunk-NYAPGKCW.js → chunk-WXCNEGW3.js} +10 -4
  35. package/dist/esm/{chunk-NYAPGKCW.js.map → chunk-WXCNEGW3.js.map} +1 -1
  36. package/dist/esm/{chunk-GBMX6FHY.js → chunk-ZB3P5AZN.js} +1 -1
  37. package/dist/esm/{chunk-GBMX6FHY.js.map → chunk-ZB3P5AZN.js.map} +1 -1
  38. package/dist/esm/kpuzzle/index.js +3 -3
  39. package/dist/esm/notation/index.js +3 -3
  40. package/dist/esm/protocol/index.js +5 -5
  41. package/dist/esm/puzzle-geometry/index.js +4570 -15
  42. package/dist/esm/puzzle-geometry/index.js.map +4 -4
  43. package/dist/esm/puzzles/index.js +5 -5
  44. package/dist/esm/{puzzles-dynamic-3x3x3-NB2PEZTV.js → puzzles-dynamic-3x3x3-KIG5A6QR.js} +2 -2
  45. package/dist/esm/{puzzles-dynamic-3x3x3-NB2PEZTV.js.map → puzzles-dynamic-3x3x3-KIG5A6QR.js.map} +0 -0
  46. package/dist/esm/puzzles-dynamic-4x4x4-PEDAPUZK.js +126 -0
  47. package/dist/esm/puzzles-dynamic-4x4x4-PEDAPUZK.js.map +7 -0
  48. package/dist/esm/{puzzles-dynamic-side-events-HOXBZYWI.js → puzzles-dynamic-side-events-5C7LMBWX.js} +2 -2
  49. package/dist/esm/{puzzles-dynamic-side-events-HOXBZYWI.js.map → puzzles-dynamic-side-events-5C7LMBWX.js.map} +1 -1
  50. package/dist/esm/{puzzles-dynamic-unofficial-MGVOFUDR.js → puzzles-dynamic-unofficial-WWJ4NJMX.js} +2 -2
  51. package/dist/esm/{puzzles-dynamic-unofficial-MGVOFUDR.js.map → puzzles-dynamic-unofficial-WWJ4NJMX.js.map} +1 -1
  52. package/dist/esm/scramble/index.js +6 -6
  53. package/dist/esm/search/index.js +11 -11
  54. package/dist/esm/{search-dynamic-sgs-side-events-4UF3XJRB.js → search-dynamic-sgs-side-events-X62KI7ZV.js} +37 -21
  55. package/dist/esm/search-dynamic-sgs-side-events-X62KI7ZV.js.map +7 -0
  56. package/dist/esm/{search-dynamic-sgs-unofficial-ZEUVDMBT.js → search-dynamic-sgs-unofficial-YAPJYTMF.js} +35 -14
  57. package/dist/esm/{search-dynamic-sgs-unofficial-ZEUVDMBT.js.map → search-dynamic-sgs-unofficial-YAPJYTMF.js.map} +2 -2
  58. package/dist/esm/{search-dynamic-solve-3x3x3-K4TG7P3X.js → search-dynamic-solve-3x3x3-7XZTYQMO.js} +795 -142
  59. package/dist/esm/{search-dynamic-solve-3x3x3-K4TG7P3X.js.map → search-dynamic-solve-3x3x3-7XZTYQMO.js.map} +1 -1
  60. package/dist/esm/{search-dynamic-solve-4x4x4-FKEWH5MW.js → search-dynamic-solve-4x4x4-5HST67LZ.js} +135 -29
  61. package/dist/esm/{search-dynamic-solve-4x4x4-FKEWH5MW.js.map → search-dynamic-solve-4x4x4-5HST67LZ.js.map} +1 -1
  62. package/dist/esm/{search-dynamic-solve-fto-WROONLZS.js → search-dynamic-solve-fto-4LI23P6K.js} +253 -69
  63. package/dist/esm/{search-dynamic-solve-fto-WROONLZS.js.map → search-dynamic-solve-fto-4LI23P6K.js.map} +2 -2
  64. package/dist/esm/{search-dynamic-solve-kilominx-JVBOIWI2.js → search-dynamic-solve-kilominx-PIS3T2P4.js} +32 -8
  65. package/dist/esm/{search-dynamic-solve-kilominx-JVBOIWI2.js.map → search-dynamic-solve-kilominx-PIS3T2P4.js.map} +2 -2
  66. package/dist/esm/{search-dynamic-solve-master_tetraminx-3R2CJUKW.js → search-dynamic-solve-master_tetraminx-UB32C7MM.js} +111 -42
  67. package/dist/esm/{search-dynamic-solve-master_tetraminx-3R2CJUKW.js.map → search-dynamic-solve-master_tetraminx-UB32C7MM.js.map} +2 -2
  68. package/dist/esm/{search-dynamic-solve-sq1-RS5HN6AH.js → search-dynamic-solve-sq1-HA72TYF2.js} +54 -9
  69. package/dist/esm/{search-dynamic-solve-sq1-RS5HN6AH.js.map → search-dynamic-solve-sq1-HA72TYF2.js.map} +2 -2
  70. package/dist/esm/search-worker-inside-generated-string-HMA547DJ.js +3886 -0
  71. package/dist/esm/search-worker-inside-generated-string-HMA547DJ.js.map +7 -0
  72. package/dist/esm/{search-worker-js-entry-NTV7KFZ5.js → search-worker-js-entry-3QMPUE4B.js} +149 -55
  73. package/dist/esm/search-worker-js-entry-3QMPUE4B.js.map +7 -0
  74. package/dist/esm/{search-worker-ts-entry-EUKJTYA6.js → search-worker-ts-entry-3RHWJNVQ.js} +6 -6
  75. package/dist/esm/{search-worker-ts-entry-EUKJTYA6.js.map → search-worker-ts-entry-3RHWJNVQ.js.map} +1 -1
  76. package/dist/esm/stream/index.js +12 -8
  77. package/dist/esm/stream/index.js.map +1 -1
  78. package/dist/esm/twisty/index.js +1186 -1533
  79. package/dist/esm/twisty/index.js.map +4 -4
  80. package/dist/esm/{twisty-dynamic-3d-UJR5FP6R.js → twisty-dynamic-3d-2KRJEHAN.js} +358 -146
  81. package/dist/esm/twisty-dynamic-3d-2KRJEHAN.js.map +7 -0
  82. package/dist/types/{Alg-1b229e63.d.ts → Alg-137fb0d5.d.ts} +53 -46
  83. package/dist/types/{KState-7a536c23.d.ts → KState-d5f04c9a.d.ts} +1 -1
  84. package/dist/types/{TwizzleLink-0fbaf9bd.d.ts → TwizzleLink-43d94aca.d.ts} +57 -21
  85. package/dist/types/alg/index.d.ts +12 -8
  86. package/dist/types/bluetooth/index.d.ts +4 -4
  87. package/dist/types/{bluetooth-puzzle-7065b808.d.ts → bluetooth-puzzle-7e1a2576.d.ts} +9 -9
  88. package/dist/types/kpuzzle/index.d.ts +2 -2
  89. package/dist/types/notation/index.d.ts +1 -1
  90. package/dist/types/{outside-f12ca41a.d.ts → outside-f83e819a.d.ts} +2 -2
  91. package/dist/types/parseAlg-a28f7568.d.ts +9 -0
  92. package/dist/types/protocol/index.d.ts +2 -2
  93. package/dist/types/puzzle-geometry/index.d.ts +3 -3
  94. package/dist/types/puzzles/index.d.ts +5 -5
  95. package/dist/types/scramble/index.d.ts +3 -3
  96. package/dist/types/search/index.d.ts +3 -3
  97. package/dist/types/stream/index.d.ts +5 -5
  98. package/dist/types/twisty/index.d.ts +13 -6
  99. package/package.json +32 -28
  100. package/dist/esm/chunk-3Y4PK4XI.js.map +0 -7
  101. package/dist/esm/chunk-NQORDEXF.js.map +0 -7
  102. package/dist/esm/chunk-NS5XT5ZV.js +0 -4386
  103. package/dist/esm/chunk-NS5XT5ZV.js.map +0 -7
  104. package/dist/esm/chunk-RECTK3R2.js +0 -342
  105. package/dist/esm/chunk-RECTK3R2.js.map +0 -7
  106. package/dist/esm/chunk-VY7VF4MA.js.map +0 -7
  107. package/dist/esm/search-dynamic-sgs-side-events-4UF3XJRB.js.map +0 -7
  108. package/dist/esm/search-worker-inside-generated-string-KTF5N656.js +0 -3768
  109. package/dist/esm/search-worker-inside-generated-string-KTF5N656.js.map +0 -7
  110. package/dist/esm/search-worker-js-entry-NTV7KFZ5.js.map +0 -7
  111. package/dist/esm/twisty-dynamic-3d-UJR5FP6R.js.map +0 -7
  112. package/dist/types/parse-7cf1a92b.d.ts +0 -9
@@ -1,19 +1,4574 @@
1
1
  import {
2
- PGNotation,
3
- PUZZLE_BASE_SHAPES,
4
- PUZZLE_CUT_TYPES,
5
- PuzzleGeometry,
6
- Quat,
7
- getPG3DNamedPuzzles,
8
- getPuzzleDescriptionString,
9
- getPuzzleGeometryByDesc,
10
- getPuzzleGeometryByName,
11
- parseOptions,
12
- parsePuzzleDescription,
13
- schreierSims
14
- } from "../chunk-NS5XT5ZV.js";
15
- import "../chunk-NQORDEXF.js";
16
- import "../chunk-MGJA5U5O.js";
2
+ Move,
3
+ QuantumMove
4
+ } from "../chunk-PCR6JT2W.js";
5
+ import "../chunk-SBZRVSPK.js";
6
+
7
+ // src/cubing/puzzle-geometry/FaceNameSwizzler.ts
8
+ var FaceNameSwizzler = class {
9
+ constructor(facenames, gripnames_arg) {
10
+ this.facenames = facenames;
11
+ this.prefixFree = true;
12
+ this.gripnames = [];
13
+ if (gripnames_arg) {
14
+ this.gripnames = gripnames_arg;
15
+ }
16
+ for (let i = 0; this.prefixFree && i < facenames.length; i++) {
17
+ for (let j = 0; this.prefixFree && j < facenames.length; j++) {
18
+ if (i !== j && facenames[i].startsWith(facenames[j])) {
19
+ this.prefixFree = false;
20
+ }
21
+ }
22
+ }
23
+ }
24
+ setGripNames(names) {
25
+ this.gripnames = names;
26
+ }
27
+ splitByFaceNames(s) {
28
+ const r = [];
29
+ let at = 0;
30
+ while (at < s.length) {
31
+ if (at > 0 && at < s.length && s[at] === "_") {
32
+ at++;
33
+ }
34
+ let currentMatch = -1;
35
+ for (let i = 0; i < this.facenames.length; i++) {
36
+ if (s.substr(at).startsWith(this.facenames[i]) && (currentMatch < 0 || this.facenames[i].length > this.facenames[currentMatch].length)) {
37
+ currentMatch = i;
38
+ }
39
+ }
40
+ if (currentMatch >= 0) {
41
+ r.push(currentMatch);
42
+ at += this.facenames[currentMatch].length;
43
+ } else {
44
+ throw new Error("Could not split " + s + " into face names.");
45
+ }
46
+ }
47
+ return r;
48
+ }
49
+ joinByFaceIndices(list) {
50
+ let sep = "";
51
+ const r = [];
52
+ for (let i = 0; i < list.length; i++) {
53
+ r.push(sep);
54
+ r.push(this.facenames[list[i]]);
55
+ if (!this.prefixFree) {
56
+ sep = "_";
57
+ }
58
+ }
59
+ return r.join("");
60
+ }
61
+ spinmatch(userinput, longname) {
62
+ if (userinput === longname) {
63
+ return true;
64
+ }
65
+ try {
66
+ const e1 = this.splitByFaceNames(userinput);
67
+ const e2 = this.splitByFaceNames(longname);
68
+ if (e1.length !== e2.length && e1.length < 3) {
69
+ return false;
70
+ }
71
+ for (let i = 0; i < e1.length; i++) {
72
+ for (let j = 0; j < i; j++) {
73
+ if (e1[i] === e1[j]) {
74
+ return false;
75
+ }
76
+ }
77
+ let found = false;
78
+ for (let j = 0; j < e2.length; j++) {
79
+ if (e1[i] === e2[j]) {
80
+ found = true;
81
+ break;
82
+ }
83
+ }
84
+ if (!found) {
85
+ return false;
86
+ }
87
+ }
88
+ return true;
89
+ } catch (e) {
90
+ return false;
91
+ }
92
+ }
93
+ spinmatchv(userinput, longname) {
94
+ if (userinput.endsWith("v") && longname.endsWith("v")) {
95
+ return this.spinmatch(
96
+ userinput.slice(0, userinput.length - 1),
97
+ longname.slice(0, longname.length - 1)
98
+ );
99
+ } else {
100
+ return this.spinmatch(userinput, longname);
101
+ }
102
+ }
103
+ unswizzle(s) {
104
+ if ((s.endsWith("v") || s.endsWith("w")) && s[0] <= "Z") {
105
+ s = s.slice(0, s.length - 1);
106
+ }
107
+ const upperCaseGrip = s.toUpperCase();
108
+ for (let i = 0; i < this.gripnames.length; i++) {
109
+ const g = this.gripnames[i];
110
+ if (this.spinmatch(upperCaseGrip, g)) {
111
+ return g;
112
+ }
113
+ }
114
+ return s;
115
+ }
116
+ };
117
+
118
+ // src/cubing/puzzle-geometry/notation-mapping/NullMapper.ts
119
+ var NullMapper = class {
120
+ notationToInternal(move) {
121
+ return move;
122
+ }
123
+ notationToExternal(move) {
124
+ return move;
125
+ }
126
+ };
127
+
128
+ // src/cubing/puzzle-geometry/notation-mapping/FTONotationMapper.ts
129
+ var FTONotationMapper = class {
130
+ constructor(child, sw) {
131
+ this.child = child;
132
+ this.sw = sw;
133
+ }
134
+ notationToInternal(move) {
135
+ if (move.family === "T" && move.innerLayer === void 0 && move.outerLayer === void 0) {
136
+ return new Move(
137
+ new QuantumMove("FLRv", move.innerLayer, move.outerLayer),
138
+ move.amount
139
+ );
140
+ } else {
141
+ const r = this.child.notationToInternal(move);
142
+ return r;
143
+ }
144
+ }
145
+ notationToExternal(move) {
146
+ let fam = move.family;
147
+ if (fam.length > 0 && fam[fam.length - 1] === "v") {
148
+ fam = fam.substring(0, fam.length - 1);
149
+ }
150
+ if (this.sw.spinmatch(fam, "FLUR")) {
151
+ return new Move(
152
+ new QuantumMove("T", move.innerLayer, move.outerLayer),
153
+ move.amount
154
+ );
155
+ }
156
+ return this.child.notationToExternal(move);
157
+ }
158
+ };
159
+
160
+ // src/cubing/puzzle-geometry/notation-mapping/FaceRenamingMapper.ts
161
+ var FaceRenamingMapper = class {
162
+ constructor(internalNames, externalNames) {
163
+ this.internalNames = internalNames;
164
+ this.externalNames = externalNames;
165
+ }
166
+ convertString(grip, a, b) {
167
+ let suffix = "";
168
+ if ((grip.endsWith("v") || grip.endsWith("v")) && grip <= "_") {
169
+ suffix = grip.slice(grip.length - 1);
170
+ grip = grip.slice(0, grip.length - 1);
171
+ }
172
+ const upper = grip.toUpperCase();
173
+ let isLowerCase = false;
174
+ if (grip !== upper) {
175
+ isLowerCase = true;
176
+ grip = upper;
177
+ }
178
+ grip = b.joinByFaceIndices(a.splitByFaceNames(grip));
179
+ if (isLowerCase) {
180
+ grip = grip.toLowerCase();
181
+ }
182
+ return grip + suffix;
183
+ }
184
+ convert(move, a, b) {
185
+ const grip = move.family;
186
+ const ngrip = this.convertString(grip, a, b);
187
+ if (grip === ngrip) {
188
+ return move;
189
+ } else {
190
+ return new Move(
191
+ new QuantumMove(ngrip, move.innerLayer, move.outerLayer),
192
+ move.amount
193
+ );
194
+ }
195
+ }
196
+ notationToInternal(move) {
197
+ const r = this.convert(move, this.externalNames, this.internalNames);
198
+ return r;
199
+ }
200
+ notationToExternal(move) {
201
+ return this.convert(move, this.internalNames, this.externalNames);
202
+ }
203
+ };
204
+
205
+ // src/cubing/puzzle-geometry/notation-mapping/MegaminxScramblingNotationMapper.ts
206
+ var MegaminxScramblingNotationMapper = class {
207
+ constructor(child) {
208
+ this.child = child;
209
+ }
210
+ notationToInternal(move) {
211
+ if (move.innerLayer === void 0 && move.outerLayer === void 0) {
212
+ if (Math.abs(move.amount) === 1) {
213
+ if (move.family === "R++") {
214
+ return new Move(new QuantumMove("L", 3, 2), -2 * move.amount);
215
+ } else if (move.family === "R--") {
216
+ return new Move(new QuantumMove("L", 3, 2), 2 * move.amount);
217
+ } else if (move.family === "D++") {
218
+ return new Move(new QuantumMove("U", 3, 2), -2 * move.amount);
219
+ } else if (move.family === "D--") {
220
+ return new Move(new QuantumMove("U", 3, 2), 2 * move.amount);
221
+ }
222
+ if (move.family === "R_PLUSPLUS_") {
223
+ return new Move(new QuantumMove("L", 3, 2), -2 * move.amount);
224
+ } else if (move.family === "D_PLUSPLUS_") {
225
+ return new Move(new QuantumMove("U", 3, 2), -2 * move.amount);
226
+ }
227
+ }
228
+ if (move.family === "y") {
229
+ return new Move("Uv", move.amount);
230
+ }
231
+ if (move.family === "x" && Math.abs(move.amount) === 2) {
232
+ return new Move("ERv", move.amount / 2);
233
+ }
234
+ }
235
+ return this.child.notationToInternal(move);
236
+ }
237
+ notationToExternal(move) {
238
+ if (move.family === "ERv" && Math.abs(move.amount) === 1) {
239
+ return new Move(
240
+ new QuantumMove("x", move.innerLayer, move.outerLayer),
241
+ move.amount * 2
242
+ );
243
+ }
244
+ if (move.family === "ILv" && Math.abs(move.amount) === 1) {
245
+ return new Move(
246
+ new QuantumMove("x", move.innerLayer, move.outerLayer),
247
+ -move.amount * 2
248
+ );
249
+ }
250
+ if (move.family === "Uv") {
251
+ return new Move(
252
+ new QuantumMove("y", move.innerLayer, move.outerLayer),
253
+ move.amount
254
+ );
255
+ }
256
+ if (move.family === "Dv") {
257
+ return new Move("y", -move.amount);
258
+ }
259
+ return this.child.notationToExternal(move);
260
+ }
261
+ };
262
+
263
+ // src/cubing/puzzle-geometry/notation-mapping/NxNxNCubeMapper.ts
264
+ var NxNxNCubeMapper = class {
265
+ constructor(slices) {
266
+ this.slices = slices;
267
+ }
268
+ notationToInternal(move) {
269
+ const grip = move.family;
270
+ if (!move.innerLayer && !move.outerLayer) {
271
+ if (grip === "x") {
272
+ move = new Move("Rv", move.amount);
273
+ } else if (grip === "y") {
274
+ move = new Move("Uv", move.amount);
275
+ } else if (grip === "z") {
276
+ move = new Move("Fv", move.amount);
277
+ }
278
+ if ((this.slices & 1) === 1) {
279
+ if (grip === "E") {
280
+ move = new Move(
281
+ new QuantumMove("D", (this.slices + 1) / 2),
282
+ move.amount
283
+ );
284
+ } else if (grip === "M") {
285
+ move = new Move(
286
+ new QuantumMove("L", (this.slices + 1) / 2),
287
+ move.amount
288
+ );
289
+ } else if (grip === "S") {
290
+ move = new Move(
291
+ new QuantumMove("F", (this.slices + 1) / 2),
292
+ move.amount
293
+ );
294
+ }
295
+ }
296
+ if (this.slices > 2) {
297
+ if (grip === "e") {
298
+ move = new Move(
299
+ new QuantumMove("D", this.slices - 1, 2),
300
+ move.amount
301
+ );
302
+ } else if (grip === "m") {
303
+ move = new Move(
304
+ new QuantumMove("L", this.slices - 1, 2),
305
+ move.amount
306
+ );
307
+ } else if (grip === "s") {
308
+ move = new Move(
309
+ new QuantumMove("F", this.slices - 1, 2),
310
+ move.amount
311
+ );
312
+ }
313
+ }
314
+ }
315
+ return move;
316
+ }
317
+ notationToExternal(move) {
318
+ const grip = move.family;
319
+ if (!move.innerLayer && !move.outerLayer) {
320
+ if (grip === "Rv") {
321
+ return new Move("x", move.amount);
322
+ } else if (grip === "Uv") {
323
+ return new Move("y", move.amount);
324
+ } else if (grip === "Fv") {
325
+ return new Move("z", move.amount);
326
+ } else if (grip === "Lv") {
327
+ return new Move("x", -move.amount);
328
+ } else if (grip === "Dv") {
329
+ return new Move("y", -move.amount);
330
+ } else if (grip === "Bv") {
331
+ return new Move("z", -move.amount);
332
+ }
333
+ }
334
+ return move;
335
+ }
336
+ };
337
+
338
+ // src/cubing/puzzle-geometry/notation-mapping/PyraminxNotationMapper.ts
339
+ var pyraminxFamilyMap = {
340
+ U: "frl",
341
+ L: "fld",
342
+ R: "fdr",
343
+ B: "dlr",
344
+ u: "FRL",
345
+ l: "FLD",
346
+ r: "FDR",
347
+ b: "DLR",
348
+ Uv: "FRLv",
349
+ Lv: "FLDv",
350
+ Rv: "FDRv",
351
+ Bv: "DLRv",
352
+ D: "D",
353
+ F: "F",
354
+ BL: "L",
355
+ BR: "R"
356
+ };
357
+ var tetraminxFamilyMap = {
358
+ U: "FRL",
359
+ L: "FLD",
360
+ R: "FDR",
361
+ B: "DLR",
362
+ u: "frl",
363
+ l: "fld",
364
+ r: "fdr",
365
+ b: "dlr",
366
+ Uv: "FRLv",
367
+ Lv: "FLDv",
368
+ Rv: "FDRv",
369
+ Bv: "DLRv",
370
+ D: "D",
371
+ F: "F",
372
+ BL: "L",
373
+ BR: "R",
374
+ d: "d",
375
+ f: "f",
376
+ bl: "l",
377
+ br: "r"
378
+ };
379
+ var pyraminxFamilyMapWCA = {
380
+ U: "FRL",
381
+ L: "FLD",
382
+ R: "FDR",
383
+ B: "DLR"
384
+ };
385
+ var pyraminxExternalQuantumY = new QuantumMove("y");
386
+ var pyraminxInternalQuantumY = new QuantumMove("Dv");
387
+ var PyraminxNotationMapper = class {
388
+ constructor(child) {
389
+ this.child = child;
390
+ this.wcaHack = false;
391
+ this.map = pyraminxFamilyMap;
392
+ }
393
+ notationToInternal(move) {
394
+ if (this.wcaHack && move.innerLayer === 2 && move.outerLayer === null) {
395
+ const newFamilyWCA = pyraminxFamilyMapWCA[move.family];
396
+ if (newFamilyWCA) {
397
+ return new Move(
398
+ new QuantumMove(newFamilyWCA, move.innerLayer, move.outerLayer),
399
+ move.amount
400
+ );
401
+ }
402
+ }
403
+ const newFamily = this.map[move.family];
404
+ if (newFamily) {
405
+ return new Move(
406
+ new QuantumMove(newFamily, move.innerLayer, move.outerLayer),
407
+ move.amount
408
+ );
409
+ } else if (pyraminxExternalQuantumY.isIdentical(move.quantum)) {
410
+ return new Move(pyraminxInternalQuantumY, -move.amount);
411
+ } else {
412
+ return null;
413
+ }
414
+ }
415
+ notationToExternal(move) {
416
+ if (this.wcaHack && move.innerLayer === 2 && move.outerLayer === null) {
417
+ for (const [external, internal] of Object.entries(pyraminxFamilyMapWCA)) {
418
+ if (this.child.spinmatch(move.family, internal)) {
419
+ return new Move(
420
+ new QuantumMove(external, move.innerLayer, move.outerLayer),
421
+ move.amount
422
+ );
423
+ }
424
+ }
425
+ }
426
+ for (const [external, internal] of Object.entries(this.map)) {
427
+ if (this.child.spinmatch(move.family, internal)) {
428
+ return new Move(
429
+ new QuantumMove(external, move.innerLayer, move.outerLayer),
430
+ move.amount
431
+ );
432
+ }
433
+ }
434
+ if (pyraminxInternalQuantumY.isIdentical(move.quantum)) {
435
+ return new Move(pyraminxExternalQuantumY, -move.amount);
436
+ } else {
437
+ return null;
438
+ }
439
+ }
440
+ };
441
+ var TetraminxNotationMapper = class extends PyraminxNotationMapper {
442
+ constructor(child) {
443
+ super(child);
444
+ this.wcaHack = true;
445
+ this.map = tetraminxFamilyMap;
446
+ }
447
+ };
448
+
449
+ // src/cubing/puzzle-geometry/notation-mapping/SkewbNotationMapper.ts
450
+ var skewbFamilyMap = {
451
+ U: "UBL",
452
+ UL: "ULF",
453
+ F: "UFR",
454
+ UR: "URB",
455
+ B: "DBL",
456
+ D: "DFR",
457
+ L: "DLF",
458
+ R: "DRB",
459
+ Uv: "UBLv",
460
+ ULv: "ULFv",
461
+ Fv: "UFRv",
462
+ URv: "URBv",
463
+ Bv: "DBLv",
464
+ Dv: "DFRv",
465
+ Lv: "DLFv",
466
+ Rv: "DRBv"
467
+ };
468
+ var skewbExternalQuantumX = new QuantumMove("x");
469
+ var skewbInternalQuantumX = new QuantumMove("Rv");
470
+ var skewbInternalQuantumXPrime = new QuantumMove("Lv");
471
+ var skewbExternalQuantumY = new QuantumMove("y");
472
+ var skewbInternalQuantumY = new QuantumMove("Uv");
473
+ var skewbInternalQuantumYPrime = new QuantumMove("Dv");
474
+ var skewbExternalQuantumZ = new QuantumMove("z");
475
+ var skewbInternalQuantumZ = new QuantumMove("Fv");
476
+ var skewbInternalQuantumZPrime = new QuantumMove("Bv");
477
+ var SkewbNotationMapper = class {
478
+ constructor(child) {
479
+ this.child = child;
480
+ }
481
+ notationToInternal(move) {
482
+ if (move.innerLayer || move.outerLayer) {
483
+ return null;
484
+ }
485
+ const newFamily = skewbFamilyMap[move.family];
486
+ if (newFamily) {
487
+ return new Move(
488
+ new QuantumMove(newFamily, move.outerLayer, move.innerLayer),
489
+ move.amount
490
+ );
491
+ }
492
+ if (skewbExternalQuantumX.isIdentical(move.quantum)) {
493
+ return new Move(skewbInternalQuantumX, move.amount);
494
+ }
495
+ if (skewbExternalQuantumY.isIdentical(move.quantum)) {
496
+ return new Move(skewbInternalQuantumY, move.amount);
497
+ }
498
+ if (skewbExternalQuantumZ.isIdentical(move.quantum)) {
499
+ return new Move(skewbInternalQuantumZ, move.amount);
500
+ }
501
+ return null;
502
+ }
503
+ notationToExternal(move) {
504
+ for (const [external, internal] of Object.entries(skewbFamilyMap)) {
505
+ if (this.child.spinmatchv(move.family, internal)) {
506
+ return new Move(
507
+ new QuantumMove(external, move.innerLayer, move.outerLayer),
508
+ move.amount
509
+ );
510
+ }
511
+ }
512
+ if (skewbInternalQuantumX.isIdentical(move.quantum)) {
513
+ return new Move(skewbExternalQuantumX, move.amount);
514
+ }
515
+ if (skewbInternalQuantumXPrime.isIdentical(move.quantum)) {
516
+ return new Move(skewbExternalQuantumX, -move.amount);
517
+ }
518
+ if (skewbInternalQuantumY.isIdentical(move.quantum)) {
519
+ return new Move(skewbExternalQuantumY, move.amount);
520
+ }
521
+ if (skewbInternalQuantumYPrime.isIdentical(move.quantum)) {
522
+ return new Move(skewbExternalQuantumY, -move.amount);
523
+ }
524
+ if (skewbInternalQuantumZ.isIdentical(move.quantum)) {
525
+ return new Move(skewbExternalQuantumZ, move.amount);
526
+ }
527
+ if (skewbInternalQuantumZPrime.isIdentical(move.quantum)) {
528
+ return new Move(skewbExternalQuantumZ, -move.amount);
529
+ }
530
+ return null;
531
+ }
532
+ };
533
+
534
+ // src/cubing/puzzle-geometry/Options.ts
535
+ function parseOptions(argv) {
536
+ let argp = 0;
537
+ const options = {};
538
+ while (argp < argv.length && argv[argp][0] === "-") {
539
+ const option = argv[argp++];
540
+ if (option === "--rotations") {
541
+ options.addRotations = true;
542
+ } else if (option === "--allmoves") {
543
+ options.allMoves = true;
544
+ } else if (option === "--outerblockmoves") {
545
+ options.outerBlockMoves = true;
546
+ } else if (option === "--vertexmoves") {
547
+ options.vertexMoves = true;
548
+ } else if (option === "--nocorners") {
549
+ options.includeCornerOrbits = false;
550
+ } else if (option === "--noedges") {
551
+ options.includeEdgeOrbits = false;
552
+ } else if (option === "--noorientation") {
553
+ options.fixedOrientation = true;
554
+ } else if (option === "--nocenters") {
555
+ options.includeCenterOrbits = false;
556
+ } else if (option === "--omit") {
557
+ options.excludeOrbits = argv[argp].split(",");
558
+ argp++;
559
+ } else if (option === "--moves") {
560
+ options.moveList = argv[argp].split(",");
561
+ argp++;
562
+ } else if (option === "--optimize") {
563
+ options.optimizeOrbits = true;
564
+ } else if (option === "--scramble") {
565
+ options.scrambleAmount = 100;
566
+ } else if (option === "--fixcorner") {
567
+ options.fixedPieceType = "v";
568
+ } else if (option === "--fixedge") {
569
+ options.fixedPieceType = "e";
570
+ } else if (option === "--fixcenter") {
571
+ options.fixedPieceType = "f";
572
+ } else if (option === "--orientcenters") {
573
+ options.orientCenters = true;
574
+ } else if (option === "--puzzleorientation") {
575
+ options.puzzleOrientation = JSON.parse(argv[argp]);
576
+ argp++;
577
+ } else {
578
+ throw new Error("Bad option: " + option);
579
+ }
580
+ }
581
+ const puzzleDescription = parsePuzzleDescription(argv.slice(argp).join(" "));
582
+ return { puzzleDescription, options };
583
+ }
584
+ var PuzzleGeometryFullOptions = class {
585
+ constructor(options = {}) {
586
+ this.verbosity = 0;
587
+ this.allMoves = false;
588
+ this.vertexMoves = false;
589
+ this.addRotations = false;
590
+ this.moveList = null;
591
+ this.fixedOrientation = false;
592
+ this.fixedPieceType = null;
593
+ this.orientCenters = false;
594
+ this.includeCornerOrbits = true;
595
+ this.includeCenterOrbits = true;
596
+ this.includeEdgeOrbits = true;
597
+ this.excludeOrbits = [];
598
+ this.optimizeOrbits = false;
599
+ this.grayCorners = false;
600
+ this.grayCenters = false;
601
+ this.grayEdges = false;
602
+ this.puzzleOrientation = null;
603
+ this.puzzleOrientations = null;
604
+ this.scrambleAmount = 0;
605
+ Object.assign(this, options);
606
+ }
607
+ };
608
+
609
+ // src/cubing/puzzle-geometry/Perm.ts
610
+ var zeroCache = [];
611
+ var iotaCache = [];
612
+ function zeros(n) {
613
+ if (!zeroCache[n]) {
614
+ const c = Array(n);
615
+ for (let i = 0; i < n; i++) {
616
+ c[i] = 0;
617
+ }
618
+ zeroCache[n] = c;
619
+ }
620
+ return zeroCache[n];
621
+ }
622
+ function iota(n) {
623
+ if (!iotaCache[n]) {
624
+ const c = Array(n);
625
+ for (let i = 0; i < n; i++) {
626
+ c[i] = i;
627
+ }
628
+ iotaCache[n] = c;
629
+ }
630
+ return iotaCache[n];
631
+ }
632
+ function identity(n) {
633
+ return new Perm(iota(n));
634
+ }
635
+ function factorial(a) {
636
+ let r = 1n;
637
+ while (a > 1) {
638
+ r *= BigInt(a);
639
+ a--;
640
+ }
641
+ return r;
642
+ }
643
+ function gcd(a, b) {
644
+ if (a > b) {
645
+ const t = a;
646
+ a = b;
647
+ b = t;
648
+ }
649
+ while (a > 0) {
650
+ const m = b % a;
651
+ b = a;
652
+ a = m;
653
+ }
654
+ return b;
655
+ }
656
+ function lcm(a, b) {
657
+ return a / gcd(a, b) * b;
658
+ }
659
+ var Perm = class {
660
+ constructor(a) {
661
+ this.n = a.length;
662
+ this.p = a;
663
+ }
664
+ toString() {
665
+ return "Perm[" + this.p.join(" ") + "]";
666
+ }
667
+ mul(p2) {
668
+ const c = Array(this.n);
669
+ for (let i = 0; i < this.n; i++) {
670
+ c[i] = p2.p[this.p[i]];
671
+ }
672
+ return new Perm(c);
673
+ }
674
+ rmul(p2) {
675
+ const c = Array(this.n);
676
+ for (let i = 0; i < this.n; i++) {
677
+ c[i] = this.p[p2.p[i]];
678
+ }
679
+ return new Perm(c);
680
+ }
681
+ inv() {
682
+ const c = Array(this.n);
683
+ for (let i = 0; i < this.n; i++) {
684
+ c[this.p[i]] = i;
685
+ }
686
+ return new Perm(c);
687
+ }
688
+ compareTo(p2) {
689
+ for (let i = 0; i < this.n; i++) {
690
+ if (this.p[i] !== p2.p[i]) {
691
+ return this.p[i] - p2.p[i];
692
+ }
693
+ }
694
+ return 0;
695
+ }
696
+ toGap() {
697
+ const cyc = new Array();
698
+ const seen = new Array(this.n);
699
+ for (let i = 0; i < this.p.length; i++) {
700
+ if (seen[i] || this.p[i] === i) {
701
+ continue;
702
+ }
703
+ const incyc = new Array();
704
+ for (let j = i; !seen[j]; j = this.p[j]) {
705
+ incyc.push(1 + j);
706
+ seen[j] = true;
707
+ }
708
+ cyc.push("(" + incyc.join(",") + ")");
709
+ }
710
+ return cyc.join("");
711
+ }
712
+ order() {
713
+ let r = 1;
714
+ const seen = new Array(this.n);
715
+ for (let i = 0; i < this.p.length; i++) {
716
+ if (seen[i] || this.p[i] === i) {
717
+ continue;
718
+ }
719
+ let cs = 0;
720
+ for (let j = i; !seen[j]; j = this.p[j]) {
721
+ cs++;
722
+ seen[j] = true;
723
+ }
724
+ r = lcm(r, cs);
725
+ }
726
+ return r;
727
+ }
728
+ };
729
+
730
+ // src/cubing/puzzle-geometry/PermOriSet.ts
731
+ var PGOrbitDef = class {
732
+ constructor(size, mod) {
733
+ this.size = size;
734
+ this.mod = mod;
735
+ }
736
+ reassemblySize() {
737
+ return factorial(this.size) * BigInt(this.mod) ** BigInt(this.size);
738
+ }
739
+ };
740
+ var lastGlobalDefinitionCounter = 0;
741
+ function externalName(mapper, moveString) {
742
+ const mv = Move.fromString(moveString);
743
+ const mv2 = mapper.notationToExternal(mv);
744
+ if (mv2 === null || mv === mv2) {
745
+ return moveString;
746
+ }
747
+ return mv2.toString();
748
+ }
749
+ var PGOrbitsDef = class {
750
+ constructor(orbitnames, orbitdefs, solved, movenames, moveops, isRotation, forcenames) {
751
+ this.orbitnames = orbitnames;
752
+ this.orbitdefs = orbitdefs;
753
+ this.solved = solved;
754
+ this.movenames = movenames;
755
+ this.moveops = moveops;
756
+ this.isRotation = isRotation;
757
+ this.forcenames = forcenames;
758
+ }
759
+ transformToKTransformationData(t) {
760
+ const mp = {};
761
+ for (let j = 0; j < this.orbitnames.length; j++) {
762
+ mp[this.orbitnames[j]] = t.orbits[j].toKPuzzle();
763
+ }
764
+ return mp;
765
+ }
766
+ static transformToKTransformationData(orbitnames, t) {
767
+ const mp = {};
768
+ for (let j = 0; j < orbitnames.length; j++) {
769
+ mp[orbitnames[j]] = t.orbits[j].toKPuzzle();
770
+ }
771
+ return mp;
772
+ }
773
+ describeSet(s, r, mapper) {
774
+ const n = this.orbitdefs[s].size;
775
+ const m = new Array(n);
776
+ for (let i = 0; i < n; i++) {
777
+ m[i] = [];
778
+ }
779
+ for (let i = 0; i < this.movenames.length; i++) {
780
+ if (this.isRotation[i]) {
781
+ continue;
782
+ }
783
+ let mvname = this.movenames[i];
784
+ if (!this.forcenames[i]) {
785
+ mvname = externalName(mapper, mvname);
786
+ if (mvname[mvname.length - 1] === "'") {
787
+ mvname = mvname.substring(0, mvname.length - 1);
788
+ }
789
+ }
790
+ const pd = this.moveops[i].orbits[s];
791
+ for (let j = 0; j < n; j++) {
792
+ if (pd.perm[j] != j || pd.ori[j] != 0) {
793
+ m[j].push(mvname);
794
+ }
795
+ }
796
+ }
797
+ for (let j = 0; j < n; j++) {
798
+ r.push("# " + (j + 1) + " " + m[j].join(" "));
799
+ }
800
+ }
801
+ toKsolve(name, mapper = new NullMapper()) {
802
+ const result = [];
803
+ result.push("Name " + name);
804
+ result.push("");
805
+ for (let i = 0; i < this.orbitnames.length; i++) {
806
+ result.push(
807
+ `Set ${this.orbitnames[i]} ${this.orbitdefs[i].size} ${this.orbitdefs[i].mod}`
808
+ );
809
+ this.describeSet(i, result, mapper);
810
+ }
811
+ result.push("");
812
+ result.push("Solved");
813
+ for (let i = 0; i < this.orbitnames.length; i++) {
814
+ this.solved.orbits[i].appendDefinition(
815
+ result,
816
+ this.orbitnames[i],
817
+ false,
818
+ false
819
+ );
820
+ }
821
+ result.push("End");
822
+ for (let i = 0; i < this.movenames.length; i++) {
823
+ result.push("");
824
+ let name2 = this.movenames[i];
825
+ if (!this.forcenames[i]) {
826
+ name2 = externalName(mapper, this.movenames[i]);
827
+ }
828
+ let doinv = false;
829
+ if (name2[name2.length - 1] === "'") {
830
+ doinv = true;
831
+ name2 = name2.substring(0, name2.length - 1);
832
+ }
833
+ result.push("Move " + name2);
834
+ for (let j = 0; j < this.orbitnames.length; j++) {
835
+ if (doinv) {
836
+ this.moveops[i].orbits[j].inv().appendDefinition(result, this.orbitnames[j], true);
837
+ } else {
838
+ this.moveops[i].orbits[j].appendDefinition(
839
+ result,
840
+ this.orbitnames[j],
841
+ true
842
+ );
843
+ }
844
+ }
845
+ result.push("End");
846
+ }
847
+ return result;
848
+ }
849
+ toKPuzzleDefinition(includemoves) {
850
+ const orbits = {};
851
+ const start = {};
852
+ for (let i = 0; i < this.orbitnames.length; i++) {
853
+ orbits[this.orbitnames[i]] = {
854
+ numPieces: this.orbitdefs[i].size,
855
+ numOrientations: this.orbitdefs[i].mod
856
+ };
857
+ const startTransformation = this.solved.orbits[i].toKPuzzle();
858
+ start[this.orbitnames[i]] = {
859
+ pieces: startTransformation.permutation,
860
+ orientation: startTransformation.orientation
861
+ };
862
+ }
863
+ const moves = {};
864
+ if (includemoves) {
865
+ for (let i = 0; i < this.movenames.length; i++) {
866
+ moves[this.movenames[i]] = this.transformToKTransformationData(
867
+ this.moveops[i]
868
+ );
869
+ }
870
+ }
871
+ return {
872
+ name: `PG3D #${++lastGlobalDefinitionCounter}`,
873
+ orbits,
874
+ startStateData: start,
875
+ moves
876
+ };
877
+ }
878
+ optimize() {
879
+ const neworbitnames = [];
880
+ const neworbitdefs = [];
881
+ const newsolved = [];
882
+ const newmoveops = [];
883
+ for (let j = 0; j < this.moveops.length; j++) {
884
+ newmoveops.push([]);
885
+ }
886
+ for (let i = 0; i < this.orbitdefs.length; i++) {
887
+ const om = this.orbitdefs[i].mod;
888
+ const n = this.orbitdefs[i].size;
889
+ const du = new DisjointUnion(n);
890
+ const changed = new Array(this.orbitdefs[i].size);
891
+ for (let k = 0; k < n; k++) {
892
+ changed[k] = false;
893
+ }
894
+ for (let j = 0; j < this.moveops.length; j++) {
895
+ if (!this.isRotation[j]) {
896
+ for (let k = 0; k < n; k++) {
897
+ if (this.moveops[j].orbits[i].perm[k] !== k || this.moveops[j].orbits[i].ori[k] !== 0) {
898
+ changed[k] = true;
899
+ du.union(k, this.moveops[j].orbits[i].perm[k]);
900
+ }
901
+ }
902
+ }
903
+ }
904
+ let keepori = true;
905
+ if (om > 1) {
906
+ keepori = false;
907
+ const duo = new DisjointUnion(this.orbitdefs[i].size * om);
908
+ for (let j = 0; j < this.moveops.length; j++) {
909
+ for (let k = 0; k < n; k++) {
910
+ if (this.moveops[j].orbits[i].perm[k] !== k || this.moveops[j].orbits[i].ori[k] !== 0) {
911
+ for (let o = 0; o < om; o++) {
912
+ duo.union(
913
+ k * om + o,
914
+ this.moveops[j].orbits[i].perm[k] * om + (o + this.moveops[j].orbits[i].ori[k]) % om
915
+ );
916
+ }
917
+ }
918
+ }
919
+ }
920
+ for (let j = 0; !keepori && j < n; j++) {
921
+ for (let o = 1; o < om; o++) {
922
+ if (duo.find(j * om) === duo.find(j * om + o)) {
923
+ keepori = true;
924
+ }
925
+ }
926
+ }
927
+ for (let j = 0; !keepori && j < n; j++) {
928
+ for (let k = 0; k < j; k++) {
929
+ if (this.solved.orbits[i].perm[j] === this.solved.orbits[i].perm[k]) {
930
+ keepori = true;
931
+ }
932
+ }
933
+ }
934
+ }
935
+ let nontriv = -1;
936
+ let multiple = false;
937
+ for (let j = 0; j < this.orbitdefs[i].size; j++) {
938
+ if (changed[j]) {
939
+ const h = du.find(j);
940
+ if (nontriv < 0) {
941
+ nontriv = h;
942
+ } else if (nontriv !== h) {
943
+ multiple = true;
944
+ }
945
+ }
946
+ }
947
+ for (let j = 0; j < this.orbitdefs[i].size; j++) {
948
+ if (!changed[j]) {
949
+ continue;
950
+ }
951
+ const h = du.find(j);
952
+ if (h !== j) {
953
+ continue;
954
+ }
955
+ const no = [];
956
+ const on = [];
957
+ let nv = 0;
958
+ for (let k = 0; k < this.orbitdefs[i].size; k++) {
959
+ if (du.find(k) === j) {
960
+ no[nv] = k;
961
+ on[k] = nv;
962
+ nv++;
963
+ }
964
+ }
965
+ if (multiple) {
966
+ neworbitnames.push(`${this.orbitnames[i]}_p${j}`);
967
+ } else {
968
+ neworbitnames.push(this.orbitnames[i]);
969
+ }
970
+ if (keepori) {
971
+ neworbitdefs.push(new PGOrbitDef(nv, this.orbitdefs[i].mod));
972
+ newsolved.push(this.solved.orbits[i].remapVS(no, nv));
973
+ for (let k = 0; k < this.moveops.length; k++) {
974
+ newmoveops[k].push(this.moveops[k].orbits[i].remap(no, on, nv));
975
+ }
976
+ } else {
977
+ neworbitdefs.push(new PGOrbitDef(nv, 1));
978
+ newsolved.push(this.solved.orbits[i].remapVS(no, nv).killOri());
979
+ for (let k = 0; k < this.moveops.length; k++) {
980
+ newmoveops[k].push(
981
+ this.moveops[k].orbits[i].remap(no, on, nv).killOri()
982
+ );
983
+ }
984
+ }
985
+ }
986
+ }
987
+ return new PGOrbitsDef(
988
+ neworbitnames,
989
+ neworbitdefs,
990
+ new VisibleState(newsolved),
991
+ this.movenames,
992
+ newmoveops.map((_) => new PGTransform(_)),
993
+ this.isRotation,
994
+ this.forcenames
995
+ );
996
+ }
997
+ scramble(n) {
998
+ this.solved = this.solved.mul(this.getScrambleTransformation(n));
999
+ }
1000
+ getScrambleTransformation(n) {
1001
+ if (n < 100) {
1002
+ n = 100;
1003
+ }
1004
+ const pool = [];
1005
+ for (let i = 0; i < this.moveops.length; i++) {
1006
+ pool[i] = this.moveops[i];
1007
+ }
1008
+ for (let i = 0; i < pool.length; i++) {
1009
+ const j = Math.floor(Math.random() * pool.length);
1010
+ const t = pool[i];
1011
+ pool[i] = pool[j];
1012
+ pool[j] = t;
1013
+ }
1014
+ if (n < pool.length) {
1015
+ n = pool.length;
1016
+ }
1017
+ for (let i = 0; i < n; i++) {
1018
+ const ri = Math.floor(Math.random() * pool.length);
1019
+ const rj = Math.floor(Math.random() * pool.length);
1020
+ const rm = Math.floor(Math.random() * this.moveops.length);
1021
+ pool[ri] = pool[ri].mul(pool[rj]).mul(this.moveops[rm]);
1022
+ if (Math.random() < 0.1) {
1023
+ pool[ri] = pool[ri].mul(this.moveops[rm]);
1024
+ }
1025
+ }
1026
+ let s = pool[0];
1027
+ for (let i = 1; i < pool.length; i++) {
1028
+ s = s.mul(pool[i]);
1029
+ }
1030
+ return s;
1031
+ }
1032
+ reassemblySize() {
1033
+ let n = 1n;
1034
+ for (let i = 0; i < this.orbitdefs.length; i++) {
1035
+ n *= this.orbitdefs[i].reassemblySize();
1036
+ }
1037
+ return n;
1038
+ }
1039
+ };
1040
+ var _PGOrbit = class {
1041
+ constructor(perm, ori, orimod) {
1042
+ this.perm = perm;
1043
+ this.ori = ori;
1044
+ this.orimod = orimod;
1045
+ }
1046
+ static e(n, mod) {
1047
+ return new _PGOrbit(iota(n), zeros(n), mod);
1048
+ }
1049
+ mul(b) {
1050
+ const n = this.perm.length;
1051
+ const newPerm = new Array(n);
1052
+ if (this.orimod === 1) {
1053
+ for (let i = 0; i < n; i++) {
1054
+ newPerm[i] = this.perm[b.perm[i]];
1055
+ }
1056
+ return new _PGOrbit(newPerm, this.ori, this.orimod);
1057
+ } else {
1058
+ const newOri = new Array(n);
1059
+ for (let i = 0; i < n; i++) {
1060
+ newPerm[i] = this.perm[b.perm[i]];
1061
+ newOri[i] = (this.ori[b.perm[i]] + b.ori[i]) % this.orimod;
1062
+ }
1063
+ return new _PGOrbit(newPerm, newOri, this.orimod);
1064
+ }
1065
+ }
1066
+ inv() {
1067
+ const n = this.perm.length;
1068
+ const newPerm = new Array(n);
1069
+ const newOri = new Array(n);
1070
+ for (let i = 0; i < n; i++) {
1071
+ newPerm[this.perm[i]] = i;
1072
+ newOri[this.perm[i]] = (this.orimod - this.ori[i]) % this.orimod;
1073
+ }
1074
+ return new _PGOrbit(newPerm, newOri, this.orimod);
1075
+ }
1076
+ equal(b) {
1077
+ const n = this.perm.length;
1078
+ for (let i = 0; i < n; i++) {
1079
+ if (this.perm[i] !== b.perm[i] || this.ori[i] !== b.ori[i]) {
1080
+ return false;
1081
+ }
1082
+ }
1083
+ return true;
1084
+ }
1085
+ killOri() {
1086
+ const n = this.perm.length;
1087
+ for (let i = 0; i < n; i++) {
1088
+ this.ori[i] = 0;
1089
+ }
1090
+ this.orimod = 1;
1091
+ return this;
1092
+ }
1093
+ toPerm() {
1094
+ const o = this.orimod;
1095
+ if (o === 1) {
1096
+ return new Perm(this.perm);
1097
+ }
1098
+ const n = this.perm.length;
1099
+ const newPerm = new Array(n * o);
1100
+ for (let i = 0; i < n; i++) {
1101
+ for (let j = 0; j < o; j++) {
1102
+ newPerm[i * o + j] = o * this.perm[i] + (this.ori[i] + j) % o;
1103
+ }
1104
+ }
1105
+ return new Perm(newPerm);
1106
+ }
1107
+ identicalPieces() {
1108
+ const done = [];
1109
+ const n = this.perm.length;
1110
+ const r = [];
1111
+ for (let i = 0; i < n; i++) {
1112
+ const v = this.perm[i];
1113
+ if (done[v] === void 0) {
1114
+ const s = [i];
1115
+ done[v] = true;
1116
+ for (let j = i + 1; j < n; j++) {
1117
+ if (this.perm[j] === v) {
1118
+ s.push(j);
1119
+ }
1120
+ }
1121
+ r.push(s);
1122
+ }
1123
+ }
1124
+ return r;
1125
+ }
1126
+ order() {
1127
+ return this.toPerm().order();
1128
+ }
1129
+ isIdentity() {
1130
+ const n = this.perm.length;
1131
+ if (this.perm === iota(n) && this.ori === zeros(n)) {
1132
+ return true;
1133
+ }
1134
+ for (let i = 0; i < n; i++) {
1135
+ if (this.perm[i] !== i || this.ori[i] !== 0) {
1136
+ return false;
1137
+ }
1138
+ }
1139
+ return true;
1140
+ }
1141
+ zeroOris() {
1142
+ const n = this.perm.length;
1143
+ if (this.ori === zeros(n)) {
1144
+ return true;
1145
+ }
1146
+ for (let i = 0; i < n; i++) {
1147
+ if (this.ori[i] !== 0) {
1148
+ return false;
1149
+ }
1150
+ }
1151
+ return true;
1152
+ }
1153
+ remap(no, on, nv) {
1154
+ const newPerm = new Array(nv);
1155
+ const newOri = new Array(nv);
1156
+ for (let i = 0; i < nv; i++) {
1157
+ newPerm[i] = on[this.perm[no[i]]];
1158
+ newOri[i] = this.ori[no[i]];
1159
+ }
1160
+ return new _PGOrbit(newPerm, newOri, this.orimod);
1161
+ }
1162
+ remapVS(no, nv) {
1163
+ const newPerm = new Array(nv);
1164
+ const newOri = new Array(nv);
1165
+ let nextNew = 0;
1166
+ const reassign = [];
1167
+ for (let i = 0; i < nv; i++) {
1168
+ const ov = this.perm[no[i]];
1169
+ if (reassign[ov] === void 0) {
1170
+ reassign[ov] = nextNew++;
1171
+ }
1172
+ newPerm[i] = reassign[ov];
1173
+ newOri[i] = this.ori[no[i]];
1174
+ }
1175
+ return new _PGOrbit(newPerm, newOri, this.orimod);
1176
+ }
1177
+ appendDefinition(result, name, useVS, concise = true) {
1178
+ if (concise && this.isIdentity()) {
1179
+ return;
1180
+ }
1181
+ result.push(name);
1182
+ result.push(this.perm.map((_) => _ + 1).join(" "));
1183
+ if (!this.zeroOris()) {
1184
+ if (useVS) {
1185
+ const newori = new Array(this.ori.length);
1186
+ for (let i = 0; i < newori.length; i++) {
1187
+ newori[this.perm[i]] = this.ori[i];
1188
+ }
1189
+ result.push(newori.join(" "));
1190
+ } else {
1191
+ result.push(this.ori.join(" "));
1192
+ }
1193
+ }
1194
+ }
1195
+ toKPuzzle() {
1196
+ const n = this.perm.length;
1197
+ if (this.isIdentity()) {
1198
+ if (!_PGOrbit.kcache[n]) {
1199
+ _PGOrbit.kcache[n] = { permutation: iota(n), orientation: zeros(n) };
1200
+ }
1201
+ return _PGOrbit.kcache[n];
1202
+ } else {
1203
+ return { permutation: this.perm, orientation: this.ori };
1204
+ }
1205
+ }
1206
+ };
1207
+ var PGOrbit = _PGOrbit;
1208
+ PGOrbit.kcache = [];
1209
+ var PGTransformBase = class {
1210
+ constructor(orbits) {
1211
+ this.orbits = orbits;
1212
+ }
1213
+ internalMul(b) {
1214
+ const newOrbits = [];
1215
+ for (let i = 0; i < this.orbits.length; i++) {
1216
+ newOrbits.push(this.orbits[i].mul(b.orbits[i]));
1217
+ }
1218
+ return newOrbits;
1219
+ }
1220
+ internalInv() {
1221
+ const newOrbits = [];
1222
+ for (const orbit of this.orbits) {
1223
+ newOrbits.push(orbit.inv());
1224
+ }
1225
+ return newOrbits;
1226
+ }
1227
+ equal(b) {
1228
+ for (let i = 0; i < this.orbits.length; i++) {
1229
+ if (!this.orbits[i].equal(b.orbits[i])) {
1230
+ return false;
1231
+ }
1232
+ }
1233
+ return true;
1234
+ }
1235
+ killOri() {
1236
+ for (const orbit of this.orbits) {
1237
+ orbit.killOri();
1238
+ }
1239
+ return this;
1240
+ }
1241
+ toPerm() {
1242
+ const perms = new Array();
1243
+ let n = 0;
1244
+ for (const orbit of this.orbits) {
1245
+ const p = orbit.toPerm();
1246
+ perms.push(p);
1247
+ n += p.n;
1248
+ }
1249
+ const newPerm = new Array(n);
1250
+ n = 0;
1251
+ for (const p of perms) {
1252
+ for (let j = 0; j < p.n; j++) {
1253
+ newPerm[n + j] = n + p.p[j];
1254
+ }
1255
+ n += p.n;
1256
+ }
1257
+ return new Perm(newPerm);
1258
+ }
1259
+ identicalPieces() {
1260
+ const r = [];
1261
+ let n = 0;
1262
+ for (const orbit of this.orbits) {
1263
+ const o = orbit.orimod;
1264
+ const s = orbit.identicalPieces();
1265
+ for (let j = 0; j < s.length; j++) {
1266
+ r.push(s[j].map((_) => _ * o + n));
1267
+ }
1268
+ n += o * orbit.perm.length;
1269
+ }
1270
+ return r;
1271
+ }
1272
+ order() {
1273
+ let r = 1;
1274
+ for (const orbit of this.orbits) {
1275
+ r = lcm(r, orbit.order());
1276
+ }
1277
+ return r;
1278
+ }
1279
+ };
1280
+ var PGTransform = class extends PGTransformBase {
1281
+ constructor(orbits) {
1282
+ super(orbits);
1283
+ }
1284
+ mul(b) {
1285
+ return new PGTransform(this.internalMul(b));
1286
+ }
1287
+ mulScalar(n) {
1288
+ if (n === 0) {
1289
+ return this.e();
1290
+ }
1291
+ let t = this;
1292
+ if (n < 0) {
1293
+ t = t.inv();
1294
+ n = -n;
1295
+ }
1296
+ while ((n & 1) === 0) {
1297
+ t = t.mul(t);
1298
+ n >>= 1;
1299
+ }
1300
+ if (n === 1) {
1301
+ return t;
1302
+ }
1303
+ let s = t;
1304
+ let r = this.e();
1305
+ while (n > 0) {
1306
+ if (n & 1) {
1307
+ r = r.mul(s);
1308
+ }
1309
+ if (n > 1) {
1310
+ s = s.mul(s);
1311
+ }
1312
+ n >>= 1;
1313
+ }
1314
+ return r;
1315
+ }
1316
+ inv() {
1317
+ return new PGTransform(this.internalInv());
1318
+ }
1319
+ e() {
1320
+ return new PGTransform(
1321
+ this.orbits.map((_) => PGOrbit.e(_.perm.length, _.orimod))
1322
+ );
1323
+ }
1324
+ };
1325
+ var VisibleState = class extends PGTransformBase {
1326
+ constructor(orbits) {
1327
+ super(orbits);
1328
+ }
1329
+ mul(b) {
1330
+ return new VisibleState(this.internalMul(b));
1331
+ }
1332
+ };
1333
+ var DisjointUnion = class {
1334
+ constructor(n) {
1335
+ this.n = n;
1336
+ this.heads = new Array(n);
1337
+ for (let i = 0; i < n; i++) {
1338
+ this.heads[i] = i;
1339
+ }
1340
+ }
1341
+ find(v) {
1342
+ let h = this.heads[v];
1343
+ if (this.heads[h] === h) {
1344
+ return h;
1345
+ }
1346
+ h = this.find(this.heads[h]);
1347
+ this.heads[v] = h;
1348
+ return h;
1349
+ }
1350
+ union(a, b) {
1351
+ const ah = this.find(a);
1352
+ const bh = this.find(b);
1353
+ if (ah < bh) {
1354
+ this.heads[bh] = ah;
1355
+ } else if (ah > bh) {
1356
+ this.heads[ah] = bh;
1357
+ }
1358
+ }
1359
+ };
1360
+ function showcanon(g, disp) {
1361
+ const n = g.moveops.length;
1362
+ if (n > 30) {
1363
+ throw new Error("Canon info too big for bitmask");
1364
+ }
1365
+ const orders = [];
1366
+ const commutes = [];
1367
+ for (let i = 0; i < n; i++) {
1368
+ const permA = g.moveops[i];
1369
+ orders.push(permA.order());
1370
+ let bits = 0;
1371
+ for (let j = 0; j < n; j++) {
1372
+ if (j === i) {
1373
+ continue;
1374
+ }
1375
+ const permB = g.moveops[j];
1376
+ if (permA.mul(permB).equal(permB.mul(permA))) {
1377
+ bits |= 1 << j;
1378
+ }
1379
+ }
1380
+ commutes.push(bits);
1381
+ }
1382
+ let curlev = {};
1383
+ curlev[0] = 1;
1384
+ for (let d = 0; d < 100; d++) {
1385
+ let sum = 0;
1386
+ const nextlev = {};
1387
+ let uniq = 0;
1388
+ for (const sti in curlev) {
1389
+ const st = +sti;
1390
+ const cnt = curlev[st];
1391
+ sum += cnt;
1392
+ uniq++;
1393
+ for (let mv = 0; mv < orders.length; mv++) {
1394
+ if ((st >> mv & 1) === 0 && (st & commutes[mv] & (1 << mv) - 1) === 0) {
1395
+ const nst = st & commutes[mv] | 1 << mv;
1396
+ if (nextlev[nst] === void 0) {
1397
+ nextlev[nst] = 0;
1398
+ }
1399
+ nextlev[nst] += (orders[mv] - 1) * cnt;
1400
+ }
1401
+ }
1402
+ }
1403
+ disp(`${d}: canonseq ${sum} states ${uniq}`);
1404
+ curlev = nextlev;
1405
+ }
1406
+ }
1407
+
1408
+ // src/cubing/puzzle-geometry/PGPuzzles.ts
1409
+ var PGPuzzles = {
1410
+ "2x2x2": "c f 0",
1411
+ "3x3x3": "c f 0.333333333333333",
1412
+ "4x4x4": "c f 0.5 f 0",
1413
+ "5x5x5": "c f 0.6 f 0.2",
1414
+ "6x6x6": "c f 0.666666666666667 f 0.333333333333333 f 0",
1415
+ "7x7x7": "c f 0.714285714285714 f 0.428571428571429 f 0.142857142857143",
1416
+ "8x8x8": "c f 0.75 f 0.5 f 0.25 f 0",
1417
+ "9x9x9": "c f 0.777777777777778 f 0.555555555555556 f 0.333333333333333 f 0.111111111111111",
1418
+ "10x10x10": "c f 0.8 f 0.6 f 0.4 f 0.2 f 0",
1419
+ "11x11x11": "c f 0.818181818181818 f 0.636363636363636 f 0.454545454545455 f 0.272727272727273 f 0.0909090909090909",
1420
+ "12x12x12": "c f 0.833333333333333 f 0.666666666666667 f 0.5 f 0.333333333333333 f 0.166666666666667 f 0",
1421
+ "13x13x13": "c f 0.846153846153846 f 0.692307692307692 f 0.538461538461538 f 0.384615384615385 f 0.230769230769231 f 0.0769230769230769",
1422
+ "20x20x20": "c f 0 f .1 f .2 f .3 f .4 f .5 f .6 f .7 f .8 f .9",
1423
+ "30x30x30": "c f 0 f .066667 f .133333 f .2 f .266667 f .333333 f .4 f .466667 f .533333 f .6 f .666667 f .733333 f .8 f .866667 f .933333",
1424
+ "40x40x40": "c f 0 f .05 f .1 f .15 f .2 f .25 f .3 f .35 f .4 f .45 f .5 f .55 f .6 f .65 f .7 f .75 f .8 f .85 f .9 f .95",
1425
+ "skewb": "c v 0",
1426
+ "master skewb": "c v 0.275",
1427
+ "professor skewb": "c v 0 v 0.38",
1428
+ "compy cube": "c v 0.915641442663986",
1429
+ "helicopter": "c e 0.707106781186547",
1430
+ "curvy copter": "c e 0.83",
1431
+ "dino": "c v 0.577350269189626",
1432
+ "little chop": "c e 0",
1433
+ "pyramorphix": "t e 0",
1434
+ "mastermorphix": "t e 0.346184634065199",
1435
+ "pyraminx": "t v 0.333333333333333 v 1.66666666666667",
1436
+ "tetraminx": "t v 0.333333333333333",
1437
+ "master pyraminx": "t v 0 v 1 v 2",
1438
+ "master tetraminx": "t v 0 v 1",
1439
+ "professor pyraminx": "t v -0.2 v 0.6 v 1.4 v 2.2",
1440
+ "professor tetraminx": "t v -0.2 v 0.6 v 1.4",
1441
+ "Jing pyraminx": "t f 0",
1442
+ "master pyramorphix": "t e 0.866025403784437",
1443
+ "megaminx": "d f 0.7",
1444
+ "gigaminx": "d f 0.64 f 0.82",
1445
+ "teraminx": "d f 0.64 f 0.76 f 0.88",
1446
+ "petaminx": "d f 0.64 f 0.73 f 0.82 f 0.91",
1447
+ "examinx": "d f 0.64 f 0.712 f 0.784 f 0.856 f 0.928",
1448
+ "zetaminx": "d f 0.64 f 0.7 f 0.76 f 0.82 f 0.88 f 0.94",
1449
+ "yottaminx": "d f 0.64 f 0.6914 f 0.7429 f 0.7943 f 0.8457 f 0.8971 f 0.9486",
1450
+ "pentultimate": "d f 0",
1451
+ "master pentultimate": "d f 0.1",
1452
+ "elite pentultimate": "d f 0 f 0.145905",
1453
+ "starminx": "d v 0.937962370425399",
1454
+ "starminx 2": "d f 0.23606797749979",
1455
+ "pyraminx crystal": "d f 0.447213595499989",
1456
+ "chopasaurus": "d v 0",
1457
+ "big chop": "d e 0",
1458
+ "skewb diamond": "o f 0",
1459
+ "FTO": "o f 0.333333333333333",
1460
+ "master FTO": "o f 0.5 f 0",
1461
+ "Christopher's jewel": "o v 0.577350269189626",
1462
+ "octastar": "o e 0",
1463
+ "Trajber's octahedron": "o v 0.433012701892219",
1464
+ "radio chop": "i f 0",
1465
+ "icosamate": "i v 0",
1466
+ "icosahedron 2": "i v 0.18759247376021",
1467
+ "icosahedron 3": "i v 0.18759247376021 e 0",
1468
+ "icosahedron static faces": "i v 0.84",
1469
+ "icosahedron moving faces": "i v 0.73",
1470
+ "Eitan's star": "i f 0.61803398874989",
1471
+ "2x2x2 + dino": "c f 0 v 0.577350269189626",
1472
+ "2x2x2 + little chop": "c f 0 e 0",
1473
+ "dino + little chop": "c v 0.577350269189626 e 0",
1474
+ "2x2x2 + dino + little chop": "c f 0 v 0.577350269189626 e 0",
1475
+ "megaminx + chopasaurus": "d f 0.61803398875 v 0",
1476
+ "starminx combo": "d f 0.23606797749979 v 0.937962370425399"
1477
+ };
1478
+
1479
+ // src/cubing/puzzle-geometry/Quat.ts
1480
+ var eps = 1e-9;
1481
+ function centermassface(face) {
1482
+ let s = new Quat(0, 0, 0, 0);
1483
+ for (let i = 0; i < face.length; i++) {
1484
+ s = s.sum(face[i]);
1485
+ }
1486
+ return s.smul(1 / face.length);
1487
+ }
1488
+ function solvethreeplanes(p1, p2, p3, planes) {
1489
+ const p = planes[p1].intersect3(planes[p2], planes[p3]);
1490
+ if (!p) {
1491
+ return p;
1492
+ }
1493
+ for (let i = 0; i < planes.length; i++) {
1494
+ if (i !== p1 && i !== p2 && i !== p3) {
1495
+ const dt = planes[i].b * p.b + planes[i].c * p.c + planes[i].d * p.d;
1496
+ if (planes[i].a > 0 && dt > planes[i].a || planes[i].a < 0 && dt < planes[i].a) {
1497
+ return false;
1498
+ }
1499
+ }
1500
+ }
1501
+ return p;
1502
+ }
1503
+ var Quat = class {
1504
+ constructor(a, b, c, d) {
1505
+ this.a = a;
1506
+ this.b = b;
1507
+ this.c = c;
1508
+ this.d = d;
1509
+ }
1510
+ mul(q) {
1511
+ return new Quat(
1512
+ this.a * q.a - this.b * q.b - this.c * q.c - this.d * q.d,
1513
+ this.a * q.b + this.b * q.a + this.c * q.d - this.d * q.c,
1514
+ this.a * q.c - this.b * q.d + this.c * q.a + this.d * q.b,
1515
+ this.a * q.d + this.b * q.c - this.c * q.b + this.d * q.a
1516
+ );
1517
+ }
1518
+ toString() {
1519
+ return `Q[${this.a},${this.b},${this.c},${this.d}]`;
1520
+ }
1521
+ dist(q) {
1522
+ return Math.hypot(this.a - q.a, this.b - q.b, this.c - q.c, this.d - q.d);
1523
+ }
1524
+ len() {
1525
+ return Math.hypot(this.a, this.b, this.c, this.d);
1526
+ }
1527
+ cross(q) {
1528
+ return new Quat(
1529
+ 0,
1530
+ this.c * q.d - this.d * q.c,
1531
+ this.d * q.b - this.b * q.d,
1532
+ this.b * q.c - this.c * q.b
1533
+ );
1534
+ }
1535
+ dot(q) {
1536
+ return this.b * q.b + this.c * q.c + this.d * q.d;
1537
+ }
1538
+ normalize() {
1539
+ const d = Math.sqrt(this.dot(this));
1540
+ return new Quat(this.a / d, this.b / d, this.c / d, this.d / d);
1541
+ }
1542
+ makenormal() {
1543
+ return new Quat(0, this.b, this.c, this.d).normalize();
1544
+ }
1545
+ normalizeplane() {
1546
+ const d = Math.hypot(this.b, this.c, this.d);
1547
+ return new Quat(this.a / d, this.b / d, this.c / d, this.d / d);
1548
+ }
1549
+ smul(m) {
1550
+ return new Quat(this.a * m, this.b * m, this.c * m, this.d * m);
1551
+ }
1552
+ sum(q) {
1553
+ return new Quat(this.a + q.a, this.b + q.b, this.c + q.c, this.d + q.d);
1554
+ }
1555
+ sub(q) {
1556
+ return new Quat(this.a - q.a, this.b - q.b, this.c - q.c, this.d - q.d);
1557
+ }
1558
+ angle() {
1559
+ return 2 * Math.acos(this.a);
1560
+ }
1561
+ invrot() {
1562
+ return new Quat(this.a, -this.b, -this.c, -this.d);
1563
+ }
1564
+ det3x3(a00, a01, a02, a10, a11, a12, a20, a21, a22) {
1565
+ return a00 * (a11 * a22 - a12 * a21) + a01 * (a12 * a20 - a10 * a22) + a02 * (a10 * a21 - a11 * a20);
1566
+ }
1567
+ rotateplane(q) {
1568
+ const t = q.mul(new Quat(0, this.b, this.c, this.d)).mul(q.invrot());
1569
+ t.a = this.a;
1570
+ return t;
1571
+ }
1572
+ orthogonal() {
1573
+ const ab = Math.abs(this.b);
1574
+ const ac = Math.abs(this.c);
1575
+ const ad = Math.abs(this.d);
1576
+ if (ab < ac && ab < ad) {
1577
+ return this.cross(new Quat(0, 1, 0, 0)).normalize();
1578
+ } else if (ac < ab && ac < ad) {
1579
+ return this.cross(new Quat(0, 0, 1, 0)).normalize();
1580
+ } else {
1581
+ return this.cross(new Quat(0, 0, 0, 1)).normalize();
1582
+ }
1583
+ }
1584
+ pointrotation(b) {
1585
+ const a = this.normalize();
1586
+ b = b.normalize();
1587
+ if (a.sub(b).len() < eps) {
1588
+ return new Quat(1, 0, 0, 0);
1589
+ }
1590
+ let h = a.sum(b);
1591
+ if (h.len() < eps) {
1592
+ h = h.orthogonal();
1593
+ } else {
1594
+ h = h.normalize();
1595
+ }
1596
+ const r = a.cross(h);
1597
+ r.a = a.dot(h);
1598
+ return r;
1599
+ }
1600
+ unproject(b) {
1601
+ return this.sum(b.smul(-this.dot(b) / (this.len() * b.len())));
1602
+ }
1603
+ rotatepoint(q) {
1604
+ return q.mul(this).mul(q.invrot());
1605
+ }
1606
+ rotateface(face) {
1607
+ return face.map((_) => _.rotatepoint(this));
1608
+ }
1609
+ intersect3(p2, p3) {
1610
+ const det = this.det3x3(
1611
+ this.b,
1612
+ this.c,
1613
+ this.d,
1614
+ p2.b,
1615
+ p2.c,
1616
+ p2.d,
1617
+ p3.b,
1618
+ p3.c,
1619
+ p3.d
1620
+ );
1621
+ if (Math.abs(det) < eps) {
1622
+ return false;
1623
+ }
1624
+ return new Quat(
1625
+ 0,
1626
+ this.det3x3(this.a, this.c, this.d, p2.a, p2.c, p2.d, p3.a, p3.c, p3.d) / det,
1627
+ this.det3x3(this.b, this.a, this.d, p2.b, p2.a, p2.d, p3.b, p3.a, p3.d) / det,
1628
+ this.det3x3(this.b, this.c, this.a, p2.b, p2.c, p2.a, p3.b, p3.c, p3.a) / det
1629
+ );
1630
+ }
1631
+ side(x) {
1632
+ if (x > eps) {
1633
+ return 1;
1634
+ }
1635
+ if (x < -eps) {
1636
+ return -1;
1637
+ }
1638
+ return 0;
1639
+ }
1640
+ cutface(face) {
1641
+ const d = this.a;
1642
+ let seen = 0;
1643
+ let r = null;
1644
+ for (let i = 0; i < face.length; i++) {
1645
+ seen |= 1 << this.side(face[i].dot(this) - d) + 1;
1646
+ }
1647
+ if ((seen & 5) === 5) {
1648
+ r = [];
1649
+ const inout = face.map((_) => this.side(_.dot(this) - d));
1650
+ for (let s = -1; s <= 1; s += 2) {
1651
+ const nface = [];
1652
+ for (let k = 0; k < face.length; k++) {
1653
+ if (inout[k] === s || inout[k] === 0) {
1654
+ nface.push(face[k]);
1655
+ }
1656
+ const kk = (k + 1) % face.length;
1657
+ if (inout[k] + inout[kk] === 0 && inout[k] !== 0) {
1658
+ const vk = face[k].dot(this) - d;
1659
+ const vkk = face[kk].dot(this) - d;
1660
+ const r2 = vk / (vk - vkk);
1661
+ const pt = face[k].smul(1 - r2).sum(face[kk].smul(r2));
1662
+ nface.push(pt);
1663
+ }
1664
+ }
1665
+ r.push(nface);
1666
+ }
1667
+ }
1668
+ return r;
1669
+ }
1670
+ cutfaces(faces) {
1671
+ const nfaces = [];
1672
+ for (let j = 0; j < faces.length; j++) {
1673
+ const face = faces[j];
1674
+ const t = this.cutface(face);
1675
+ if (t) {
1676
+ nfaces.push(t[0]);
1677
+ nfaces.push(t[1]);
1678
+ } else {
1679
+ nfaces.push(face);
1680
+ }
1681
+ }
1682
+ return nfaces;
1683
+ }
1684
+ faceside(face) {
1685
+ const d = this.a;
1686
+ for (let i = 0; i < face.length; i++) {
1687
+ const s = this.side(face[i].dot(this) - d);
1688
+ if (s !== 0) {
1689
+ return s;
1690
+ }
1691
+ }
1692
+ throw new Error("Could not determine side of plane in faceside");
1693
+ }
1694
+ sameplane(p) {
1695
+ const a = this.normalize();
1696
+ const b = p.normalize();
1697
+ return a.dist(b) < eps || a.dist(b.smul(-1)) < eps;
1698
+ }
1699
+ makecut(r) {
1700
+ return new Quat(r, this.b, this.c, this.d);
1701
+ }
1702
+ };
1703
+
1704
+ // src/cubing/puzzle-geometry/PlatonicGenerator.ts
1705
+ var eps2 = 1e-9;
1706
+ function cube() {
1707
+ const s5 = Math.sqrt(0.5);
1708
+ return [new Quat(s5, s5, 0, 0), new Quat(s5, 0, s5, 0)];
1709
+ }
1710
+ function tetrahedron() {
1711
+ return [new Quat(0.5, 0.5, 0.5, 0.5), new Quat(0.5, 0.5, 0.5, -0.5)];
1712
+ }
1713
+ function dodecahedron() {
1714
+ const d36 = 2 * Math.PI / 10;
1715
+ let dx = 0.5 + 0.3 * Math.sqrt(5);
1716
+ let dy = 0.5 + 0.1 * Math.sqrt(5);
1717
+ const dd = Math.sqrt(dx * dx + dy * dy);
1718
+ dx /= dd;
1719
+ dy /= dd;
1720
+ return [
1721
+ new Quat(Math.cos(d36), dx * Math.sin(d36), dy * Math.sin(d36), 0),
1722
+ new Quat(0.5, 0.5, 0.5, 0.5)
1723
+ ];
1724
+ }
1725
+ function icosahedron() {
1726
+ let dx = 1 / 6 + Math.sqrt(5) / 6;
1727
+ let dy = 2 / 3 + Math.sqrt(5) / 3;
1728
+ const dd = Math.sqrt(dx * dx + dy * dy);
1729
+ dx /= dd;
1730
+ dy /= dd;
1731
+ const ang = 2 * Math.PI / 6;
1732
+ return [
1733
+ new Quat(Math.cos(ang), dx * Math.sin(ang), dy * Math.sin(ang), 0),
1734
+ new Quat(Math.cos(ang), -dx * Math.sin(ang), dy * Math.sin(ang), 0)
1735
+ ];
1736
+ }
1737
+ function octahedron() {
1738
+ const s5 = Math.sqrt(0.5);
1739
+ return [new Quat(0.5, 0.5, 0.5, 0.5), new Quat(s5, 0, 0, s5)];
1740
+ }
1741
+ function closure(g) {
1742
+ const q = [new Quat(1, 0, 0, 0)];
1743
+ for (let i = 0; i < q.length; i++) {
1744
+ for (let j = 0; j < g.length; j++) {
1745
+ const ns = g[j].mul(q[i]);
1746
+ const negns = ns.smul(-1);
1747
+ let wasseen = false;
1748
+ for (let k = 0; k < q.length; k++) {
1749
+ if (ns.dist(q[k]) < eps2 || negns.dist(q[k]) < eps2) {
1750
+ wasseen = true;
1751
+ break;
1752
+ }
1753
+ }
1754
+ if (!wasseen) {
1755
+ q.push(ns);
1756
+ }
1757
+ }
1758
+ }
1759
+ return q;
1760
+ }
1761
+ function uniqueplanes(p, g) {
1762
+ const planes = [];
1763
+ const planerot = [];
1764
+ for (let i = 0; i < g.length; i++) {
1765
+ const p2 = p.rotateplane(g[i]);
1766
+ let wasseen = false;
1767
+ for (let j = 0; j < planes.length; j++) {
1768
+ if (p2.dist(planes[j]) < eps2) {
1769
+ wasseen = true;
1770
+ break;
1771
+ }
1772
+ }
1773
+ if (!wasseen) {
1774
+ planes.push(p2);
1775
+ planerot.push(g[i]);
1776
+ }
1777
+ }
1778
+ return planerot;
1779
+ }
1780
+ function getface(planes) {
1781
+ const face = [];
1782
+ for (let i = 1; i < planes.length; i++) {
1783
+ for (let j = i + 1; j < planes.length; j++) {
1784
+ const p = solvethreeplanes(0, i, j, planes);
1785
+ if (p) {
1786
+ let wasseen = false;
1787
+ for (let k = 0; k < face.length; k++) {
1788
+ if (p.dist(face[k]) < eps2) {
1789
+ wasseen = true;
1790
+ break;
1791
+ }
1792
+ }
1793
+ if (!wasseen) {
1794
+ face.push(p);
1795
+ }
1796
+ }
1797
+ }
1798
+ }
1799
+ for (; ; ) {
1800
+ let changed = false;
1801
+ for (let i = 0; i < face.length; i++) {
1802
+ const j = (i + 1) % face.length;
1803
+ if (planes[0].dot(face[i].cross(face[j])) < 0) {
1804
+ const t = face[i];
1805
+ face[i] = face[j];
1806
+ face[j] = t;
1807
+ changed = true;
1808
+ }
1809
+ }
1810
+ if (!changed) {
1811
+ break;
1812
+ }
1813
+ }
1814
+ return face;
1815
+ }
1816
+
1817
+ // src/cubing/puzzle-geometry/SchreierSims.ts
1818
+ var FactoredNumber = class {
1819
+ constructor() {
1820
+ this.mult = [];
1821
+ }
1822
+ multiply(n) {
1823
+ for (let f = 2; f * f <= n; f++) {
1824
+ while (n % f === 0) {
1825
+ if (void 0 !== this.mult[f]) {
1826
+ this.mult[f]++;
1827
+ } else {
1828
+ this.mult[f] = 1;
1829
+ }
1830
+ n /= f;
1831
+ }
1832
+ }
1833
+ if (n > 1) {
1834
+ if (void 0 !== this.mult[n]) {
1835
+ this.mult[n]++;
1836
+ } else {
1837
+ this.mult[n] = 1;
1838
+ }
1839
+ }
1840
+ }
1841
+ toString() {
1842
+ let r = "";
1843
+ for (let i = 0; i < this.mult.length; i++) {
1844
+ if (void 0 !== this.mult[i]) {
1845
+ if (r !== "") {
1846
+ r += "*";
1847
+ }
1848
+ r += i;
1849
+ if (this.mult[i] > 1) {
1850
+ r += `^${this.mult[i]}`;
1851
+ }
1852
+ }
1853
+ }
1854
+ return r;
1855
+ }
1856
+ };
1857
+ function schreierSims(g, disp) {
1858
+ const n = g[0].p.length;
1859
+ const e = identity(n);
1860
+ let sgs = [];
1861
+ let sgsi = [];
1862
+ let sgslen = [];
1863
+ let Tk = [];
1864
+ let Tklen = [];
1865
+ function resolve(p) {
1866
+ for (let i = p.p.length - 1; i >= 0; i--) {
1867
+ const j = p.p[i];
1868
+ if (j !== i) {
1869
+ if (!sgs[i][j]) {
1870
+ return false;
1871
+ }
1872
+ p = p.mul(sgsi[i][j]);
1873
+ }
1874
+ }
1875
+ return true;
1876
+ }
1877
+ function knutha(k, p, len) {
1878
+ Tk[k].push(p);
1879
+ Tklen[k].push(len);
1880
+ for (let i = 0; i < sgs[k].length; i++) {
1881
+ if (sgs[k][i]) {
1882
+ knuthb(k, sgs[k][i].mul(p), len + sgslen[k][i]);
1883
+ }
1884
+ }
1885
+ }
1886
+ function knuthb(k, p, len) {
1887
+ const j = p.p[k];
1888
+ if (!sgs[k][j]) {
1889
+ sgs[k][j] = p;
1890
+ sgsi[k][j] = p.inv();
1891
+ sgslen[k][j] = len;
1892
+ for (let i = 0; i < Tk[k].length; i++) {
1893
+ knuthb(k, p.mul(Tk[k][i]), len + Tklen[k][i]);
1894
+ }
1895
+ return;
1896
+ }
1897
+ const p2 = p.mul(sgsi[k][j]);
1898
+ if (!resolve(p2)) {
1899
+ knutha(k - 1, p2, len + sgslen[k][j]);
1900
+ }
1901
+ }
1902
+ function getsgs() {
1903
+ sgs = [];
1904
+ sgsi = [];
1905
+ Tk = [];
1906
+ sgslen = [];
1907
+ Tklen = [];
1908
+ for (let i = 0; i < n; i++) {
1909
+ sgs.push([]);
1910
+ sgsi.push([]);
1911
+ sgslen.push([]);
1912
+ Tk.push([]);
1913
+ Tklen.push([]);
1914
+ sgs[i][i] = e;
1915
+ sgsi[i][i] = e;
1916
+ sgslen[i][i] = 0;
1917
+ }
1918
+ let none = 0;
1919
+ let sz = 1n;
1920
+ for (let i = 0; i < g.length; i++) {
1921
+ knutha(n - 1, g[i], 1);
1922
+ sz = 1n;
1923
+ let tks = 0;
1924
+ let sollen = 0;
1925
+ const avgs = [];
1926
+ const mults = new FactoredNumber();
1927
+ for (let j = 0; j < n; j++) {
1928
+ let cnt = 0;
1929
+ let lensum = 0;
1930
+ for (let k = 0; k < n; k++) {
1931
+ if (sgs[j][k]) {
1932
+ cnt++;
1933
+ lensum += sgslen[j][k];
1934
+ if (j !== k) {
1935
+ none++;
1936
+ }
1937
+ }
1938
+ }
1939
+ tks += Tk[j].length;
1940
+ sz *= BigInt(cnt);
1941
+ if (cnt > 1) {
1942
+ mults.multiply(cnt);
1943
+ }
1944
+ const avg = lensum / cnt;
1945
+ avgs.push(avg);
1946
+ sollen += avg;
1947
+ }
1948
+ disp(
1949
+ `${i}: sz ${sz} T ${tks} sol ${sollen} none ${none} mults ${mults.toString()}`
1950
+ );
1951
+ }
1952
+ return sz;
1953
+ }
1954
+ return getsgs();
1955
+ }
1956
+
1957
+ // src/cubing/puzzle-geometry/PuzzleGeometry.ts
1958
+ function tstart(s) {
1959
+ return s;
1960
+ }
1961
+ function tend(_) {
1962
+ }
1963
+ var Face = class {
1964
+ constructor(q) {
1965
+ this.coords = new Array(q.length * 3);
1966
+ for (let i = 0; i < q.length; i++) {
1967
+ this.coords[3 * i] = q[i].b;
1968
+ this.coords[3 * i + 1] = q[i].c;
1969
+ this.coords[3 * i + 2] = q[i].d;
1970
+ }
1971
+ this.length = q.length;
1972
+ }
1973
+ get(off) {
1974
+ return new Quat(
1975
+ 0,
1976
+ this.coords[3 * off],
1977
+ this.coords[3 * off + 1],
1978
+ this.coords[3 * off + 2]
1979
+ );
1980
+ }
1981
+ centermass() {
1982
+ let sx = 0;
1983
+ let sy = 0;
1984
+ let sz = 0;
1985
+ for (let i = 0; i < this.length; i++) {
1986
+ sx += this.coords[3 * i];
1987
+ sy += this.coords[3 * i + 1];
1988
+ sz += this.coords[3 * i + 2];
1989
+ }
1990
+ return new Quat(0, sx / this.length, sy / this.length, sz / this.length);
1991
+ }
1992
+ rotate(q) {
1993
+ const a = [];
1994
+ for (let i = 0; i < this.length; i++) {
1995
+ a.push(this.get(i).rotatepoint(q));
1996
+ }
1997
+ return new Face(a);
1998
+ }
1999
+ rotateforward() {
2000
+ const a = [];
2001
+ for (let i = 1; i < this.length; i++) {
2002
+ a.push(this.get(i));
2003
+ }
2004
+ a.push(this.get(0));
2005
+ return new Face(a);
2006
+ }
2007
+ };
2008
+ var FaceTree = class {
2009
+ constructor(face, left, right) {
2010
+ this.face = face;
2011
+ this.left = left;
2012
+ this.right = right;
2013
+ }
2014
+ split(q) {
2015
+ const t = q.cutface(this.face);
2016
+ if (t !== null) {
2017
+ if (this.left === void 0) {
2018
+ this.left = new FaceTree(t[0]);
2019
+ this.right = new FaceTree(t[1]);
2020
+ } else {
2021
+ this.left = this.left?.split(q);
2022
+ this.right = this.right?.split(q);
2023
+ }
2024
+ }
2025
+ return this;
2026
+ }
2027
+ collect(arr, leftfirst) {
2028
+ if (this.left === void 0) {
2029
+ arr.push(new Face(this.face));
2030
+ } else if (leftfirst) {
2031
+ this.left?.collect(arr, false);
2032
+ this.right?.collect(arr, true);
2033
+ } else {
2034
+ this.right?.collect(arr, false);
2035
+ this.left?.collect(arr, true);
2036
+ }
2037
+ return arr;
2038
+ }
2039
+ };
2040
+ function expandfaces(rots, faces) {
2041
+ const nfaces = [];
2042
+ for (const rot of rots) {
2043
+ for (const face of faces) {
2044
+ nfaces.push(face.rotate(rot));
2045
+ }
2046
+ }
2047
+ return nfaces;
2048
+ }
2049
+ var eps3 = 1e-9;
2050
+ var copyright = "PuzzleGeometry 0.1 Copyright 2018 Tomas Rokicki.";
2051
+ var permissivieMoveParsing = false;
2052
+ function defaultnets() {
2053
+ return {
2054
+ 4: [["F", "D", "L", "R"]],
2055
+ 6: [
2056
+ ["F", "D", "L", "U", "R"],
2057
+ ["R", "F", "", "B", ""]
2058
+ ],
2059
+ 8: [
2060
+ ["F", "D", "L", "R"],
2061
+ ["D", "F", "BR", ""],
2062
+ ["BR", "D", "", "BB"],
2063
+ ["BB", "BR", "U", "BL"]
2064
+ ],
2065
+ 12: [
2066
+ ["U", "F", "", "", "", ""],
2067
+ ["F", "U", "R", "C", "A", "L"],
2068
+ ["R", "F", "", "", "E", ""],
2069
+ ["E", "R", "", "BF", "", ""],
2070
+ ["BF", "E", "BR", "BL", "I", "D"]
2071
+ ],
2072
+ 20: [
2073
+ ["R", "C", "F", "E"],
2074
+ ["F", "R", "L", "U"],
2075
+ ["L", "F", "A", ""],
2076
+ ["E", "R", "G", "I"],
2077
+ ["I", "E", "S", "H"],
2078
+ ["S", "I", "J", "B"],
2079
+ ["B", "S", "K", "D"],
2080
+ ["K", "B", "M", "O"],
2081
+ ["O", "K", "P", "N"],
2082
+ ["P", "O", "Q", ""]
2083
+ ]
2084
+ };
2085
+ }
2086
+ function defaultcolors() {
2087
+ return {
2088
+ 4: { F: "#00ff00", D: "#ffff00", L: "#ff0000", R: "#0000ff" },
2089
+ 6: {
2090
+ U: "#ffffff",
2091
+ F: "#00ff00",
2092
+ R: "#ff0000",
2093
+ D: "#ffff00",
2094
+ B: "#0000ff",
2095
+ L: "#ff8000"
2096
+ },
2097
+ 8: {
2098
+ U: "#ffffff",
2099
+ F: "#ff0000",
2100
+ R: "#00bb00",
2101
+ D: "#ffff00",
2102
+ BB: "#1122ff",
2103
+ L: "#9524c5",
2104
+ BL: "#ff8800",
2105
+ BR: "#aaaaaa"
2106
+ },
2107
+ 12: {
2108
+ U: "#ffffff",
2109
+ F: "#006633",
2110
+ R: "#ff0000",
2111
+ C: "#ffffd0",
2112
+ A: "#3399ff",
2113
+ L: "#660099",
2114
+ E: "#ff66cc",
2115
+ BF: "#99ff00",
2116
+ BR: "#0000ff",
2117
+ BL: "#ffff00",
2118
+ I: "#ff6633",
2119
+ D: "#999999"
2120
+ },
2121
+ 20: {
2122
+ R: "#db69f0",
2123
+ C: "#178fde",
2124
+ F: "#23238b",
2125
+ E: "#9cc726",
2126
+ L: "#2c212d",
2127
+ U: "#177fa7",
2128
+ A: "#e0de7f",
2129
+ G: "#2b57c0",
2130
+ I: "#41126b",
2131
+ S: "#4b8c28",
2132
+ H: "#7c098d",
2133
+ J: "#7fe7b4",
2134
+ B: "#85fb74",
2135
+ K: "#3f4bc3",
2136
+ D: "#0ff555",
2137
+ M: "#f1c2c8",
2138
+ O: "#58d340",
2139
+ P: "#c514f2",
2140
+ N: "#14494e",
2141
+ Q: "#8b1be1"
2142
+ }
2143
+ };
2144
+ }
2145
+ var orientationDefaults = {
2146
+ 4: {
2147
+ v: ["DFR", "DLF", "DRL", "FLR"],
2148
+ e: ["FR", "LF", "DF", "DL", "RD", "RL"],
2149
+ c: ["DF", "FD", "RL", "LR"]
2150
+ },
2151
+ 6: {
2152
+ v: ["URF", "UBR", "ULB", "UFL", "DFR", "DRB", "DBL", "DLF"],
2153
+ e: ["UF", "UR", "UB", "UL", "DF", "DR", "DB", "DL", "FR", "FL", "BR", "BL"],
2154
+ c: ["UB", "LU", "FU", "RU", "BU", "DF"]
2155
+ },
2156
+ 8: {
2157
+ v: ["UBBBRR", "URFL", "ULBLBB", "DBRBBBL", "DBLLF", "DFRBR"],
2158
+ e: [
2159
+ "UL",
2160
+ "UBB",
2161
+ "UR",
2162
+ "BRD",
2163
+ "BLD",
2164
+ "FD",
2165
+ "BRR",
2166
+ "FR",
2167
+ "FL",
2168
+ "BLL",
2169
+ "BLBB",
2170
+ "BRBB"
2171
+ ],
2172
+ c: ["BBU", "LU", "RU", "BRD", "FD", "BLD", "DF", "UBB"]
2173
+ },
2174
+ 12: {
2175
+ v: [
2176
+ "URF",
2177
+ "UFL",
2178
+ "ULBL",
2179
+ "UBLBR",
2180
+ "UBRR",
2181
+ "DEBF",
2182
+ "DBFI",
2183
+ "DIA",
2184
+ "DAC",
2185
+ "DCE",
2186
+ "LAI",
2187
+ "ALF",
2188
+ "FCA",
2189
+ "CFR",
2190
+ "REC",
2191
+ "ERBR",
2192
+ "BRBFE",
2193
+ "BFBRBL",
2194
+ "BLIBF",
2195
+ "IBLL"
2196
+ ],
2197
+ e: [
2198
+ "UF",
2199
+ "UR",
2200
+ "UBR",
2201
+ "UBL",
2202
+ "UL",
2203
+ "ER",
2204
+ "EBR",
2205
+ "EBF",
2206
+ "ED",
2207
+ "EC",
2208
+ "IBF",
2209
+ "IBL",
2210
+ "IL",
2211
+ "IA",
2212
+ "ID",
2213
+ "AC",
2214
+ "CF",
2215
+ "FA",
2216
+ "BFBR",
2217
+ "BRBL",
2218
+ "BLBF",
2219
+ "CD",
2220
+ "AD",
2221
+ "AL",
2222
+ "FL",
2223
+ "FR",
2224
+ "CR",
2225
+ "BFD",
2226
+ "BRR",
2227
+ "BLL"
2228
+ ],
2229
+ c: [
2230
+ "UF",
2231
+ "FU",
2232
+ "DBF",
2233
+ "BFD",
2234
+ "AD",
2235
+ "CD",
2236
+ "BRU",
2237
+ "BLU",
2238
+ "LA",
2239
+ "RA",
2240
+ "EBR",
2241
+ "IBL"
2242
+ ]
2243
+ },
2244
+ 20: {
2245
+ v: [
2246
+ "FLPQU",
2247
+ "FUGER",
2248
+ "FRCAL",
2249
+ "HCREI",
2250
+ "ISBDH",
2251
+ "JSIEG",
2252
+ "BSJMK",
2253
+ "MQPOK",
2254
+ "ONDBK",
2255
+ "NOPLA",
2256
+ "UQMJG",
2257
+ "DNACH"
2258
+ ],
2259
+ e: [
2260
+ "FU",
2261
+ "FL",
2262
+ "FR",
2263
+ "EG",
2264
+ "ER",
2265
+ "EI",
2266
+ "SJ",
2267
+ "SI",
2268
+ "SB",
2269
+ "KM",
2270
+ "KB",
2271
+ "KO",
2272
+ "PQ",
2273
+ "PO",
2274
+ "PL",
2275
+ "UG",
2276
+ "JG",
2277
+ "MQ",
2278
+ "UQ",
2279
+ "HC",
2280
+ "HD",
2281
+ "ND",
2282
+ "NA",
2283
+ "JM",
2284
+ "CA",
2285
+ "AL",
2286
+ "CR",
2287
+ "HI",
2288
+ "DB",
2289
+ "NO"
2290
+ ],
2291
+ c: [
2292
+ "FU",
2293
+ "UF",
2294
+ "GE",
2295
+ "EG",
2296
+ "JS",
2297
+ "SJ",
2298
+ "MK",
2299
+ "KM",
2300
+ "QP",
2301
+ "PQ",
2302
+ "LA",
2303
+ "AL",
2304
+ "RC",
2305
+ "CR",
2306
+ "IH",
2307
+ "HI",
2308
+ "BD",
2309
+ "DB",
2310
+ "ON",
2311
+ "NO"
2312
+ ]
2313
+ }
2314
+ };
2315
+ function defaultOrientations() {
2316
+ return {
2317
+ 4: [
2318
+ ["FLR", [0, 1, 0]],
2319
+ ["F", [0, 0, 1]]
2320
+ ],
2321
+ 6: [
2322
+ ["U", [0, 1, 0]],
2323
+ ["F", [0, 0, 1]]
2324
+ ],
2325
+ 8: [
2326
+ ["U", [0, 1, 0]],
2327
+ ["F", [0, 0, 1]]
2328
+ ],
2329
+ 12: [
2330
+ ["U", [0, 1, 0]],
2331
+ ["F", [0, 0, 1]]
2332
+ ],
2333
+ 20: [
2334
+ ["GUQMJ", [0, 1, 0]],
2335
+ ["F", [0, 0, 1]]
2336
+ ]
2337
+ };
2338
+ }
2339
+ function findelement(a, p) {
2340
+ for (let i = 0; i < a.length; i++) {
2341
+ if (a[i][0].dist(p) < eps3) {
2342
+ return i;
2343
+ }
2344
+ }
2345
+ throw new Error("Element not found");
2346
+ }
2347
+ function getPG3DNamedPuzzles() {
2348
+ return PGPuzzles;
2349
+ }
2350
+ function getPuzzleDescriptionString(puzzleName) {
2351
+ return PGPuzzles[puzzleName];
2352
+ }
2353
+ var PUZZLE_BASE_SHAPES = ["c", "t", "o", "d", "i"];
2354
+ var PUZZLE_CUT_TYPES = ["f", "v", "e"];
2355
+ function parsePuzzleDescription(s) {
2356
+ const a = s.split(/ /).filter(Boolean);
2357
+ if (a.length % 2 === 0) {
2358
+ return null;
2359
+ }
2360
+ const shape = a[0];
2361
+ if (shape !== "o" && shape !== "c" && shape !== "i" && shape !== "d" && shape !== "t") {
2362
+ return null;
2363
+ }
2364
+ const cuts = [];
2365
+ for (let i = 1; i < a.length; i += 2) {
2366
+ if (a[i] !== "f" && a[i] !== "v" && a[i] !== "e") {
2367
+ return null;
2368
+ }
2369
+ cuts.push({
2370
+ cutType: a[i],
2371
+ distance: parseFloat(a[i + 1])
2372
+ });
2373
+ }
2374
+ return { shape, cuts };
2375
+ }
2376
+ function getPuzzleGeometryByDesc(desc, options = {}) {
2377
+ const parsed = parsePuzzleDescription(desc);
2378
+ if (parsed === null) {
2379
+ throw new Error("Could not parse the puzzle description");
2380
+ }
2381
+ const pg = new PuzzleGeometry(
2382
+ parsed,
2383
+ Object.assign({}, { allMoves: true }, options)
2384
+ );
2385
+ pg.allstickers();
2386
+ pg.genperms();
2387
+ return pg;
2388
+ }
2389
+ function getPuzzleGeometryByName(puzzleName, options) {
2390
+ return getPuzzleGeometryByDesc(PGPuzzles[puzzleName], options);
2391
+ }
2392
+ function getmovename(geo, bits, slices) {
2393
+ let inverted = false;
2394
+ if (slices - bits[1] < bits[0]) {
2395
+ geo = [geo[2], geo[3], geo[0], geo[1]];
2396
+ bits = [slices - bits[1], slices - bits[0]];
2397
+ inverted = true;
2398
+ }
2399
+ let movenameFamily = geo[0];
2400
+ let movenamePrefix = "";
2401
+ if (bits[0] === 0 && bits[1] === slices) {
2402
+ movenameFamily = movenameFamily + "v";
2403
+ } else if (bits[0] === bits[1]) {
2404
+ if (bits[1] > 0) {
2405
+ movenamePrefix = String(bits[1] + 1);
2406
+ }
2407
+ } else if (bits[0] === 0) {
2408
+ movenameFamily = movenameFamily.toLowerCase();
2409
+ if (bits[1] > 1) {
2410
+ movenamePrefix = String(bits[1] + 1);
2411
+ }
2412
+ } else {
2413
+ throw new Error(
2414
+ `We only support slice and outer block moves right now. ${bits}`
2415
+ );
2416
+ }
2417
+ return [movenamePrefix + movenameFamily, inverted];
2418
+ }
2419
+ function splitByFaceNames(s, facenames) {
2420
+ const r = [];
2421
+ let at = 0;
2422
+ while (at < s.length) {
2423
+ if (at > 0 && at < s.length && s[at] === "_") {
2424
+ at++;
2425
+ }
2426
+ let currentMatch = "";
2427
+ for (const facename of facenames) {
2428
+ if (s.substr(at).startsWith(facename[1]) && facename[1].length > currentMatch.length) {
2429
+ currentMatch = facename[1];
2430
+ }
2431
+ }
2432
+ if (currentMatch !== "") {
2433
+ r.push(currentMatch);
2434
+ at += currentMatch.length;
2435
+ } else {
2436
+ throw new Error("Could not split " + s + " into face names.");
2437
+ }
2438
+ }
2439
+ return r;
2440
+ }
2441
+ function toCoords(q, maxdist) {
2442
+ return [q.b / maxdist, -q.c / maxdist, q.d / maxdist];
2443
+ }
2444
+ function toFaceCoords(q, maxdist) {
2445
+ const r = [];
2446
+ const n = q.length;
2447
+ for (let i = 0; i < n; i++) {
2448
+ const pt = toCoords(q.get(n - i - 1), maxdist);
2449
+ r[3 * i] = pt[0];
2450
+ r[3 * i + 1] = pt[1];
2451
+ r[3 * i + 2] = pt[2];
2452
+ }
2453
+ return r;
2454
+ }
2455
+ var PuzzleGeometry = class {
2456
+ constructor(puzzleDescription, options) {
2457
+ this.puzzleDescription = puzzleDescription;
2458
+ this.cmovesbyslice = [];
2459
+ this.duplicatedFaces = [];
2460
+ this.duplicatedCubies = [];
2461
+ this.fixedCubie = -1;
2462
+ this.net = [];
2463
+ this.colors = [];
2464
+ this.notationMapper = new NullMapper();
2465
+ this.addNotationMapper = "";
2466
+ this.setReidOrder = false;
2467
+ const t1 = tstart("genperms");
2468
+ this.options = new PuzzleGeometryFullOptions(options);
2469
+ if (this.options.verbosity > 0) {
2470
+ console.log(this.header("# "));
2471
+ }
2472
+ this.create(puzzleDescription);
2473
+ tend(t1);
2474
+ }
2475
+ create(puzzleDescription) {
2476
+ const { shape, cuts } = puzzleDescription;
2477
+ this.moveplanes = [];
2478
+ this.moveplanes2 = [];
2479
+ this.faces = [];
2480
+ this.cubies = [];
2481
+ let g = null;
2482
+ switch (shape) {
2483
+ case "c":
2484
+ g = cube();
2485
+ break;
2486
+ case "o":
2487
+ g = octahedron();
2488
+ break;
2489
+ case "i":
2490
+ g = icosahedron();
2491
+ break;
2492
+ case "t":
2493
+ g = tetrahedron();
2494
+ break;
2495
+ case "d":
2496
+ g = dodecahedron();
2497
+ break;
2498
+ default:
2499
+ throw new Error("Bad shape argument: " + shape);
2500
+ }
2501
+ this.rotations = closure(g);
2502
+ if (this.options.verbosity) {
2503
+ console.log("# Rotations: " + this.rotations.length);
2504
+ }
2505
+ const baseplane = g[0];
2506
+ this.baseplanerot = uniqueplanes(baseplane, this.rotations);
2507
+ const baseplanes = this.baseplanerot.map((_) => baseplane.rotateplane(_));
2508
+ this.baseplanes = baseplanes;
2509
+ this.baseFaceCount = baseplanes.length;
2510
+ const net = defaultnets()[baseplanes.length];
2511
+ this.net = net;
2512
+ this.colors = defaultcolors()[baseplanes.length];
2513
+ if (this.options.verbosity > 0) {
2514
+ console.log("# Base planes: " + baseplanes.length);
2515
+ }
2516
+ const baseface = getface(baseplanes);
2517
+ const zero = new Quat(0, 0, 0, 0);
2518
+ if (this.options.verbosity > 0) {
2519
+ console.log("# Face vertices: " + baseface.length);
2520
+ }
2521
+ const facenormal = baseplanes[0].makenormal();
2522
+ const edgenormal = baseface[0].sum(baseface[1]).makenormal();
2523
+ const vertexnormal = baseface[0].makenormal();
2524
+ const boundary = new Quat(1, facenormal.b, facenormal.c, facenormal.d);
2525
+ if (this.options.verbosity > 0) {
2526
+ console.log("# Boundary is " + boundary);
2527
+ }
2528
+ const planerot = uniqueplanes(boundary, this.rotations);
2529
+ const planes = planerot.map((_) => boundary.rotateplane(_));
2530
+ const firstface = getface(planes);
2531
+ this.edgedistance = firstface[0].sum(firstface[1]).smul(0.5).dist(zero);
2532
+ this.vertexdistance = firstface[0].dist(zero);
2533
+ const cutplanes = [];
2534
+ const intersects = [];
2535
+ let sawface = false;
2536
+ let sawedge = false;
2537
+ let sawvertex = false;
2538
+ for (const cut of cuts) {
2539
+ let normal = null;
2540
+ let distance = 0;
2541
+ switch (cut.cutType) {
2542
+ case "f":
2543
+ normal = facenormal;
2544
+ distance = 1;
2545
+ sawface = true;
2546
+ break;
2547
+ case "v":
2548
+ normal = vertexnormal;
2549
+ distance = this.vertexdistance;
2550
+ sawvertex = true;
2551
+ break;
2552
+ case "e":
2553
+ normal = edgenormal;
2554
+ distance = this.edgedistance;
2555
+ sawedge = true;
2556
+ break;
2557
+ default:
2558
+ throw new Error("Bad cut argument: " + cut.cutType);
2559
+ }
2560
+ cutplanes.push(normal.makecut(cut.distance));
2561
+ intersects.push(cut.distance < distance);
2562
+ }
2563
+ if (this.options.addRotations) {
2564
+ if (!sawface) {
2565
+ cutplanes.push(facenormal.makecut(10));
2566
+ }
2567
+ if (!sawvertex) {
2568
+ cutplanes.push(vertexnormal.makecut(10));
2569
+ }
2570
+ if (!sawedge) {
2571
+ cutplanes.push(edgenormal.makecut(10));
2572
+ }
2573
+ }
2574
+ this.basefaces = [];
2575
+ for (const baseplanerot of this.baseplanerot) {
2576
+ const face = baseplanerot.rotateface(firstface);
2577
+ this.basefaces.push(new Face(face));
2578
+ }
2579
+ const facenames = [];
2580
+ const faceplanes = [];
2581
+ const vertexnames = [];
2582
+ const edgenames = [];
2583
+ const edgesperface = firstface.length;
2584
+ function searchaddelement(a, p, name) {
2585
+ for (const el of a) {
2586
+ if (el[0].dist(p) < eps3) {
2587
+ el.push(name);
2588
+ return;
2589
+ }
2590
+ }
2591
+ a.push([p, name]);
2592
+ }
2593
+ for (let i = 0; i < this.baseplanerot.length; i++) {
2594
+ const face = this.baseplanerot[i].rotateface(firstface);
2595
+ for (let j = 0; j < face.length; j++) {
2596
+ const jj = (j + 1) % face.length;
2597
+ const midpoint = face[j].sum(face[jj]).smul(0.5);
2598
+ searchaddelement(edgenames, midpoint, i);
2599
+ }
2600
+ }
2601
+ const otherfaces = [];
2602
+ for (let i = 0; i < this.baseplanerot.length; i++) {
2603
+ const face = this.baseplanerot[i].rotateface(firstface);
2604
+ const facelist = [];
2605
+ for (let j = 0; j < face.length; j++) {
2606
+ const jj = (j + 1) % face.length;
2607
+ const midpoint = face[j].sum(face[jj]).smul(0.5);
2608
+ const el = edgenames[findelement(edgenames, midpoint)];
2609
+ if (i === el[1]) {
2610
+ facelist.push(el[2]);
2611
+ } else if (i === el[2]) {
2612
+ facelist.push(el[1]);
2613
+ } else {
2614
+ throw new Error("Could not find edge");
2615
+ }
2616
+ }
2617
+ otherfaces.push(facelist);
2618
+ }
2619
+ const facenametoindex = {};
2620
+ const faceindextoname = [];
2621
+ faceindextoname.push(net[0][0]);
2622
+ facenametoindex[net[0][0]] = 0;
2623
+ faceindextoname[otherfaces[0][0]] = net[0][1];
2624
+ facenametoindex[net[0][1]] = otherfaces[0][0];
2625
+ for (const neti of net) {
2626
+ const f0 = neti[0];
2627
+ const fi = facenametoindex[f0];
2628
+ if (fi === void 0) {
2629
+ throw new Error("Bad edge description; first edge not connected");
2630
+ }
2631
+ let ii = -1;
2632
+ for (let j = 0; j < otherfaces[fi].length; j++) {
2633
+ const fn2 = faceindextoname[otherfaces[fi][j]];
2634
+ if (fn2 !== void 0 && fn2 === neti[1]) {
2635
+ ii = j;
2636
+ break;
2637
+ }
2638
+ }
2639
+ if (ii < 0) {
2640
+ throw new Error("First element of a net not known");
2641
+ }
2642
+ for (let j = 2; j < neti.length; j++) {
2643
+ if (neti[j] === "") {
2644
+ continue;
2645
+ }
2646
+ const of = otherfaces[fi][(j + ii - 1) % edgesperface];
2647
+ const fn2 = faceindextoname[of];
2648
+ if (fn2 !== void 0 && fn2 !== neti[j]) {
2649
+ throw new Error("Face mismatch in net");
2650
+ }
2651
+ faceindextoname[of] = neti[j];
2652
+ facenametoindex[neti[j]] = of;
2653
+ }
2654
+ }
2655
+ for (let i = 0; i < this.baseplanerot.length; i++) {
2656
+ const face = this.baseplanerot[i].rotateface(firstface);
2657
+ const faceplane = boundary.rotateplane(this.baseplanerot[i]);
2658
+ const facename = faceindextoname[i];
2659
+ facenames.push([face, facename]);
2660
+ faceplanes.push([faceplane, facename]);
2661
+ }
2662
+ for (let i = 0; i < this.baseplanerot.length; i++) {
2663
+ const face = this.baseplanerot[i].rotateface(firstface);
2664
+ const facename = faceindextoname[i];
2665
+ for (let j = 0; j < face.length; j++) {
2666
+ const jj = (j + 1) % face.length;
2667
+ const midpoint = face[j].sum(face[jj]).smul(0.5);
2668
+ const jjj = (j + 2) % face.length;
2669
+ const midpoint2 = face[jj].sum(face[jjj]).smul(0.5);
2670
+ const e1 = findelement(edgenames, midpoint);
2671
+ const e2 = findelement(edgenames, midpoint2);
2672
+ searchaddelement(vertexnames, face[jj], [facename, e2, e1]);
2673
+ }
2674
+ }
2675
+ this.swizzler = new FaceNameSwizzler(facenames.map((_) => _[1]));
2676
+ const sep = this.swizzler.prefixFree ? "" : "_";
2677
+ const oridata = orientationDefaults[this.baseFaceCount];
2678
+ const markedface = [];
2679
+ for (let i = 0; i < this.baseFaceCount; i++) {
2680
+ markedface[1 << i] = i;
2681
+ }
2682
+ {
2683
+ const oriprefs = oridata["v"];
2684
+ for (const name of oriprefs) {
2685
+ const fn = this.swizzler.splitByFaceNames(name);
2686
+ let bits = 0;
2687
+ for (const i of fn) {
2688
+ bits |= 1 << i;
2689
+ }
2690
+ markedface[bits] = fn[0];
2691
+ }
2692
+ }
2693
+ {
2694
+ const oriprefs = oridata["e"];
2695
+ for (const name of oriprefs) {
2696
+ const fn = this.swizzler.splitByFaceNames(name);
2697
+ let bits = 0;
2698
+ for (const i of fn) {
2699
+ bits |= 1 << i;
2700
+ }
2701
+ markedface[bits] = fn[0];
2702
+ }
2703
+ }
2704
+ {
2705
+ const oriprefs = oridata["c"];
2706
+ for (const name of oriprefs) {
2707
+ const fn = this.swizzler.splitByFaceNames(name);
2708
+ const bits = 1 << fn[0] | 1 << this.baseFaceCount;
2709
+ markedface[bits] = fn[1];
2710
+ }
2711
+ }
2712
+ for (let i = 0; i < edgenames.length; i++) {
2713
+ if (edgenames[i].length !== 3) {
2714
+ throw new Error("Bad length in edge names " + edgenames[i]);
2715
+ }
2716
+ const f1 = edgenames[i][1];
2717
+ const f2 = edgenames[i][2];
2718
+ let c1 = faceindextoname[f1];
2719
+ const c2 = faceindextoname[f2];
2720
+ const bits = 1 << f1 | 1 << f2;
2721
+ if (markedface[bits] == f1) {
2722
+ c1 = c1 + sep + c2;
2723
+ } else {
2724
+ c1 = c2 + sep + c1;
2725
+ }
2726
+ edgenames[i] = [edgenames[i][0], c1];
2727
+ }
2728
+ for (let i = 0; i < vertexnames.length; i++) {
2729
+ let bits = 0;
2730
+ if (vertexnames[i].length < 4) {
2731
+ throw new Error("Bad length in vertex names");
2732
+ }
2733
+ for (let j = 1; j < vertexnames[i].length; j++) {
2734
+ bits |= 1 << facenametoindex[vertexnames[i][j][0]];
2735
+ }
2736
+ const fi = markedface[bits];
2737
+ let st = -1;
2738
+ for (let j = 1; j < vertexnames[i].length; j++) {
2739
+ if (fi === facenametoindex[vertexnames[i][j][0]]) {
2740
+ st = j;
2741
+ }
2742
+ }
2743
+ if (st < 0) {
2744
+ throw new Error(
2745
+ "Internal error; couldn't find face name when fixing corners"
2746
+ );
2747
+ }
2748
+ let r = "";
2749
+ for (let j = 1; j < vertexnames[i].length; j++) {
2750
+ if (j === 1) {
2751
+ r = vertexnames[i][st][0];
2752
+ } else {
2753
+ r = r + sep + vertexnames[i][st][0];
2754
+ }
2755
+ for (let k = 1; k < vertexnames[i].length; k++) {
2756
+ if (vertexnames[i][st][1] === vertexnames[i][k][2]) {
2757
+ st = k;
2758
+ break;
2759
+ }
2760
+ }
2761
+ }
2762
+ vertexnames[i] = [vertexnames[i][0], r];
2763
+ }
2764
+ this.markedface = markedface;
2765
+ if (this.options.verbosity > 1) {
2766
+ console.log("# Face names: " + facenames.map((_) => _[1]).join(" "));
2767
+ console.log("# Edge names: " + edgenames.map((_) => _[1]).join(" "));
2768
+ console.log("# Vertex names: " + vertexnames.map((_) => _[1]).join(" "));
2769
+ }
2770
+ const geonormals = [];
2771
+ for (const faceplane of faceplanes) {
2772
+ geonormals.push([faceplane[0].makenormal(), faceplane[1], "f"]);
2773
+ }
2774
+ for (const edgename of edgenames) {
2775
+ geonormals.push([edgename[0].makenormal(), edgename[1], "e"]);
2776
+ }
2777
+ for (const vertexname of vertexnames) {
2778
+ geonormals.push([vertexname[0].makenormal(), vertexname[1], "v"]);
2779
+ }
2780
+ this.facenames = facenames;
2781
+ this.faceplanes = faceplanes;
2782
+ this.edgenames = edgenames;
2783
+ this.vertexnames = vertexnames;
2784
+ this.geonormals = geonormals;
2785
+ const geonormalnames = geonormals.map((_) => _[1]);
2786
+ this.swizzler.setGripNames(geonormalnames);
2787
+ if (this.options.verbosity > 0) {
2788
+ console.log(
2789
+ "# Distances: face " + 1 + " edge " + this.edgedistance + " vertex " + this.vertexdistance
2790
+ );
2791
+ }
2792
+ for (let c = 0; c < cutplanes.length; c++) {
2793
+ for (const rotation of this.rotations) {
2794
+ const q = cutplanes[c].rotateplane(rotation);
2795
+ let wasseen = false;
2796
+ for (const moveplane of this.moveplanes) {
2797
+ if (q.sameplane(moveplane)) {
2798
+ wasseen = true;
2799
+ break;
2800
+ }
2801
+ }
2802
+ if (!wasseen) {
2803
+ this.moveplanes.push(q);
2804
+ if (intersects[c]) {
2805
+ this.moveplanes2.push(q);
2806
+ }
2807
+ }
2808
+ }
2809
+ }
2810
+ let ft = new FaceTree(firstface);
2811
+ const tar = this.moveplanes2.slice();
2812
+ let rval = 31;
2813
+ for (let i = 0; i < tar.length; i++) {
2814
+ const j = i + Math.floor((tar.length - i) * (rval / 65536));
2815
+ ft = ft.split(tar[j]);
2816
+ tar[j] = tar[i];
2817
+ rval = (rval * 1657 + 101) % 65536;
2818
+ }
2819
+ const faces = ft.collect([], true);
2820
+ this.faces = faces;
2821
+ if (this.options.verbosity > 0) {
2822
+ console.log("# Faces is now " + faces.length);
2823
+ }
2824
+ this.stickersperface = faces.length;
2825
+ const simplerot = [];
2826
+ const cm = centermassface(firstface);
2827
+ for (const rotation of this.rotations) {
2828
+ const f = rotation.rotateface(firstface);
2829
+ if (cm.dist(centermassface(f)) < eps3) {
2830
+ simplerot.push(rotation);
2831
+ }
2832
+ }
2833
+ const finished = new Array(faces.length);
2834
+ const sortme = [];
2835
+ for (let i = 0; i < faces.length; i++) {
2836
+ const cm2 = faces[i].centermass();
2837
+ sortme.push([cm.dist(cm2), cm2, i]);
2838
+ }
2839
+ sortme.sort((a, b) => a[0] - b[0]);
2840
+ for (let ii = 0; ii < faces.length; ii++) {
2841
+ const i = sortme[ii][2];
2842
+ if (!finished[i]) {
2843
+ finished[i] = true;
2844
+ for (const rot of simplerot) {
2845
+ const f2 = faces[i].rotate(rot);
2846
+ const cm2 = f2.centermass();
2847
+ for (let kk = ii + 1; kk < faces.length; kk++) {
2848
+ if (sortme[kk][0] - sortme[ii][0] > eps3) {
2849
+ break;
2850
+ }
2851
+ const k = sortme[kk][2];
2852
+ if (!finished[k] && cm2.dist(sortme[kk][1]) < eps3) {
2853
+ finished[k] = true;
2854
+ faces[k] = f2;
2855
+ break;
2856
+ }
2857
+ }
2858
+ }
2859
+ }
2860
+ }
2861
+ this.shortedge = 1e99;
2862
+ for (const face of faces) {
2863
+ for (let j = 0; j < face.length; j++) {
2864
+ const k = (j + 1) % face.length;
2865
+ const t = face.get(j).dist(face.get(k));
2866
+ if (t < this.shortedge) {
2867
+ this.shortedge = t;
2868
+ }
2869
+ }
2870
+ }
2871
+ if (this.options.verbosity > 0) {
2872
+ console.log("# Short edge is " + this.shortedge);
2873
+ }
2874
+ if (shape === "c" && sawface && !sawedge && !sawvertex) {
2875
+ this.addNotationMapper = "NxNxNCubeMapper";
2876
+ this.setReidOrder = true;
2877
+ }
2878
+ if (shape === "c" && sawvertex && !sawface && !sawedge) {
2879
+ this.addNotationMapper = "SkewbMapper";
2880
+ }
2881
+ if (shape === "t" && (sawvertex || sawface) && !sawedge) {
2882
+ this.addNotationMapper = "PyraminxOrTetraminxMapper";
2883
+ }
2884
+ if (shape === "o" && sawface) {
2885
+ this.notationMapper = new FaceRenamingMapper(
2886
+ this.swizzler,
2887
+ new FaceNameSwizzler(["F", "D", "L", "BL", "R", "U", "BR", "B"])
2888
+ );
2889
+ if (!sawedge && !sawvertex) {
2890
+ this.addNotationMapper = "FTOMapper";
2891
+ }
2892
+ }
2893
+ if (shape === "d" && sawface) {
2894
+ this.addNotationMapper = "MegaminxMapper";
2895
+ this.notationMapper = new FaceRenamingMapper(
2896
+ this.swizzler,
2897
+ new FaceNameSwizzler([
2898
+ "U",
2899
+ "F",
2900
+ "L",
2901
+ "BL",
2902
+ "BR",
2903
+ "R",
2904
+ "FR",
2905
+ "FL",
2906
+ "DL",
2907
+ "B",
2908
+ "DR",
2909
+ "D"
2910
+ ])
2911
+ );
2912
+ }
2913
+ }
2914
+ keyface(face) {
2915
+ return this.keyface2(face.centermass());
2916
+ }
2917
+ keyface2(cm) {
2918
+ let s = "";
2919
+ const sfcc = String.fromCharCode;
2920
+ for (const moveplaneset of this.moveplanesets) {
2921
+ if (moveplaneset.length > 0) {
2922
+ const dv = cm.dot(moveplaneset[0]);
2923
+ let t = 0;
2924
+ let b = 1;
2925
+ while (b * 2 <= moveplaneset.length) {
2926
+ b *= 2;
2927
+ }
2928
+ for (; b > 0; b >>= 1) {
2929
+ if (t + b <= moveplaneset.length && dv > moveplaneset[t + b - 1].a) {
2930
+ t += b;
2931
+ }
2932
+ }
2933
+ if (t < 47) {
2934
+ s = s + sfcc(33 + t);
2935
+ } else if (t < 47 + 47 * 47) {
2936
+ s = s + sfcc(33 + 47 + Math.floor(t / 47) - 1) + sfcc(33 + t % 47);
2937
+ } else if (t < 47 + 47 * 47 + 47 * 47 * 47) {
2938
+ s = s + sfcc(33 + 47 + Math.floor((t - 47) / (47 * 47) - 1)) + sfcc(33 + 47 + Math.floor((t - 47) / 47) % 47) + sfcc(33 + t % 47);
2939
+ } else {
2940
+ throw Error("Too many slices for cubie encoding");
2941
+ }
2942
+ }
2943
+ }
2944
+ return s;
2945
+ }
2946
+ keyface3(face) {
2947
+ const cm = face.centermass();
2948
+ const r = [];
2949
+ for (const moveplaneset of this.moveplanesets) {
2950
+ if (moveplaneset.length > 0) {
2951
+ const dv = cm.dot(moveplaneset[0]);
2952
+ let t = 0;
2953
+ let b = 1;
2954
+ while (b * 2 <= moveplaneset.length) {
2955
+ b *= 2;
2956
+ }
2957
+ for (; b > 0; b >>= 1) {
2958
+ if (t + b <= moveplaneset.length && dv > moveplaneset[t + b - 1].a) {
2959
+ t += b;
2960
+ }
2961
+ }
2962
+ r.push(t);
2963
+ }
2964
+ }
2965
+ return r;
2966
+ }
2967
+ findface(cm) {
2968
+ const key = this.keyface2(cm);
2969
+ const arr = this.facelisthash.get(key);
2970
+ if (arr.length === 1) {
2971
+ return arr[0];
2972
+ }
2973
+ for (let i = 0; i + 1 < arr.length; i++) {
2974
+ const face2 = this.facelisthash.get(key)[i];
2975
+ if (Math.abs(cm.dist(this.facecentermass[face2])) < eps3) {
2976
+ return face2;
2977
+ }
2978
+ }
2979
+ return arr[arr.length - 1];
2980
+ }
2981
+ project2d(facen, edgen, targvec) {
2982
+ const face = this.facenames[facen][0];
2983
+ const edgen2 = (edgen + 1) % face.length;
2984
+ const plane = this.baseplanes[facen];
2985
+ let x0 = face[edgen2].sub(face[edgen]);
2986
+ const olen = x0.len();
2987
+ x0 = x0.normalize();
2988
+ const y0 = x0.cross(plane).normalize();
2989
+ let delta = targvec[1].sub(targvec[0]);
2990
+ const len = delta.len() / olen;
2991
+ delta = delta.normalize();
2992
+ const cosr = delta.b;
2993
+ const sinr = delta.c;
2994
+ const x1 = x0.smul(cosr).sub(y0.smul(sinr)).smul(len);
2995
+ const y1 = y0.smul(cosr).sum(x0.smul(sinr)).smul(len);
2996
+ const off = new Quat(
2997
+ 0,
2998
+ targvec[0].b - x1.dot(face[edgen]),
2999
+ targvec[0].c - y1.dot(face[edgen]),
3000
+ 0
3001
+ );
3002
+ return [x1, y1, off];
3003
+ }
3004
+ allstickers() {
3005
+ const t1 = tstart("allstickers");
3006
+ this.faces = expandfaces(this.baseplanerot, this.faces);
3007
+ if (this.options.verbosity > 0) {
3008
+ console.log("# Total stickers is now " + this.faces.length);
3009
+ }
3010
+ this.facecentermass = new Array(this.faces.length);
3011
+ for (let i = 0; i < this.faces.length; i++) {
3012
+ this.facecentermass[i] = this.faces[i].centermass();
3013
+ }
3014
+ const moveplanesets = [];
3015
+ const moveplanenormals = [];
3016
+ for (const q of this.moveplanes) {
3017
+ const qnormal = q.makenormal();
3018
+ let wasseen = false;
3019
+ for (const moveplanenormal of moveplanenormals) {
3020
+ if (qnormal.sameplane(moveplanenormal.makenormal())) {
3021
+ wasseen = true;
3022
+ }
3023
+ }
3024
+ if (!wasseen) {
3025
+ moveplanenormals.push(qnormal);
3026
+ moveplanesets.push([]);
3027
+ }
3028
+ }
3029
+ for (const q of this.moveplanes2) {
3030
+ const qnormal = q.makenormal();
3031
+ for (let j = 0; j < moveplanenormals.length; j++) {
3032
+ if (qnormal.sameplane(moveplanenormals[j])) {
3033
+ moveplanesets[j].push(q);
3034
+ break;
3035
+ }
3036
+ }
3037
+ }
3038
+ for (let i = 0; i < moveplanesets.length; i++) {
3039
+ const q = moveplanesets[i].map((_) => _.normalizeplane());
3040
+ const goodnormal = moveplanenormals[i];
3041
+ for (let j = 0; j < q.length; j++) {
3042
+ if (q[j].makenormal().dist(goodnormal) > eps3) {
3043
+ q[j] = q[j].smul(-1);
3044
+ }
3045
+ }
3046
+ q.sort((a, b) => a.a - b.a);
3047
+ moveplanesets[i] = q;
3048
+ }
3049
+ this.moveplanesets = moveplanesets;
3050
+ this.moveplanenormals = moveplanenormals;
3051
+ const sizes = moveplanesets.map((_) => _.length);
3052
+ if (this.options.verbosity > 0) {
3053
+ console.log("# Move plane sets: " + sizes);
3054
+ }
3055
+ const moverotations = [];
3056
+ for (let i = 0; i < moveplanesets.length; i++) {
3057
+ moverotations.push([]);
3058
+ }
3059
+ for (const q of this.rotations) {
3060
+ if (Math.abs(Math.abs(q.a) - 1) < eps3) {
3061
+ continue;
3062
+ }
3063
+ const qnormal = q.makenormal();
3064
+ for (let j = 0; j < moveplanesets.length; j++) {
3065
+ if (qnormal.sameplane(moveplanenormals[j])) {
3066
+ moverotations[j].push(q);
3067
+ break;
3068
+ }
3069
+ }
3070
+ }
3071
+ this.moverotations = moverotations;
3072
+ for (let i = 0; i < moverotations.length; i++) {
3073
+ const r = moverotations[i];
3074
+ const goodnormal = r[0].makenormal();
3075
+ for (let j = 0; j < r.length; j++) {
3076
+ if (goodnormal.dist(r[j].makenormal()) > eps3) {
3077
+ r[j] = r[j].smul(-1);
3078
+ }
3079
+ }
3080
+ r.sort((a, b) => a.angle() - b.angle());
3081
+ if (moverotations[i][0].dot(moveplanenormals[i]) < 0) {
3082
+ r.reverse();
3083
+ }
3084
+ }
3085
+ const sizes2 = moverotations.map((_) => 1 + _.length);
3086
+ this.movesetorders = sizes2;
3087
+ const movesetgeos = [];
3088
+ let gtype = "?";
3089
+ for (let i = 0; i < moveplanesets.length; i++) {
3090
+ const p0 = moveplanenormals[i];
3091
+ let neg = null;
3092
+ let pos = null;
3093
+ for (const geonormal of this.geonormals) {
3094
+ const d = p0.dot(geonormal[0]);
3095
+ if (Math.abs(d - 1) < eps3) {
3096
+ pos = [geonormal[1], geonormal[2]];
3097
+ gtype = geonormal[2];
3098
+ } else if (Math.abs(d + 1) < eps3) {
3099
+ neg = [geonormal[1], geonormal[2]];
3100
+ gtype = geonormal[2];
3101
+ }
3102
+ }
3103
+ if (pos === null || neg === null) {
3104
+ throw new Error("Saw positive or negative sides as null");
3105
+ }
3106
+ movesetgeos.push([
3107
+ pos[0],
3108
+ pos[1],
3109
+ neg[0],
3110
+ neg[1],
3111
+ 1 + moveplanesets[i].length
3112
+ ]);
3113
+ if (this.addNotationMapper === "NxNxNCubeMapper" && gtype === "f") {
3114
+ this.notationMapper = new NxNxNCubeMapper(1 + moveplanesets[i].length);
3115
+ this.addNotationMapper = "";
3116
+ }
3117
+ if (this.addNotationMapper === "SkewbMapper" && moveplanesets[0].length === 1) {
3118
+ this.notationMapper = new SkewbNotationMapper(this.swizzler);
3119
+ this.addNotationMapper = "";
3120
+ }
3121
+ if (this.addNotationMapper === "PyraminxOrTetraminxMapper") {
3122
+ if (moveplanesets[0].length === 2 && moveplanesets[0][0].a === 0.333333333333333 && moveplanesets[0][1].a === 1.66666666666667) {
3123
+ this.notationMapper = new PyraminxNotationMapper(this.swizzler);
3124
+ this.addNotationMapper = "";
3125
+ } else {
3126
+ this.notationMapper = new TetraminxNotationMapper(this.swizzler);
3127
+ this.addNotationMapper = "";
3128
+ }
3129
+ }
3130
+ if (this.addNotationMapper === "MegaminxMapper" && gtype === "f") {
3131
+ if (1 + moveplanesets[i].length === 3) {
3132
+ this.notationMapper = new MegaminxScramblingNotationMapper(
3133
+ this.notationMapper
3134
+ );
3135
+ }
3136
+ this.addNotationMapper = "";
3137
+ }
3138
+ if (this.addNotationMapper === "FTOMapper" && gtype === "f") {
3139
+ if (1 + moveplanesets[i].length === 3) {
3140
+ this.notationMapper = new FTONotationMapper(
3141
+ this.notationMapper,
3142
+ this.swizzler
3143
+ );
3144
+ }
3145
+ this.addNotationMapper = "";
3146
+ }
3147
+ }
3148
+ this.movesetgeos = movesetgeos;
3149
+ const facelisthash = /* @__PURE__ */ new Map();
3150
+ const faces = this.faces;
3151
+ for (let i = 0; i < faces.length; i++) {
3152
+ const face = faces[i];
3153
+ const s = this.keyface(face);
3154
+ if (!facelisthash.get(s)) {
3155
+ facelisthash.set(s, [i]);
3156
+ } else {
3157
+ const arr = facelisthash.get(s);
3158
+ arr.push(i);
3159
+ if (arr.length === this.baseFaceCount) {
3160
+ if (this.options.verbosity > 0) {
3161
+ console.log("# Splitting core.");
3162
+ }
3163
+ for (let suff = 0; suff < arr.length; suff++) {
3164
+ const s2 = s + " " + suff;
3165
+ facelisthash.set(s2, [arr[suff]]);
3166
+ }
3167
+ }
3168
+ }
3169
+ }
3170
+ this.facelisthash = facelisthash;
3171
+ if (this.options.verbosity > 0) {
3172
+ console.log("# Cubies: " + facelisthash.size);
3173
+ }
3174
+ const cubies = [];
3175
+ const facetocubie = [];
3176
+ const facetoord = [];
3177
+ for (const facelist of facelisthash.values()) {
3178
+ if (facelist.length === this.baseFaceCount) {
3179
+ continue;
3180
+ }
3181
+ if (facelist.length > 1) {
3182
+ const cm = facelist.map((_) => faces[_].centermass());
3183
+ const cmall = centermassface(cm);
3184
+ for (let looplimit = 0; facelist.length > 2; looplimit++) {
3185
+ let changed = false;
3186
+ for (let i = 0; i < facelist.length; i++) {
3187
+ const j = (i + 1) % facelist.length;
3188
+ if (cmall.dot(cm[i].cross(cm[j])) < 0) {
3189
+ const u = cm[i];
3190
+ cm[i] = cm[j];
3191
+ cm[j] = u;
3192
+ const v = facelist[i];
3193
+ facelist[i] = facelist[j];
3194
+ facelist[j] = v;
3195
+ changed = true;
3196
+ }
3197
+ }
3198
+ if (!changed) {
3199
+ break;
3200
+ }
3201
+ if (looplimit > 1e3) {
3202
+ throw new Error("Bad epsilon math; too close to border");
3203
+ }
3204
+ }
3205
+ let bits = 0;
3206
+ for (const f of facelist) {
3207
+ bits |= 1 << Math.floor(f / this.stickersperface);
3208
+ }
3209
+ const markedface = this.markedface[bits];
3210
+ let mini = -1;
3211
+ for (let i = 0; i < facelist.length; i++) {
3212
+ if (Math.floor(facelist[i] / this.stickersperface) === markedface) {
3213
+ mini = i;
3214
+ }
3215
+ }
3216
+ if (mini < 0) {
3217
+ throw new Error("Could not find marked face in list");
3218
+ }
3219
+ if (mini !== 0) {
3220
+ const ofacelist = facelist.slice();
3221
+ for (let i = 0; i < facelist.length; i++) {
3222
+ facelist[i] = ofacelist[(mini + i) % facelist.length];
3223
+ }
3224
+ }
3225
+ }
3226
+ for (let j = 0; j < facelist.length; j++) {
3227
+ const k = facelist[j];
3228
+ facetocubie[k] = cubies.length;
3229
+ facetoord[k] = j;
3230
+ }
3231
+ cubies.push(facelist);
3232
+ }
3233
+ this.cubies = cubies;
3234
+ this.facetocubie = facetocubie;
3235
+ this.facetoord = facetoord;
3236
+ const typenames = ["?", "CENTERS", "EDGES", "CORNERS", "C4RNER", "C5RNER"];
3237
+ const cubiesetnames = [];
3238
+ const cubietypecounts = [0, 0, 0, 0, 0, 0];
3239
+ const orbitoris = [];
3240
+ const seen = [];
3241
+ let cubiesetnum = 0;
3242
+ const cubiesetnums = [];
3243
+ const cubieordnums = [];
3244
+ const cubieords = [];
3245
+ const cubievaluemap = [];
3246
+ const getcolorkey = (cubienum) => {
3247
+ return cubies[cubienum].map((_) => this.getfaceindex(_)).join(" ");
3248
+ };
3249
+ const cubiesetcubies = [];
3250
+ for (let i = 0; i < cubies.length; i++) {
3251
+ const cubie = cubies[i];
3252
+ if (cubie.length === 0) {
3253
+ continue;
3254
+ }
3255
+ if (seen[i]) {
3256
+ continue;
3257
+ }
3258
+ const cubiekeymap = {};
3259
+ let cubievalueid = 0;
3260
+ cubieords.push(0);
3261
+ cubiesetcubies.push([]);
3262
+ const facecnt = cubie.length;
3263
+ const typectr = cubietypecounts[facecnt]++;
3264
+ let typename = typenames[facecnt];
3265
+ if (typename === void 0 || facecnt === this.baseFaceCount) {
3266
+ typename = "CORE";
3267
+ }
3268
+ typename = typename + (typectr === 0 ? "" : typectr + 1);
3269
+ cubiesetnames[cubiesetnum] = typename;
3270
+ orbitoris[cubiesetnum] = facecnt;
3271
+ const queue = [i];
3272
+ let qg = 0;
3273
+ seen[i] = true;
3274
+ while (qg < queue.length) {
3275
+ const cind = queue[qg++];
3276
+ const cubiecolorkey = getcolorkey(cind);
3277
+ if (cubie.length > 1 || cubiekeymap[cubiecolorkey] === void 0) {
3278
+ cubiekeymap[cubiecolorkey] = cubievalueid++;
3279
+ }
3280
+ cubievaluemap[cind] = cubiekeymap[cubiecolorkey];
3281
+ cubiesetnums[cind] = cubiesetnum;
3282
+ cubiesetcubies[cubiesetnum].push(cind);
3283
+ cubieordnums[cind] = cubieords[cubiesetnum]++;
3284
+ if (queue.length < this.rotations.length) {
3285
+ const cm = this.facecentermass[cubies[cind][0]];
3286
+ for (const moverotation of moverotations) {
3287
+ const tq = this.facetocubie[this.findface(cm.rotatepoint(moverotation[0]))];
3288
+ if (!seen[tq]) {
3289
+ queue.push(tq);
3290
+ seen[tq] = true;
3291
+ }
3292
+ }
3293
+ }
3294
+ }
3295
+ cubiesetnum++;
3296
+ }
3297
+ if (this.setReidOrder && 4 <= this.stickersperface && this.stickersperface <= 9) {
3298
+ const reidorder = [
3299
+ [
3300
+ "UF",
3301
+ "UR",
3302
+ "UB",
3303
+ "UL",
3304
+ "DF",
3305
+ "DR",
3306
+ "DB",
3307
+ "DL",
3308
+ "FR",
3309
+ "FL",
3310
+ "BR",
3311
+ "BL"
3312
+ ],
3313
+ ["UFR", "URB", "UBL", "ULF", "DRF", "DFL", "DLB", "DBR"],
3314
+ ["U", "L", "F", "R", "B", "D"]
3315
+ ];
3316
+ const reidmap = {};
3317
+ for (const cubie of reidorder) {
3318
+ for (let j = 0; j < cubie.length; j++) {
3319
+ let mask = 0;
3320
+ for (let k = 0; k < cubie[j].length; k++) {
3321
+ mask |= 1 << cubie[j].charCodeAt(k) - 65;
3322
+ }
3323
+ reidmap[mask] = j;
3324
+ }
3325
+ }
3326
+ for (const cubieset of cubiesetcubies) {
3327
+ for (const cubienum of cubieset) {
3328
+ let mask = 0;
3329
+ for (const cubie of cubies[cubienum]) {
3330
+ mask |= 1 << this.facenames[this.getfaceindex(cubie)][1].charCodeAt(0) - 65;
3331
+ }
3332
+ cubieordnums[cubienum] = reidmap[mask];
3333
+ }
3334
+ }
3335
+ }
3336
+ this.cubiesetnums = cubiesetnums;
3337
+ this.cubieordnums = cubieordnums;
3338
+ this.cubiesetnames = cubiesetnames;
3339
+ this.cubieords = cubieords;
3340
+ this.orbitoris = orbitoris;
3341
+ this.cubievaluemap = cubievaluemap;
3342
+ this.cubiesetcubies = cubiesetcubies;
3343
+ if (this.options.fixedPieceType !== null) {
3344
+ for (let i = 0; i < cubies.length; i++) {
3345
+ if (this.options.fixedPieceType === "v" && cubies[i].length > 2 || this.options.fixedPieceType === "e" && cubies[i].length === 2 || this.options.fixedPieceType === "f" && cubies[i].length === 1) {
3346
+ this.fixedCubie = i;
3347
+ break;
3348
+ }
3349
+ }
3350
+ if (this.fixedCubie < 0) {
3351
+ throw new Error(
3352
+ "Could not find a cubie of type " + this.options.fixedPieceType + " to fix."
3353
+ );
3354
+ }
3355
+ }
3356
+ if (this.options.verbosity > 0) {
3357
+ console.log("# Cubie orbit sizes " + cubieords);
3358
+ }
3359
+ tend(t1);
3360
+ }
3361
+ unswizzle(mv) {
3362
+ const newmv = this.notationMapper.notationToInternal(mv);
3363
+ if (newmv === null) {
3364
+ return null;
3365
+ }
3366
+ return newmv.modified({ family: this.swizzler.unswizzle(newmv.family) });
3367
+ }
3368
+ stringToBlockMove(mv) {
3369
+ const re = RegExp("^(([0-9]+)-)?([0-9]+)?([^0-9]+)([0-9]+'?)?$");
3370
+ const p = mv.match(re);
3371
+ if (p === null) {
3372
+ throw new Error("Bad move passed " + mv);
3373
+ }
3374
+ const grip = p[4];
3375
+ let loslice = void 0;
3376
+ let hislice = void 0;
3377
+ if (p[2] !== void 0) {
3378
+ if (p[3] === void 0) {
3379
+ throw new Error("Missing second number in range");
3380
+ }
3381
+ loslice = parseInt(p[2], 10);
3382
+ }
3383
+ if (p[3] !== void 0) {
3384
+ hislice = parseInt(p[3], 10);
3385
+ }
3386
+ let amountstr = "1";
3387
+ let amount = 1;
3388
+ if (p[5] !== void 0) {
3389
+ amountstr = p[5];
3390
+ if (amountstr[0] === "'") {
3391
+ amountstr = "-" + amountstr.substring(1);
3392
+ }
3393
+ amount = parseInt(amountstr, 10);
3394
+ }
3395
+ return new Move(new QuantumMove(grip, hislice, loslice), amount);
3396
+ }
3397
+ parseMove(move) {
3398
+ const bm = this.notationMapper.notationToInternal(move);
3399
+ if (bm === null) {
3400
+ throw new Error("Bad move " + move.family);
3401
+ }
3402
+ move = bm;
3403
+ let grip = move.family;
3404
+ let fullrotation = false;
3405
+ if (grip.endsWith("v") && grip[0] <= "Z") {
3406
+ if (move.innerLayer !== void 0 || move.outerLayer !== void 0) {
3407
+ throw new Error("Cannot use a prefix with full cube rotations");
3408
+ }
3409
+ grip = grip.slice(0, -1);
3410
+ fullrotation = true;
3411
+ }
3412
+ if (grip.endsWith("w") && grip[0] <= "Z") {
3413
+ grip = grip.slice(0, -1).toLowerCase();
3414
+ }
3415
+ let geo;
3416
+ let msi = -1;
3417
+ const geoname = this.swizzler.unswizzle(grip);
3418
+ let firstgrip = false;
3419
+ for (let i = 0; i < this.movesetgeos.length; i++) {
3420
+ const g = this.movesetgeos[i];
3421
+ if (geoname === g[0]) {
3422
+ firstgrip = true;
3423
+ geo = g;
3424
+ msi = i;
3425
+ }
3426
+ if (geoname === g[2]) {
3427
+ firstgrip = false;
3428
+ geo = g;
3429
+ msi = i;
3430
+ }
3431
+ }
3432
+ let loslice = 1;
3433
+ let hislice = 1;
3434
+ if (grip.toUpperCase() !== grip) {
3435
+ hislice = 2;
3436
+ }
3437
+ if (geo === void 0) {
3438
+ throw new Error("Bad grip in move " + move.family);
3439
+ }
3440
+ if (move.outerLayer !== void 0) {
3441
+ loslice = move.outerLayer;
3442
+ }
3443
+ if (move.innerLayer !== void 0) {
3444
+ if (move.outerLayer === void 0) {
3445
+ hislice = move.innerLayer;
3446
+ if (grip <= "Z") {
3447
+ loslice = hislice;
3448
+ } else {
3449
+ loslice = 1;
3450
+ }
3451
+ } else {
3452
+ hislice = move.innerLayer;
3453
+ }
3454
+ }
3455
+ loslice--;
3456
+ hislice--;
3457
+ if (fullrotation) {
3458
+ loslice = 0;
3459
+ hislice = this.moveplanesets[msi].length;
3460
+ }
3461
+ if (loslice < 0 || loslice > this.moveplanesets[msi].length || hislice < 0 || hislice > this.moveplanesets[msi].length) {
3462
+ throw new Error(
3463
+ "Bad slice spec " + loslice + " " + hislice + " vs " + this.moveplanesets[msi].length
3464
+ );
3465
+ }
3466
+ if (!permissivieMoveParsing && loslice === 0 && hislice === this.moveplanesets[msi].length && !fullrotation) {
3467
+ throw new Error(
3468
+ "! full puzzle rotations must be specified with v suffix."
3469
+ );
3470
+ }
3471
+ return [void 0, msi, loslice, hislice, firstgrip, move.amount];
3472
+ }
3473
+ parsemove(mv) {
3474
+ const r = this.parseMove(this.stringToBlockMove(mv));
3475
+ r[0] = mv;
3476
+ return r;
3477
+ }
3478
+ genperms() {
3479
+ const t1 = tstart("genperms");
3480
+ if (this.cmovesbyslice.length > 0) {
3481
+ return;
3482
+ }
3483
+ const cmovesbyslice = [];
3484
+ if (this.options.orientCenters) {
3485
+ for (let k = 0; k < this.cubies.length; k++) {
3486
+ if (this.cubies[k].length === 1) {
3487
+ const kk = this.cubies[k][0];
3488
+ const i = this.getfaceindex(kk);
3489
+ const center = this.basefaces[i].centermass();
3490
+ if (center.dist(this.facecentermass[kk]) < eps3) {
3491
+ const bits = 1 << i | 1 << this.baseFaceCount;
3492
+ const towards = this.markedface[bits];
3493
+ const normal = this.baseplanes[towards].makenormal();
3494
+ let hiv = -1;
3495
+ let hii = -1;
3496
+ for (let ii = 0; ii < this.faces[kk].length; ii++) {
3497
+ const pt = this.faces[kk].get(ii);
3498
+ const t = normal.dot(pt.sub(center));
3499
+ if (t > hiv) {
3500
+ hiv = t;
3501
+ hii = ii;
3502
+ }
3503
+ }
3504
+ const hii2 = (hii + 1) % this.faces[kk].length;
3505
+ if (Math.abs(normal.dot(this.faces[kk].get(hii2).sub(center)) - hiv) < eps3) {
3506
+ hii = hii2;
3507
+ }
3508
+ if (hii != 0) {
3509
+ const qs = [];
3510
+ for (let ii = 0; ii < this.faces[kk].length; ii++) {
3511
+ qs.push(this.faces[kk].get((ii + hii) % this.faces[kk].length));
3512
+ }
3513
+ this.faces[kk] = new Face(qs);
3514
+ }
3515
+ const o = this.basefaces[i].length;
3516
+ for (let m = 1; m < o; m++) {
3517
+ this.cubies[k].push(this.cubies[k][m - 1]);
3518
+ }
3519
+ this.duplicatedFaces[kk] = o;
3520
+ this.duplicatedCubies[k] = o;
3521
+ this.orbitoris[this.cubiesetnums[k]] = o;
3522
+ }
3523
+ }
3524
+ }
3525
+ }
3526
+ for (let k = 0; k < this.moveplanesets.length; k++) {
3527
+ const moveplaneset = this.moveplanesets[k];
3528
+ const slicenum = [];
3529
+ const slicecnts = [moveplaneset.length + 1, 0];
3530
+ let bhi = 1;
3531
+ while (bhi * 2 <= moveplaneset.length) {
3532
+ bhi *= 2;
3533
+ }
3534
+ for (let i = 0; i < this.faces.length; i++) {
3535
+ let t = 0;
3536
+ if (moveplaneset.length > 0) {
3537
+ const dv = this.facecentermass[i].dot(moveplaneset[0]);
3538
+ for (let b = bhi; b > 0; b >>= 1) {
3539
+ if (t + b <= moveplaneset.length && dv > moveplaneset[t + b - 1].a) {
3540
+ t += b;
3541
+ }
3542
+ }
3543
+ t = moveplaneset.length - t;
3544
+ }
3545
+ slicenum.push(t);
3546
+ while (slicecnts.length <= t) {
3547
+ slicecnts.push(0);
3548
+ }
3549
+ slicecnts[t]++;
3550
+ }
3551
+ const axiscmoves = new Array(slicecnts.length);
3552
+ for (let sc = 0; sc < slicecnts.length; sc++) {
3553
+ axiscmoves[sc] = [];
3554
+ }
3555
+ const cubiedone = [];
3556
+ for (let i = 0; i < this.faces.length; i++) {
3557
+ if (slicenum[i] < 0) {
3558
+ continue;
3559
+ }
3560
+ const b = [this.facetocubie[i], this.facetoord[i]];
3561
+ let cm = this.facecentermass[i];
3562
+ const ocm = cm;
3563
+ let fi2 = i;
3564
+ const sc = slicenum[fi2];
3565
+ for (; ; ) {
3566
+ slicenum[fi2] = -1;
3567
+ const cm2 = cm.rotatepoint(this.moverotations[k][0]);
3568
+ if (cm2.dist(ocm) < eps3) {
3569
+ break;
3570
+ }
3571
+ fi2 = this.findface(cm2);
3572
+ b.push(this.facetocubie[fi2], this.facetoord[fi2]);
3573
+ cm = cm2;
3574
+ }
3575
+ if (b.length > 2 && this.options.orientCenters && (this.cubies[b[0]].length === 1 || this.duplicatedCubies[b[0]] > 1)) {
3576
+ if (this.facecentermass[i].dist(
3577
+ this.basefaces[this.getfaceindex(i)].centermass()
3578
+ ) < eps3) {
3579
+ let face1 = this.faces[this.cubies[b[0]][0]];
3580
+ for (let ii = 0; ii < b.length; ii += 2) {
3581
+ const face0 = this.faces[this.cubies[b[ii]][0]];
3582
+ let o = -1;
3583
+ for (let jj = 0; jj < face1.length; jj++) {
3584
+ if (face0.get(jj).dist(face1.get(0)) < eps3) {
3585
+ o = jj;
3586
+ break;
3587
+ }
3588
+ }
3589
+ if (o < 0) {
3590
+ throw new Error(
3591
+ "Couldn't find rotation of center faces; ignoring for now."
3592
+ );
3593
+ } else {
3594
+ b[ii + 1] = o;
3595
+ face1 = face1.rotate(this.moverotations[k][0]);
3596
+ }
3597
+ }
3598
+ }
3599
+ }
3600
+ if (b.length === 2 && this.options.orientCenters) {
3601
+ for (let ii = 1; ii < this.movesetorders[k]; ii++) {
3602
+ if (sc === 0) {
3603
+ b.push(b[0], ii);
3604
+ } else {
3605
+ b.push(
3606
+ b[0],
3607
+ (this.movesetorders[k] - ii) % this.movesetorders[k]
3608
+ );
3609
+ }
3610
+ }
3611
+ }
3612
+ if (b.length > 2 && !cubiedone[b[0]]) {
3613
+ if (b.length !== 2 * this.movesetorders[k]) {
3614
+ throw new Error("Bad length in perm gen");
3615
+ }
3616
+ for (const v of b) {
3617
+ axiscmoves[sc].push(v);
3618
+ }
3619
+ }
3620
+ for (let j = 0; j < b.length; j += 2) {
3621
+ cubiedone[b[j]] = true;
3622
+ }
3623
+ }
3624
+ for (let kk = 0; kk < axiscmoves.length; kk++) {
3625
+ axiscmoves[kk] = axiscmoves[kk].slice();
3626
+ }
3627
+ cmovesbyslice.push(axiscmoves);
3628
+ }
3629
+ this.cmovesbyslice = cmovesbyslice;
3630
+ if (this.options.moveList) {
3631
+ const parsedmovelist = [];
3632
+ for (const moveString of this.options.moveList) {
3633
+ parsedmovelist.push(this.parsemove(moveString));
3634
+ }
3635
+ this.parsedmovelist = parsedmovelist;
3636
+ }
3637
+ this.facelisthash.clear();
3638
+ this.facecentermass = [];
3639
+ tend(t1);
3640
+ }
3641
+ getboundarygeometry() {
3642
+ return {
3643
+ baseplanes: this.baseplanes,
3644
+ facenames: this.facenames,
3645
+ faceplanes: this.faceplanes,
3646
+ vertexnames: this.vertexnames,
3647
+ edgenames: this.edgenames,
3648
+ geonormals: this.geonormals
3649
+ };
3650
+ }
3651
+ getmovesets(k) {
3652
+ const slices = this.moveplanesets[k].length;
3653
+ let r = [];
3654
+ if (this.parsedmovelist !== void 0) {
3655
+ for (const parsedmove of this.parsedmovelist) {
3656
+ if (parsedmove[1] !== k) {
3657
+ continue;
3658
+ }
3659
+ if (parsedmove[4]) {
3660
+ r.push([parsedmove[2], parsedmove[3]]);
3661
+ } else {
3662
+ r.push([slices - parsedmove[3], slices - parsedmove[2]]);
3663
+ }
3664
+ r.push(parsedmove[5]);
3665
+ }
3666
+ } else if (this.options.vertexMoves && !this.options.allMoves) {
3667
+ const msg = this.movesetgeos[k];
3668
+ if (msg[1] !== msg[3]) {
3669
+ for (let i = 0; i < slices; i++) {
3670
+ if (msg[1] !== "v") {
3671
+ if (this.options.outerBlockMoves) {
3672
+ r.push([i + 1, slices]);
3673
+ } else {
3674
+ r.push([i + 1]);
3675
+ }
3676
+ r.push(1);
3677
+ } else {
3678
+ if (this.options.outerBlockMoves) {
3679
+ r.push([0, i]);
3680
+ } else {
3681
+ r.push([i, i]);
3682
+ }
3683
+ r.push(1);
3684
+ }
3685
+ }
3686
+ }
3687
+ } else {
3688
+ for (let i = 0; i <= slices; i++) {
3689
+ if (!this.options.allMoves && i + i === slices) {
3690
+ continue;
3691
+ }
3692
+ if (this.options.outerBlockMoves) {
3693
+ if (i + i > slices) {
3694
+ r.push([i, slices]);
3695
+ } else {
3696
+ r.push([0, i]);
3697
+ }
3698
+ } else {
3699
+ r.push([i, i]);
3700
+ }
3701
+ r.push(1);
3702
+ }
3703
+ }
3704
+ if (this.fixedCubie >= 0) {
3705
+ const dep = this.keyface3(this.faces[this.cubies[this.fixedCubie][0]])[k];
3706
+ const newr = [];
3707
+ for (let i = 0; i < r.length; i += 2) {
3708
+ let o = r[i];
3709
+ if (dep >= o[0] && dep <= o[1]) {
3710
+ if (o[0] === 0) {
3711
+ o = [o[1] + 1, slices];
3712
+ } else if (slices === o[1]) {
3713
+ o = [0, o[0] - 1];
3714
+ } else {
3715
+ throw Error("fixed cubie option would disconnect move");
3716
+ }
3717
+ }
3718
+ let found = false;
3719
+ for (let j = 0; j < newr.length; j += 2) {
3720
+ if (newr[j][0] === o[0] && newr[j][1] === o[1] && newr[j + 1] === r[i + 1]) {
3721
+ found = true;
3722
+ break;
3723
+ }
3724
+ }
3725
+ if (!found) {
3726
+ newr.push(o);
3727
+ newr.push(r[i + 1]);
3728
+ }
3729
+ }
3730
+ r = newr;
3731
+ }
3732
+ return r;
3733
+ }
3734
+ graybyori(cubie) {
3735
+ let ori = this.cubies[cubie].length;
3736
+ if (this.duplicatedCubies[cubie]) {
3737
+ ori = 1;
3738
+ }
3739
+ return ori === 1 && (this.options.grayCenters || !this.options.includeCenterOrbits) || ori === 2 && (this.options.grayEdges || !this.options.includeEdgeOrbits) || ori > 2 && (this.options.grayCorners || !this.options.includeCornerOrbits);
3740
+ }
3741
+ skipbyori(cubie) {
3742
+ let ori = this.cubies[cubie].length;
3743
+ if (this.duplicatedCubies[cubie]) {
3744
+ ori = 1;
3745
+ }
3746
+ return ori === 1 && !this.options.includeCenterOrbits || ori === 2 && !this.options.includeEdgeOrbits || ori > 2 && !this.options.includeCornerOrbits;
3747
+ }
3748
+ skipcubie(fi) {
3749
+ return this.skipbyori(fi);
3750
+ }
3751
+ header(comment) {
3752
+ return comment + copyright + "\n" + comment + "\n";
3753
+ }
3754
+ writegap() {
3755
+ const os = this.getOrbitsDef(false);
3756
+ const r = [];
3757
+ const mvs = [];
3758
+ for (let i = 0; i < os.moveops.length; i++) {
3759
+ let movename = "M_" + externalName(this.notationMapper, os.movenames[i]);
3760
+ let doinv = false;
3761
+ if (movename[movename.length - 1] === "'") {
3762
+ movename = movename.substring(0, movename.length - 1);
3763
+ doinv = true;
3764
+ }
3765
+ mvs.push(movename);
3766
+ if (doinv) {
3767
+ r.push(movename + ":=" + os.moveops[i].toPerm().inv().toGap() + ";");
3768
+ } else {
3769
+ r.push(movename + ":=" + os.moveops[i].toPerm().toGap() + ";");
3770
+ }
3771
+ }
3772
+ r.push("Gen:=[");
3773
+ r.push(mvs.join(","));
3774
+ r.push("];");
3775
+ const ip = os.solved.identicalPieces();
3776
+ r.push(
3777
+ "ip:=[" + ip.map((_) => "[" + _.map((__) => __ + 1).join(",") + "]").join(",") + "];"
3778
+ );
3779
+ r.push("# Size(Group(Gen));");
3780
+ r.push("# Size(Stabilizer(Group(Gen), ip, OnTuplesSets));");
3781
+ r.push("");
3782
+ return this.header("# ") + r.join("\n");
3783
+ }
3784
+ writeksolve(name = "PuzzleGeometryPuzzle") {
3785
+ const od = this.getOrbitsDef(false);
3786
+ return this.header("# ") + od.toKsolve(name, this.notationMapper).join("\n");
3787
+ }
3788
+ getKPuzzleDefinition(fortwisty = true, includemoves = true) {
3789
+ const od = this.getOrbitsDef(fortwisty, includemoves);
3790
+ const internalDefinition = od.toKPuzzleDefinition(includemoves);
3791
+ internalDefinition.experimentalPuzzleDescription = this.puzzleDescription;
3792
+ if (!internalDefinition) {
3793
+ throw new Error("Missing definition!");
3794
+ }
3795
+ return internalDefinition;
3796
+ }
3797
+ getMoveFromBits(moverange, amount, inverted, axiscmoves, setmoves, movesetorder) {
3798
+ const moveorbits = [];
3799
+ const perms = [];
3800
+ const oris = [];
3801
+ for (const len of this.cubieords) {
3802
+ perms.push(iota(len));
3803
+ oris.push(zeros(len));
3804
+ }
3805
+ for (let m = moverange[0]; m <= moverange[1]; m++) {
3806
+ const slicecmoves = axiscmoves[m];
3807
+ for (let j = 0; j < slicecmoves.length; j += 2 * movesetorder) {
3808
+ const mperm = slicecmoves.slice(j, j + 2 * movesetorder);
3809
+ const setnum = this.cubiesetnums[mperm[0]];
3810
+ for (let ii = 0; ii < mperm.length; ii += 2) {
3811
+ mperm[ii] = this.cubieordnums[mperm[ii]];
3812
+ }
3813
+ let inc = 2;
3814
+ let oinc = 3;
3815
+ if (inverted) {
3816
+ inc = mperm.length - 2;
3817
+ oinc = mperm.length - 1;
3818
+ }
3819
+ if (perms[setnum] === iota(this.cubieords[setnum])) {
3820
+ perms[setnum] = perms[setnum].slice();
3821
+ if (this.orbitoris[setnum] > 1 && !this.options.fixedOrientation) {
3822
+ oris[setnum] = oris[setnum].slice();
3823
+ }
3824
+ }
3825
+ for (let ii = 0; ii < mperm.length; ii += 2) {
3826
+ perms[setnum][mperm[(ii + inc) % mperm.length]] = mperm[ii];
3827
+ if (this.orbitoris[setnum] > 1 && !this.options.fixedOrientation) {
3828
+ oris[setnum][mperm[ii]] = (mperm[(ii + oinc) % mperm.length] - mperm[(ii + 1) % mperm.length] + 2 * this.orbitoris[setnum]) % this.orbitoris[setnum];
3829
+ }
3830
+ }
3831
+ }
3832
+ }
3833
+ let lastId = new PGOrbit(iota(24), zeros(24), 1);
3834
+ for (let ii = 0; ii < this.cubiesetnames.length; ii++) {
3835
+ if (setmoves && !setmoves[ii]) {
3836
+ continue;
3837
+ }
3838
+ if (this.orbitoris[ii] === 1 || this.options.fixedOrientation) {
3839
+ if (perms[ii] === iota(lastId.perm.length)) {
3840
+ if (perms[ii] !== lastId.perm) {
3841
+ lastId = new PGOrbit(perms[ii], oris[ii], 1);
3842
+ }
3843
+ moveorbits.push(lastId);
3844
+ } else {
3845
+ moveorbits.push(new PGOrbit(perms[ii], oris[ii], 1));
3846
+ }
3847
+ } else {
3848
+ const no = new Array(oris[ii].length);
3849
+ for (let jj = 0; jj < perms[ii].length; jj++) {
3850
+ no[jj] = oris[ii][perms[ii][jj]];
3851
+ }
3852
+ moveorbits.push(new PGOrbit(perms[ii], no, this.orbitoris[ii]));
3853
+ }
3854
+ }
3855
+ let mv = new PGTransform(moveorbits);
3856
+ if (amount !== 1) {
3857
+ mv = mv.mulScalar(amount);
3858
+ }
3859
+ return mv;
3860
+ }
3861
+ omitSet(name) {
3862
+ for (const excludedSet of this.options.excludeOrbits) {
3863
+ if (excludedSet === name) {
3864
+ return true;
3865
+ }
3866
+ }
3867
+ return false;
3868
+ }
3869
+ diffmvsets(a, b, slices, neg) {
3870
+ for (let i = 0; i < a.length; i += 2) {
3871
+ let found = false;
3872
+ for (let j = 0; !found && j < b.length; j += 2) {
3873
+ if (neg) {
3874
+ if (a[i][0] + b[j][1] === slices && a[i][1] + b[j][0] === slices && a[i + 1] === b[j + 1]) {
3875
+ found = true;
3876
+ }
3877
+ } else {
3878
+ if (a[i][0] === b[j][0] && a[i][1] === b[j][1] && a[i + 1] === b[j + 1]) {
3879
+ found = true;
3880
+ }
3881
+ }
3882
+ }
3883
+ if (!found) {
3884
+ return true;
3885
+ }
3886
+ }
3887
+ return false;
3888
+ }
3889
+ getOrbitsDef(fortwisty, includemoves = true) {
3890
+ const setmoves = [];
3891
+ if (fortwisty) {
3892
+ for (let i = 0; i < this.cubiesetnames.length; i++) {
3893
+ setmoves.push(1);
3894
+ }
3895
+ }
3896
+ const setnames = [];
3897
+ const setdefs = [];
3898
+ const mps = [];
3899
+ const addrot = [];
3900
+ for (let k = 0; k < this.moveplanesets.length; k++) {
3901
+ const moveset = this.getmovesets(k);
3902
+ mps.push(moveset);
3903
+ if (this.options.addRotations) {
3904
+ addrot.push(1);
3905
+ } else {
3906
+ addrot.push(0);
3907
+ }
3908
+ }
3909
+ const hasrotation = [];
3910
+ for (let k = 0; k < this.moveplanesets.length; k++) {
3911
+ const slices = this.moveplanesets[k].length;
3912
+ let sawone = false;
3913
+ const moveset = mps[k];
3914
+ for (let i = 0; i < moveset.length; i += 2) {
3915
+ if (moveset[i][0] === 0 && moveset[i][1] === slices) {
3916
+ sawone = true;
3917
+ }
3918
+ }
3919
+ hasrotation[k] = sawone;
3920
+ }
3921
+ if (this.options.moveList && this.options.addRotations) {
3922
+ for (let i = 0; i < this.moverotations.length; i++) {
3923
+ addrot[i] = 0;
3924
+ }
3925
+ for (let k = 0; k < this.moveplanesets.length; k++) {
3926
+ if (hasrotation[k]) {
3927
+ addrot[k] = 3;
3928
+ continue;
3929
+ }
3930
+ for (let i = 0; i < this.moverotations.length; i++) {
3931
+ let nn = this.moveplanenormals[k];
3932
+ for (let ii = 1; ii * 2 <= this.movesetorders[i]; ii++) {
3933
+ nn = nn.rotatepoint(this.moverotations[i][0]);
3934
+ if (addrot[i] & ii) {
3935
+ continue;
3936
+ }
3937
+ let found = -1;
3938
+ let neg = false;
3939
+ for (let j = 0; j < this.moveplanenormals.length; j++) {
3940
+ if (nn.dist(this.moveplanenormals[j]) < eps3) {
3941
+ found = j;
3942
+ break;
3943
+ } else if (nn.dist(this.moveplanenormals[j].smul(-1)) < eps3) {
3944
+ found = j;
3945
+ neg = true;
3946
+ break;
3947
+ }
3948
+ }
3949
+ if (found < 0) {
3950
+ throw new Error("Could not find rotation");
3951
+ }
3952
+ const cmp = mps[found];
3953
+ if (cmp.length !== mps[k].length || this.moveplanesets[k].length !== this.moveplanesets[found].length || this.diffmvsets(
3954
+ cmp,
3955
+ mps[k],
3956
+ this.moveplanesets[found].length,
3957
+ neg
3958
+ )) {
3959
+ addrot[i] |= ii;
3960
+ }
3961
+ }
3962
+ }
3963
+ }
3964
+ for (let i = 0; i < this.moverotations.length; i++) {
3965
+ if (addrot[i] === 0) {
3966
+ addrot[i] = 1;
3967
+ } else if (addrot[i] === 1) {
3968
+ if (this.movesetorders[i] > 3) {
3969
+ addrot[i] = 2;
3970
+ } else {
3971
+ addrot[i] = 0;
3972
+ }
3973
+ } else if (addrot[i] === 3) {
3974
+ addrot[i] = 0;
3975
+ } else {
3976
+ throw new Error("Impossible addrot val");
3977
+ }
3978
+ }
3979
+ }
3980
+ for (let k = 0; k < this.moveplanesets.length; k++) {
3981
+ if (addrot[k] !== 0 && !hasrotation[k]) {
3982
+ mps[k].push([0, this.moveplanesets[k].length]);
3983
+ mps[k].push(addrot[k]);
3984
+ }
3985
+ }
3986
+ for (let k = 0; k < this.moveplanesets.length; k++) {
3987
+ const moveset = mps[k];
3988
+ const movesetorder = this.movesetorders[k];
3989
+ for (let i = 0; i < moveset.length; i += 2) {
3990
+ for (let j = 0; j < i; j += 2) {
3991
+ if (moveset[i][0] === moveset[j][0] && moveset[i][1] === moveset[j][1]) {
3992
+ throw new Error("Redundant moves in moveset.");
3993
+ }
3994
+ }
3995
+ }
3996
+ const allbits = [];
3997
+ for (let i = 0; i < moveset.length; i += 2) {
3998
+ for (let j = moveset[i][0]; j <= moveset[i][1]; j++) {
3999
+ allbits[j] = 1;
4000
+ }
4001
+ }
4002
+ const axiscmoves = this.cmovesbyslice[k];
4003
+ for (let i = 0; i < axiscmoves.length; i++) {
4004
+ if (allbits[i] !== 1) {
4005
+ continue;
4006
+ }
4007
+ const slicecmoves = axiscmoves[i];
4008
+ for (let j = 0; j < slicecmoves.length; j += 2 * movesetorder) {
4009
+ if (this.skipcubie(slicecmoves[j])) {
4010
+ continue;
4011
+ }
4012
+ const ind = this.cubiesetnums[slicecmoves[j]];
4013
+ setmoves[ind] = 1;
4014
+ }
4015
+ }
4016
+ }
4017
+ for (let i = 0; i < this.cubiesetnames.length; i++) {
4018
+ if (!setmoves[i]) {
4019
+ continue;
4020
+ }
4021
+ if (this.omitSet(this.cubiesetnames[i])) {
4022
+ setmoves[i] = 0;
4023
+ continue;
4024
+ }
4025
+ setnames.push(this.cubiesetnames[i]);
4026
+ setdefs.push(
4027
+ new PGOrbitDef(
4028
+ this.cubieords[i],
4029
+ this.options.fixedOrientation ? 1 : this.orbitoris[i]
4030
+ )
4031
+ );
4032
+ }
4033
+ const solved = [];
4034
+ for (let i = 0; i < this.cubiesetnames.length; i++) {
4035
+ if (!setmoves[i]) {
4036
+ continue;
4037
+ }
4038
+ if (this.omitSet(this.cubiesetnames[i])) {
4039
+ continue;
4040
+ }
4041
+ const p = [];
4042
+ const o = [];
4043
+ for (let j = 0; j < this.cubieords[i]; j++) {
4044
+ if (fortwisty) {
4045
+ p.push(j);
4046
+ } else {
4047
+ const cubie = this.cubiesetcubies[i][j];
4048
+ p.push(this.cubievaluemap[cubie]);
4049
+ }
4050
+ o.push(0);
4051
+ }
4052
+ solved.push(
4053
+ new PGOrbit(
4054
+ p,
4055
+ o,
4056
+ this.options.fixedOrientation ? 1 : this.orbitoris[i]
4057
+ )
4058
+ );
4059
+ }
4060
+ const movenames = [];
4061
+ const forcenames = [];
4062
+ const moves = [];
4063
+ const isrots = [];
4064
+ if (includemoves) {
4065
+ for (let k = 0; k < this.moveplanesets.length; k++) {
4066
+ const moveplaneset = this.moveplanesets[k];
4067
+ const slices = moveplaneset.length;
4068
+ const moveset = mps[k];
4069
+ const movesetgeo = this.movesetgeos[k];
4070
+ for (let i = 0; i < moveset.length; i += 2) {
4071
+ const movebits = moveset[i];
4072
+ let nameoverride;
4073
+ let inverted = false;
4074
+ if (this.parsedmovelist !== void 0) {
4075
+ for (const parsedmove of this.parsedmovelist) {
4076
+ if (parsedmove[1] !== k) {
4077
+ continue;
4078
+ }
4079
+ let r2 = [];
4080
+ if (parsedmove[4]) {
4081
+ r2 = [parsedmove[2], parsedmove[3]];
4082
+ } else {
4083
+ r2 = [slices - parsedmove[3], slices - parsedmove[2]];
4084
+ }
4085
+ if (r2[0] === movebits[0] && r2[1] === movebits[1]) {
4086
+ nameoverride = parsedmove[0];
4087
+ inverted = !parsedmove[4];
4088
+ }
4089
+ }
4090
+ }
4091
+ if (nameoverride) {
4092
+ movenames.push(nameoverride);
4093
+ forcenames.push(true);
4094
+ } else {
4095
+ const mna = getmovename(movesetgeo, movebits, slices);
4096
+ inverted = mna[1];
4097
+ const movename = mna[0];
4098
+ if (moveset[i + 1] === 1) {
4099
+ movenames.push(movename);
4100
+ } else {
4101
+ movenames.push(movename + moveset[i + 1]);
4102
+ }
4103
+ forcenames.push(false);
4104
+ }
4105
+ isrots.push(movebits[0] === 0 && movebits[1] === slices);
4106
+ const mv = this.getMoveFromBits(
4107
+ movebits,
4108
+ moveset[i + 1],
4109
+ inverted,
4110
+ this.cmovesbyslice[k],
4111
+ setmoves,
4112
+ this.movesetorders[k]
4113
+ );
4114
+ moves.push(mv);
4115
+ }
4116
+ }
4117
+ }
4118
+ let r = new PGOrbitsDef(
4119
+ setnames,
4120
+ setdefs,
4121
+ new VisibleState(solved),
4122
+ movenames,
4123
+ moves,
4124
+ isrots,
4125
+ forcenames
4126
+ );
4127
+ if (this.options.optimizeOrbits) {
4128
+ r = r.optimize();
4129
+ }
4130
+ if (this.options.scrambleAmount !== 0) {
4131
+ r.scramble(this.options.scrambleAmount);
4132
+ }
4133
+ return r;
4134
+ }
4135
+ getScramble(n = 0) {
4136
+ const od = this.getOrbitsDef(false);
4137
+ return od.transformToKTransformationData(od.getScrambleTransformation(n));
4138
+ }
4139
+ getMovesAsPerms() {
4140
+ return this.getOrbitsDef(false).moveops.map((_) => _.toPerm());
4141
+ }
4142
+ showcanon(disp) {
4143
+ showcanon(this.getOrbitsDef(false), disp);
4144
+ }
4145
+ getsolved() {
4146
+ const r = [];
4147
+ for (let i = 0; i < this.baseFaceCount; i++) {
4148
+ for (let j = 0; j < this.stickersperface; j++) {
4149
+ r.push(i);
4150
+ }
4151
+ }
4152
+ return new Perm(r);
4153
+ }
4154
+ getOrientationRotation(desiredRotation) {
4155
+ const [feature1name, [x1, y1, z1]] = desiredRotation[0];
4156
+ const direction1 = new Quat(0, x1, -y1, z1);
4157
+ const [feature2name, [x2, y2, z2]] = desiredRotation[1];
4158
+ const direction2 = new Quat(0, x2, -y2, z2);
4159
+ let feature1 = null;
4160
+ let feature2 = null;
4161
+ const feature1geoname = this.swizzler.unswizzle(feature1name);
4162
+ const feature2geoname = this.swizzler.unswizzle(feature2name);
4163
+ for (const gn of this.geonormals) {
4164
+ if (feature1geoname === gn[1]) {
4165
+ feature1 = gn[0];
4166
+ }
4167
+ if (feature2geoname === gn[1]) {
4168
+ feature2 = gn[0];
4169
+ }
4170
+ }
4171
+ if (!feature1) {
4172
+ throw new Error("Could not find feature " + feature1name);
4173
+ }
4174
+ if (!feature2) {
4175
+ throw new Error("Could not find feature " + feature2name);
4176
+ }
4177
+ const r1 = feature1.pointrotation(direction1);
4178
+ const feature2rot = feature2.rotatepoint(r1);
4179
+ const r2 = feature2rot.unproject(direction1).pointrotation(direction2.unproject(direction1));
4180
+ return r2.mul(r1);
4181
+ }
4182
+ getInitial3DRotation() {
4183
+ const basefacecount = this.baseFaceCount;
4184
+ let orientationDescription = null;
4185
+ if (this.options.puzzleOrientation) {
4186
+ orientationDescription = this.options.puzzleOrientation;
4187
+ } else if (this.options.puzzleOrientations) {
4188
+ orientationDescription = this.options.puzzleOrientations[basefacecount];
4189
+ }
4190
+ if (!orientationDescription) {
4191
+ orientationDescription = defaultOrientations()[basefacecount];
4192
+ }
4193
+ if (!orientationDescription) {
4194
+ throw new Error("No default orientation?");
4195
+ }
4196
+ return this.getOrientationRotation(orientationDescription);
4197
+ }
4198
+ generate2dmapping(w = 800, h = 500, trim = 10, threed = false, twodshrink = 0.92) {
4199
+ w -= 2 * trim;
4200
+ h -= 2 * trim;
4201
+ function extendedges(a, n) {
4202
+ let dx = a[1][0] - a[0][0];
4203
+ let dy = a[1][1] - a[0][1];
4204
+ const ang = 2 * Math.PI / n;
4205
+ const cosa = Math.cos(ang);
4206
+ const sina = Math.sin(ang);
4207
+ for (let i = 2; i < n; i++) {
4208
+ const ndx = dx * cosa + dy * sina;
4209
+ dy = dy * cosa - dx * sina;
4210
+ dx = ndx;
4211
+ a.push([a[i - 1][0] + dx, a[i - 1][1] + dy]);
4212
+ }
4213
+ }
4214
+ this.genperms();
4215
+ const boundarygeo = this.getboundarygeometry();
4216
+ const face0 = boundarygeo.facenames[0][0];
4217
+ const polyn = face0.length;
4218
+ const net = this.net;
4219
+ if (net === null) {
4220
+ throw new Error("No net?");
4221
+ }
4222
+ const edges = {};
4223
+ let minx = 0;
4224
+ let miny = 0;
4225
+ let maxx = 1;
4226
+ let maxy = 0;
4227
+ edges[net[0][0]] = [
4228
+ [1, 0],
4229
+ [0, 0]
4230
+ ];
4231
+ extendedges(edges[net[0][0]], polyn);
4232
+ for (const neti of net) {
4233
+ const f0 = neti[0];
4234
+ if (!edges[f0]) {
4235
+ throw new Error("Bad edge description; first edge not connected.");
4236
+ }
4237
+ for (let j = 1; j < neti.length; j++) {
4238
+ const f1 = neti[j];
4239
+ if (f1 === "" || edges[f1]) {
4240
+ continue;
4241
+ }
4242
+ edges[f1] = [edges[f0][j % polyn], edges[f0][(j + polyn - 1) % polyn]];
4243
+ extendedges(edges[f1], polyn);
4244
+ }
4245
+ }
4246
+ for (const f in edges) {
4247
+ const es = edges[f];
4248
+ for (const esi of es) {
4249
+ minx = Math.min(minx, esi[0]);
4250
+ maxx = Math.max(maxx, esi[0]);
4251
+ miny = Math.min(miny, esi[1]);
4252
+ maxy = Math.max(maxy, esi[1]);
4253
+ }
4254
+ }
4255
+ const sc = Math.min(w / (maxx - minx), h / (maxy - miny));
4256
+ const xoff = 0.5 * (w - sc * (maxx + minx));
4257
+ const yoff = 0.5 * (h - sc * (maxy + miny));
4258
+ const geos = {};
4259
+ const bg = this.getboundarygeometry();
4260
+ const edges2 = {};
4261
+ const initv = [
4262
+ [sc + xoff, yoff],
4263
+ [xoff, yoff]
4264
+ ];
4265
+ edges2[net[0][0]] = initv;
4266
+ extendedges(edges2[net[0][0]], polyn);
4267
+ geos[this.facenames[0][1]] = this.project2d(0, 0, [
4268
+ new Quat(0, initv[0][0], initv[0][1], 0),
4269
+ new Quat(0, initv[1][0], initv[1][1], 0)
4270
+ ]);
4271
+ const connectat = [];
4272
+ connectat[0] = 0;
4273
+ for (const neti of net) {
4274
+ const f0 = neti[0];
4275
+ if (!edges2[f0]) {
4276
+ throw new Error("Bad edge description; first edge not connected.");
4277
+ }
4278
+ let gfi = -1;
4279
+ for (let j = 0; j < bg.facenames.length; j++) {
4280
+ if (f0 === bg.facenames[j][1]) {
4281
+ gfi = j;
4282
+ break;
4283
+ }
4284
+ }
4285
+ if (gfi < 0) {
4286
+ throw new Error("Could not find first face name " + f0);
4287
+ }
4288
+ const thisface = bg.facenames[gfi][0];
4289
+ for (let j = 1; j < neti.length; j++) {
4290
+ const f1 = neti[j];
4291
+ if (f1 === "" || edges2[f1]) {
4292
+ continue;
4293
+ }
4294
+ edges2[f1] = [
4295
+ edges2[f0][j % polyn],
4296
+ edges2[f0][(j + polyn - 1) % polyn]
4297
+ ];
4298
+ extendedges(edges2[f1], polyn);
4299
+ const caf0 = connectat[gfi];
4300
+ const mp = thisface[(caf0 + j) % polyn].sum(thisface[(caf0 + j + polyn - 1) % polyn]).smul(0.5);
4301
+ const epi = findelement(bg.edgenames, mp);
4302
+ const edgename = bg.edgenames[epi][1];
4303
+ const el = splitByFaceNames(edgename, this.facenames);
4304
+ const gf1 = el[f0 === el[0] ? 1 : 0];
4305
+ let gf1i = -1;
4306
+ for (let k = 0; k < bg.facenames.length; k++) {
4307
+ if (gf1 === bg.facenames[k][1]) {
4308
+ gf1i = k;
4309
+ break;
4310
+ }
4311
+ }
4312
+ if (gf1i < 0) {
4313
+ throw new Error("Could not find second face name");
4314
+ }
4315
+ const otherface = bg.facenames[gf1i][0];
4316
+ for (let k = 0; k < otherface.length; k++) {
4317
+ const mp2 = otherface[k].sum(otherface[(k + 1) % polyn]).smul(0.5);
4318
+ if (mp2.dist(mp) <= eps3) {
4319
+ const p1 = edges2[f0][(j + polyn - 1) % polyn];
4320
+ const p2 = edges2[f0][j % polyn];
4321
+ connectat[gf1i] = k;
4322
+ geos[gf1] = this.project2d(gf1i, k, [
4323
+ new Quat(0, p2[0], p2[1], 0),
4324
+ new Quat(0, p1[0], p1[1], 0)
4325
+ ]);
4326
+ break;
4327
+ }
4328
+ }
4329
+ }
4330
+ }
4331
+ let hix = 0;
4332
+ let hiy = 0;
4333
+ const rot = this.getInitial3DRotation();
4334
+ for (let face of this.faces) {
4335
+ if (threed) {
4336
+ face = face.rotate(rot);
4337
+ }
4338
+ for (let j = 0; j < face.length; j++) {
4339
+ hix = Math.max(hix, Math.abs(face.get(j).b));
4340
+ hiy = Math.max(hiy, Math.abs(face.get(j).c));
4341
+ }
4342
+ }
4343
+ const sc2 = Math.min(h / hiy / 2, (w - trim) / hix / 4);
4344
+ const mappt2d = (fn, q) => {
4345
+ if (threed) {
4346
+ q = q.rotatepoint(rot);
4347
+ const xoff2 = 0.5 * trim + 0.25 * w;
4348
+ const xmul = this.baseplanes[fn].rotateplane(rot).d < 0 ? 1 : -1;
4349
+ return [
4350
+ trim + w * 0.5 + xmul * (xoff2 - q.b * sc2),
4351
+ trim + h * 0.5 + q.c * sc2
4352
+ ];
4353
+ } else {
4354
+ const g = geos[this.facenames[fn][1]];
4355
+ return [
4356
+ trim + twodshrink * q.dot(g[0]) + g[2].b,
4357
+ trim + h - twodshrink * q.dot(g[1]) - g[2].c
4358
+ ];
4359
+ }
4360
+ };
4361
+ return mappt2d;
4362
+ }
4363
+ generatesvg(w = 800, h = 500, trim = 10, threed = false) {
4364
+ const mappt2d = this.generate2dmapping(w, h, trim, threed);
4365
+ function drawedges(id, pts, color) {
4366
+ return '<polygon id="' + id + '" class="sticker" style="fill: ' + color + '" points="' + pts.map((p) => p[0] + " " + p[1]).join(" ") + '"/>\n';
4367
+ }
4368
+ const pos = this.getsolved();
4369
+ const colormap = [];
4370
+ const facegeo = [];
4371
+ for (let i = 0; i < this.baseFaceCount; i++) {
4372
+ colormap[i] = this.colors[this.facenames[i][1]];
4373
+ }
4374
+ for (let i = 0; i < this.faces.length; i++) {
4375
+ const face = this.faces[i];
4376
+ const facenum = Math.floor(i / this.stickersperface);
4377
+ const fg = [];
4378
+ for (let j = 0; j < face.length; j++) {
4379
+ fg.push(mappt2d(facenum, face.get(j)));
4380
+ }
4381
+ facegeo.push(fg);
4382
+ }
4383
+ const svg = [];
4384
+ for (let j = 0; j < this.baseFaceCount; j++) {
4385
+ svg.push("<g>");
4386
+ svg.push("<title>" + this.facenames[j][1] + "</title>\n");
4387
+ for (let ii = 0; ii < this.stickersperface; ii++) {
4388
+ const i = j * this.stickersperface + ii;
4389
+ const cubie = this.facetocubie[i];
4390
+ const cubieori = this.facetoord[i];
4391
+ const cubiesetnum = this.cubiesetnums[cubie];
4392
+ const cubieord = this.cubieordnums[cubie];
4393
+ const color = this.graybyori(cubie) ? "#808080" : colormap[pos.p[i]];
4394
+ let id = this.cubiesetnames[cubiesetnum] + "-l" + cubieord + "-o" + cubieori;
4395
+ svg.push(drawedges(id, facegeo[i], color));
4396
+ if (this.duplicatedFaces[i]) {
4397
+ for (let jj = 1; jj < this.duplicatedFaces[i]; jj++) {
4398
+ id = this.cubiesetnames[cubiesetnum] + "-l" + cubieord + "-o" + jj;
4399
+ svg.push(drawedges(id, facegeo[i], color));
4400
+ }
4401
+ }
4402
+ }
4403
+ svg.push("</g>");
4404
+ }
4405
+ const html = '<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800 500">\n<style type="text/css"><![CDATA[.sticker { stroke: #000000; stroke-width: 1px; }]]></style>\n' + svg.join("") + "</svg>";
4406
+ return html;
4407
+ }
4408
+ get3d(options) {
4409
+ const stickers = [];
4410
+ const rot = this.getInitial3DRotation();
4411
+ const faces = [];
4412
+ const maxdist = 0.52 * this.basefaces[0].get(0).len();
4413
+ for (let i = 0; i < this.basefaces.length; i++) {
4414
+ const coords = this.basefaces[i].rotate(rot);
4415
+ const name = this.facenames[i][1];
4416
+ faces.push({ coords: toFaceCoords(coords, maxdist), name });
4417
+ }
4418
+ for (let i = 0; i < this.faces.length; i++) {
4419
+ const facenum = Math.floor(i / this.stickersperface);
4420
+ const cubie = this.facetocubie[i];
4421
+ const cubieori = this.facetoord[i];
4422
+ const cubiesetnum = this.cubiesetnums[cubie];
4423
+ const cubieord = this.cubieordnums[cubie];
4424
+ let color = this.graybyori(cubie) ? "#808080" : this.colors[this.facenames[facenum][1]];
4425
+ if (options?.stickerColors) {
4426
+ color = options.stickerColors[i];
4427
+ }
4428
+ const coords = this.faces[i].rotate(rot);
4429
+ stickers.push({
4430
+ coords: toFaceCoords(coords, maxdist),
4431
+ color,
4432
+ orbit: this.cubiesetnames[cubiesetnum],
4433
+ ord: cubieord,
4434
+ ori: cubieori,
4435
+ face: facenum
4436
+ });
4437
+ let fcoords = coords;
4438
+ if (this.duplicatedFaces[i]) {
4439
+ const rotdist = fcoords.length / this.duplicatedFaces[i];
4440
+ for (let jj = 1; jj < this.duplicatedFaces[i]; jj++) {
4441
+ for (let k = 0; k < rotdist; k++) {
4442
+ fcoords = fcoords.rotateforward();
4443
+ }
4444
+ stickers.push({
4445
+ coords: toFaceCoords(fcoords, maxdist),
4446
+ color,
4447
+ orbit: this.cubiesetnames[cubiesetnum],
4448
+ ord: cubieord,
4449
+ ori: jj,
4450
+ face: facenum,
4451
+ isDup: true
4452
+ });
4453
+ }
4454
+ }
4455
+ }
4456
+ const grips = [];
4457
+ for (let i = 0; i < this.movesetgeos.length; i++) {
4458
+ const msg = this.movesetgeos[i];
4459
+ const order = this.movesetorders[i];
4460
+ for (const gn of this.geonormals) {
4461
+ if (msg[0] === gn[1] && msg[1] === gn[2]) {
4462
+ grips.push({
4463
+ coordinates: toCoords(gn[0].rotatepoint(rot), 1),
4464
+ quantumMove: new Move(msg[0]),
4465
+ order
4466
+ });
4467
+ grips.push({
4468
+ coordinates: toCoords(gn[0].rotatepoint(rot).smul(-1), 1),
4469
+ quantumMove: new Move(msg[2]),
4470
+ order
4471
+ });
4472
+ }
4473
+ }
4474
+ }
4475
+ const twodmapper = this.generate2dmapping(2880, 2160, 0, false, 1);
4476
+ const g = function() {
4477
+ const irot = rot.invrot();
4478
+ return function(facenum, coords) {
4479
+ let q = new Quat(
4480
+ 0,
4481
+ coords[0] * maxdist,
4482
+ -coords[1] * maxdist,
4483
+ coords[2] * maxdist
4484
+ );
4485
+ q = q.rotatepoint(irot);
4486
+ const x = twodmapper(facenum, q);
4487
+ x[0] /= 2880;
4488
+ x[1] = 1 - x[1] / 2160;
4489
+ return x;
4490
+ };
4491
+ }().bind(this);
4492
+ return {
4493
+ stickers,
4494
+ faces,
4495
+ axis: grips,
4496
+ unswizzle: this.unswizzle.bind(this),
4497
+ notationMapper: this.notationMapper,
4498
+ textureMapper: { getuv: g }
4499
+ };
4500
+ }
4501
+ getGeoNormal(geoname) {
4502
+ const rot = this.getInitial3DRotation();
4503
+ const grip = this.swizzler.unswizzle(geoname);
4504
+ for (const gn of this.geonormals) {
4505
+ if (grip === gn[1]) {
4506
+ const r = toCoords(gn[0].rotatepoint(rot), 1);
4507
+ if (Math.abs(r[0]) < eps3 && Math.abs(r[2]) < eps3) {
4508
+ r[0] = 0;
4509
+ r[2] = 1e-6;
4510
+ }
4511
+ return r;
4512
+ }
4513
+ }
4514
+ return void 0;
4515
+ }
4516
+ getfaceindex(facenum) {
4517
+ const divid = this.stickersperface;
4518
+ return Math.floor(facenum / divid);
4519
+ }
4520
+ textForTwizzleExplorer() {
4521
+ return `Faces ${this.baseplanerot.length}
4522
+ Stickers per face ${this.stickersperface}
4523
+ Short edge ${this.shortedge}
4524
+ Cubies ${this.cubies.length}
4525
+ Edge distance ${this.edgedistance}
4526
+ Vertex distance ${this.vertexdistance}`;
4527
+ }
4528
+ writeSchreierSims(tw) {
4529
+ const os = this.getOrbitsDef(false);
4530
+ const as = os.reassemblySize();
4531
+ tw(`Reassembly size is ${as}`);
4532
+ const ss = schreierSims(this.getMovesAsPerms(), tw);
4533
+ const r = as / ss;
4534
+ tw(`Ratio is ${r}`);
4535
+ }
4536
+ };
4537
+ var PGNotation = class {
4538
+ constructor(pg, od) {
4539
+ this.pg = pg;
4540
+ this.orbitNames = od.orbitnames;
4541
+ }
4542
+ lookupMove(move) {
4543
+ const mv = this.pg.parseMove(move);
4544
+ if (this.pg.parsedmovelist) {
4545
+ let found = false;
4546
+ for (const parsedmove of this.pg.parsedmovelist) {
4547
+ if (parsedmove[1] === mv[1] && parsedmove[2] === mv[2] && parsedmove[3] === mv[3] && parsedmove[4] === mv[4]) {
4548
+ found = true;
4549
+ }
4550
+ }
4551
+ if (!found) {
4552
+ return null;
4553
+ }
4554
+ }
4555
+ let bits = [mv[2], mv[3]];
4556
+ if (!mv[4]) {
4557
+ const slices = this.pg.moveplanesets[mv[1]].length;
4558
+ bits = [slices - mv[3], slices - mv[2]];
4559
+ }
4560
+ const pgmv = this.pg.getMoveFromBits(
4561
+ bits,
4562
+ mv[5],
4563
+ !mv[4],
4564
+ this.pg.cmovesbyslice[mv[1]],
4565
+ void 0,
4566
+ this.pg.movesetorders[mv[1]]
4567
+ );
4568
+ const r = PGOrbitsDef.transformToKTransformationData(this.orbitNames, pgmv);
4569
+ return r;
4570
+ }
4571
+ };
17
4572
  export {
18
4573
  PUZZLE_BASE_SHAPES as EXPERIMENTAL_PUZZLE_BASE_SHAPES,
19
4574
  PUZZLE_CUT_TYPES as EXPERIMENTAL_PUZZLE_CUT_TYPES,