cubegin 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +674 -0
  3. package/NOTICE +11 -0
  4. package/README.md +49 -0
  5. package/dist/scramble-core/src/batch.mjs +18 -0
  6. package/dist/scramble-core/src/generator.d.mts +35 -0
  7. package/dist/scramble-core/src/generator.mjs +136 -0
  8. package/dist/scramble-core/src/generators/clock.d.mts +11 -0
  9. package/dist/scramble-core/src/generators/clock.mjs +32 -0
  10. package/dist/scramble-core/src/generators/cube-random-turns.d.mts +11 -0
  11. package/dist/scramble-core/src/generators/cube-random-turns.mjs +54 -0
  12. package/dist/scramble-core/src/generators/four-by-four.d.mts +14 -0
  13. package/dist/scramble-core/src/generators/four-by-four.mjs +43 -0
  14. package/dist/scramble-core/src/generators/megaminx.d.mts +11 -0
  15. package/dist/scramble-core/src/generators/megaminx.mjs +18 -0
  16. package/dist/scramble-core/src/generators/pyraminx.d.mts +11 -0
  17. package/dist/scramble-core/src/generators/pyraminx.mjs +17 -0
  18. package/dist/scramble-core/src/generators/skewb.d.mts +11 -0
  19. package/dist/scramble-core/src/generators/skewb.mjs +17 -0
  20. package/dist/scramble-core/src/generators/square1.d.mts +11 -0
  21. package/dist/scramble-core/src/generators/square1.mjs +28 -0
  22. package/dist/scramble-core/src/generators/three-by-three.d.mts +25 -0
  23. package/dist/scramble-core/src/generators/three-by-three.mjs +85 -0
  24. package/dist/scramble-core/src/generators/two-by-two.d.mts +11 -0
  25. package/dist/scramble-core/src/generators/two-by-two.mjs +17 -0
  26. package/dist/scramble-core/src/random-source.d.mts +7 -0
  27. package/dist/scramble-core/src/random-source.mjs +8 -0
  28. package/dist/scramble-core/src/solvers/min2phase/coord-cube.mjs +10 -0
  29. package/dist/scramble-core/src/solvers/min2phase/cubie-cube.mjs +246 -0
  30. package/dist/scramble-core/src/solvers/min2phase/engine.mjs +1281 -0
  31. package/dist/scramble-core/src/solvers/min2phase/search-wca.mjs +21 -0
  32. package/dist/scramble-core/src/solvers/min2phase/search.mjs +25 -0
  33. package/dist/scramble-core/src/solvers/min2phase/tools.mjs +169 -0
  34. package/dist/scramble-core/src/solvers/min2phase/util.mjs +30 -0
  35. package/dist/scramble-core/src/solvers/pyraminx-solver.d.mts +17 -0
  36. package/dist/scramble-core/src/solvers/pyraminx-solver.mjs +350 -0
  37. package/dist/scramble-core/src/solvers/skewb-solver.d.mts +15 -0
  38. package/dist/scramble-core/src/solvers/skewb-solver.mjs +399 -0
  39. package/dist/scramble-core/src/solvers/sq12phase/full-cube.mjs +212 -0
  40. package/dist/scramble-core/src/solvers/sq12phase/search.mjs +520 -0
  41. package/dist/scramble-core/src/solvers/sq12phase/shape.mjs +214 -0
  42. package/dist/scramble-core/src/solvers/sq12phase/square.mjs +135 -0
  43. package/dist/scramble-core/src/solvers/threephase/center.mjs +798 -0
  44. package/dist/scramble-core/src/solvers/threephase/edge.mjs +632 -0
  45. package/dist/scramble-core/src/solvers/threephase/full-cube.mjs +554 -0
  46. package/dist/scramble-core/src/solvers/threephase/search.mjs +262 -0
  47. package/dist/scramble-core/src/solvers/threephase/tables.mjs +201 -0
  48. package/dist/scramble-core/src/solvers/two-by-two-solver.d.mts +15 -0
  49. package/dist/scramble-core/src/solvers/two-by-two-solver.mjs +298 -0
  50. package/dist/scramble-core.d.mts +15 -0
  51. package/dist/scramble-core.mjs +15 -0
  52. package/dist/scramble-image/src/color.d.mts +12 -0
  53. package/dist/scramble-image/src/color.mjs +11 -0
  54. package/dist/scramble-image/src/render.d.mts +10 -0
  55. package/dist/scramble-image/src/render.mjs +71 -0
  56. package/dist/scramble-image/src/renderers/clock.d.mts +6 -0
  57. package/dist/scramble-image/src/renderers/clock.mjs +145 -0
  58. package/dist/scramble-image/src/renderers/cube-isometric.d.mts +8 -0
  59. package/dist/scramble-image/src/renderers/cube-isometric.mjs +204 -0
  60. package/dist/scramble-image/src/renderers/cube-net.d.mts +8 -0
  61. package/dist/scramble-image/src/renderers/cube-net.mjs +52 -0
  62. package/dist/scramble-image/src/renderers/megaminx-isometric.d.mts +9 -0
  63. package/dist/scramble-image/src/renderers/megaminx-isometric.mjs +320 -0
  64. package/dist/scramble-image/src/renderers/megaminx.d.mts +9 -0
  65. package/dist/scramble-image/src/renderers/megaminx.mjs +173 -0
  66. package/dist/scramble-image/src/renderers/pyraminx-isometric.d.mts +9 -0
  67. package/dist/scramble-image/src/renderers/pyraminx-isometric.mjs +185 -0
  68. package/dist/scramble-image/src/renderers/pyraminx.d.mts +9 -0
  69. package/dist/scramble-image/src/renderers/pyraminx.mjs +111 -0
  70. package/dist/scramble-image/src/renderers/skewb-isometric.d.mts +9 -0
  71. package/dist/scramble-image/src/renderers/skewb-isometric.mjs +233 -0
  72. package/dist/scramble-image/src/renderers/skewb.d.mts +9 -0
  73. package/dist/scramble-image/src/renderers/skewb.mjs +187 -0
  74. package/dist/scramble-image/src/renderers/square1.d.mts +10 -0
  75. package/dist/scramble-image/src/renderers/square1.mjs +253 -0
  76. package/dist/scramble-image/src/svg/svg-document.d.mts +6 -0
  77. package/dist/scramble-image/src/svg/svg-document.mjs +7 -0
  78. package/dist/scramble-image/src/svg/svg-elements.d.mts +15 -0
  79. package/dist/scramble-image/src/svg/svg-elements.mjs +25 -0
  80. package/dist/scramble-image/src/svg/svg-serialize.mjs +29 -0
  81. package/dist/scramble-image.d.mts +15 -0
  82. package/dist/scramble-image.mjs +15 -0
  83. package/dist/scramble-puzzle/src/algorithm.d.mts +8 -0
  84. package/dist/scramble-puzzle/src/algorithm.mjs +16 -0
  85. package/dist/scramble-puzzle/src/algorithm2.mjs +16 -0
  86. package/dist/scramble-puzzle/src/clock/clock-definition.d.mts +8 -0
  87. package/dist/scramble-puzzle/src/clock/clock-definition.mjs +18 -0
  88. package/dist/scramble-puzzle/src/clock/clock-definition2.mjs +18 -0
  89. package/dist/scramble-puzzle/src/clock/clock-parser.d.mts +18 -0
  90. package/dist/scramble-puzzle/src/clock/clock-parser.mjs +35 -0
  91. package/dist/scramble-puzzle/src/clock/clock-parser2.mjs +35 -0
  92. package/dist/scramble-puzzle/src/clock/clock-state.d.mts +8 -0
  93. package/dist/scramble-puzzle/src/clock/clock-state.mjs +212 -0
  94. package/dist/scramble-puzzle/src/clock/clock-state2.d.mts +13 -0
  95. package/dist/scramble-puzzle/src/clock/clock-state2.mjs +212 -0
  96. package/dist/scramble-puzzle/src/cube/cube-definition.d.mts +9 -0
  97. package/dist/scramble-puzzle/src/cube/cube-definition.mjs +18 -0
  98. package/dist/scramble-puzzle/src/cube/cube-definition2.mjs +18 -0
  99. package/dist/scramble-puzzle/src/cube/cube-move.d.mts +4 -0
  100. package/dist/scramble-puzzle/src/cube/cube-move2.d.mts +17 -0
  101. package/dist/scramble-puzzle/src/cube/cube-parser.d.mts +7 -0
  102. package/dist/scramble-puzzle/src/cube/cube-parser.mjs +60 -0
  103. package/dist/scramble-puzzle/src/cube/cube-parser2.mjs +60 -0
  104. package/dist/scramble-puzzle/src/cube/cube-state.d.mts +12 -0
  105. package/dist/scramble-puzzle/src/cube/cube-state.mjs +187 -0
  106. package/dist/scramble-puzzle/src/cube/cube-state2.d.mts +15 -0
  107. package/dist/scramble-puzzle/src/cube/cube-state2.mjs +187 -0
  108. package/dist/scramble-puzzle/src/errors.d.mts +15 -0
  109. package/dist/scramble-puzzle/src/errors.mjs +24 -0
  110. package/dist/scramble-puzzle/src/errors2.mjs +30 -0
  111. package/dist/scramble-puzzle/src/events.d.mts +5 -0
  112. package/dist/scramble-puzzle/src/events.mjs +90 -0
  113. package/dist/scramble-puzzle/src/events2.d.mts +98 -0
  114. package/dist/scramble-puzzle/src/events2.mjs +109 -0
  115. package/dist/scramble-puzzle/src/index.mjs +22 -0
  116. package/dist/scramble-puzzle/src/megaminx/megaminx-definition.d.mts +8 -0
  117. package/dist/scramble-puzzle/src/megaminx/megaminx-definition.mjs +18 -0
  118. package/dist/scramble-puzzle/src/megaminx/megaminx-definition2.mjs +18 -0
  119. package/dist/scramble-puzzle/src/megaminx/megaminx-parser.d.mts +5 -0
  120. package/dist/scramble-puzzle/src/megaminx/megaminx-parser.mjs +57 -0
  121. package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.d.mts +20 -0
  122. package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.mjs +57 -0
  123. package/dist/scramble-puzzle/src/megaminx/megaminx-state.d.mts +9 -0
  124. package/dist/scramble-puzzle/src/megaminx/megaminx-state.mjs +112 -0
  125. package/dist/scramble-puzzle/src/megaminx/megaminx-state2.d.mts +14 -0
  126. package/dist/scramble-puzzle/src/megaminx/megaminx-state2.mjs +112 -0
  127. package/dist/scramble-puzzle/src/puzzle-definition.d.mts +19 -0
  128. package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.d.mts +8 -0
  129. package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.mjs +18 -0
  130. package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition2.mjs +18 -0
  131. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.d.mts +5 -0
  132. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.mjs +34 -0
  133. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.d.mts +21 -0
  134. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.mjs +34 -0
  135. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.d.mts +11 -0
  136. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.mjs +90 -0
  137. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.d.mts +14 -0
  138. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.mjs +90 -0
  139. package/dist/scramble-puzzle/src/registry.d.mts +11 -0
  140. package/dist/scramble-puzzle/src/registry.mjs +13 -0
  141. package/dist/scramble-puzzle/src/skewb/skewb-definition.d.mts +8 -0
  142. package/dist/scramble-puzzle/src/skewb/skewb-definition.mjs +18 -0
  143. package/dist/scramble-puzzle/src/skewb/skewb-definition2.mjs +18 -0
  144. package/dist/scramble-puzzle/src/skewb/skewb-parser.d.mts +5 -0
  145. package/dist/scramble-puzzle/src/skewb/skewb-parser.mjs +33 -0
  146. package/dist/scramble-puzzle/src/skewb/skewb-parser2.d.mts +14 -0
  147. package/dist/scramble-puzzle/src/skewb/skewb-parser2.mjs +33 -0
  148. package/dist/scramble-puzzle/src/skewb/skewb-state.d.mts +11 -0
  149. package/dist/scramble-puzzle/src/skewb/skewb-state.mjs +75 -0
  150. package/dist/scramble-puzzle/src/skewb/skewb-state2.d.mts +14 -0
  151. package/dist/scramble-puzzle/src/skewb/skewb-state2.mjs +75 -0
  152. package/dist/scramble-puzzle/src/square1/square1-definition.d.mts +8 -0
  153. package/dist/scramble-puzzle/src/square1/square1-definition.mjs +18 -0
  154. package/dist/scramble-puzzle/src/square1/square1-definition2.mjs +18 -0
  155. package/dist/scramble-puzzle/src/square1/square1-parser.d.mts +17 -0
  156. package/dist/scramble-puzzle/src/square1/square1-parser.mjs +43 -0
  157. package/dist/scramble-puzzle/src/square1/square1-parser2.mjs +47 -0
  158. package/dist/scramble-puzzle/src/square1/square1-state.d.mts +9 -0
  159. package/dist/scramble-puzzle/src/square1/square1-state.mjs +115 -0
  160. package/dist/scramble-puzzle/src/square1/square1-state2.d.mts +21 -0
  161. package/dist/scramble-puzzle/src/square1/square1-state2.mjs +115 -0
  162. package/dist/scramble-puzzle.d.mts +25 -0
  163. package/dist/scramble-puzzle.mjs +23 -0
  164. package/package.json +37 -0
@@ -0,0 +1,57 @@
1
+ import { InvalidMoveError } from "../errors.mjs";
2
+ import { splitAlgorithm } from "../algorithm.mjs";
3
+ //#region ../scramble-puzzle/src/megaminx/megaminx-parser.ts
4
+ const MEGAMINX_FACES = [
5
+ "U",
6
+ "BL",
7
+ "BR",
8
+ "R",
9
+ "F",
10
+ "L",
11
+ "D",
12
+ "DR",
13
+ "DBR",
14
+ "B",
15
+ "DBL",
16
+ "DL"
17
+ ];
18
+ const FACE_MOVE_PATTERN = /^(U|BL|BR|R|F|L|D|DR|DBR|B|DBL|DL)(2'?|')?$/;
19
+ const BIG_TURN_PATTERN = /^([RD])(\+\+?|--?)$/;
20
+ const MEGAMINX_FACE_SET = new Set(MEGAMINX_FACES);
21
+ const isMegaminxFace = (face) => MEGAMINX_FACE_SET.has(face);
22
+ const parseFaceAmount = (suffix) => {
23
+ if (suffix === "2") return 2;
24
+ if (suffix === "2'") return 3;
25
+ if (suffix === "'") return 4;
26
+ return 1;
27
+ };
28
+ const parseBigTurnAmount = (suffix) => {
29
+ if (suffix === "+") return 1;
30
+ if (suffix === "++") return 2;
31
+ if (suffix === "--") return 3;
32
+ return 4;
33
+ };
34
+ const parseMegaminxMove = (token) => {
35
+ const bigTurnMatch = token.match(BIG_TURN_PATTERN);
36
+ if (bigTurnMatch) {
37
+ const [, name, suffix] = bigTurnMatch;
38
+ if (name !== "R" && name !== "D" || suffix === void 0) throw new InvalidMoveError(token, "megaminx");
39
+ return {
40
+ type: "big-turn",
41
+ name,
42
+ amount: parseBigTurnAmount(suffix)
43
+ };
44
+ }
45
+ const faceMatch = token.match(FACE_MOVE_PATTERN);
46
+ if (!faceMatch) throw new InvalidMoveError(token, "megaminx");
47
+ const [, face, suffix] = faceMatch;
48
+ if (face === void 0 || !isMegaminxFace(face)) throw new InvalidMoveError(token, "megaminx");
49
+ return {
50
+ type: "face",
51
+ face,
52
+ amount: parseFaceAmount(suffix)
53
+ };
54
+ };
55
+ const parseMegaminxAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parseMegaminxMove);
56
+ //#endregion
57
+ export { MEGAMINX_FACES, parseMegaminxAlgorithm, parseMegaminxMove };
@@ -0,0 +1,20 @@
1
+ //#region .build/vendor/scramble-puzzle/src/megaminx/megaminx-parser.d.ts
2
+ declare const MEGAMINX_FACES: readonly ["U", "BL", "BR", "R", "F", "L", "D", "DR", "DBR", "B", "DBL", "DL"];
3
+ type MegaminxFace = (typeof MEGAMINX_FACES)[number];
4
+ type MegaminxMoveAmount = 1 | 2 | 3 | 4;
5
+ type MegaminxBigTurnName = 'R' | 'D';
6
+ interface MegaminxFaceMove {
7
+ readonly type: 'face';
8
+ readonly face: MegaminxFace;
9
+ readonly amount: MegaminxMoveAmount;
10
+ }
11
+ interface MegaminxBigTurnMove {
12
+ readonly type: 'big-turn';
13
+ readonly name: MegaminxBigTurnName;
14
+ readonly amount: MegaminxMoveAmount;
15
+ }
16
+ type MegaminxMove = MegaminxFaceMove | MegaminxBigTurnMove;
17
+ declare const parseMegaminxMove: (token: string) => MegaminxMove;
18
+ declare const parseMegaminxAlgorithm: (algorithm: string) => readonly MegaminxMove[];
19
+ //#endregion
20
+ export { MEGAMINX_FACES, MegaminxBigTurnMove, MegaminxBigTurnName, MegaminxFace, MegaminxFaceMove, MegaminxMove, MegaminxMoveAmount, parseMegaminxAlgorithm, parseMegaminxMove };
@@ -0,0 +1,57 @@
1
+ import { InvalidMoveError } from "../errors2.mjs";
2
+ import { splitAlgorithm } from "../algorithm2.mjs";
3
+ //#region .build/vendor/scramble-puzzle/src/megaminx/megaminx-parser.ts
4
+ const MEGAMINX_FACES = [
5
+ "U",
6
+ "BL",
7
+ "BR",
8
+ "R",
9
+ "F",
10
+ "L",
11
+ "D",
12
+ "DR",
13
+ "DBR",
14
+ "B",
15
+ "DBL",
16
+ "DL"
17
+ ];
18
+ const FACE_MOVE_PATTERN = /^(U|BL|BR|R|F|L|D|DR|DBR|B|DBL|DL)(2'?|')?$/;
19
+ const BIG_TURN_PATTERN = /^([RD])(\+\+?|--?)$/;
20
+ const MEGAMINX_FACE_SET = new Set(MEGAMINX_FACES);
21
+ const isMegaminxFace = (face) => MEGAMINX_FACE_SET.has(face);
22
+ const parseFaceAmount = (suffix) => {
23
+ if (suffix === "2") return 2;
24
+ if (suffix === "2'") return 3;
25
+ if (suffix === "'") return 4;
26
+ return 1;
27
+ };
28
+ const parseBigTurnAmount = (suffix) => {
29
+ if (suffix === "+") return 1;
30
+ if (suffix === "++") return 2;
31
+ if (suffix === "--") return 3;
32
+ return 4;
33
+ };
34
+ const parseMegaminxMove = (token) => {
35
+ const bigTurnMatch = token.match(BIG_TURN_PATTERN);
36
+ if (bigTurnMatch) {
37
+ const [, name, suffix] = bigTurnMatch;
38
+ if (name !== "R" && name !== "D" || suffix === void 0) throw new InvalidMoveError(token, "megaminx");
39
+ return {
40
+ type: "big-turn",
41
+ name,
42
+ amount: parseBigTurnAmount(suffix)
43
+ };
44
+ }
45
+ const faceMatch = token.match(FACE_MOVE_PATTERN);
46
+ if (!faceMatch) throw new InvalidMoveError(token, "megaminx");
47
+ const [, face, suffix] = faceMatch;
48
+ if (face === void 0 || !isMegaminxFace(face)) throw new InvalidMoveError(token, "megaminx");
49
+ return {
50
+ type: "face",
51
+ face,
52
+ amount: parseFaceAmount(suffix)
53
+ };
54
+ };
55
+ const parseMegaminxAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parseMegaminxMove);
56
+ //#endregion
57
+ export { MEGAMINX_FACES, parseMegaminxAlgorithm, parseMegaminxMove };
@@ -0,0 +1,9 @@
1
+ //#region ../scramble-puzzle/src/megaminx/megaminx-state.d.ts
2
+ type MegaminxFacelet = number;
3
+ type MegaminxFaceState = readonly MegaminxFacelet[];
4
+ type MegaminxImage = readonly MegaminxFaceState[];
5
+ interface MegaminxState {
6
+ readonly image: MegaminxImage;
7
+ }
8
+ //#endregion
9
+ export { MegaminxState };
@@ -0,0 +1,112 @@
1
+ import { InvalidMoveError } from "../errors.mjs";
2
+ import { MEGAMINX_FACES } from "./megaminx-parser.mjs";
3
+ //#region ../scramble-puzzle/src/megaminx/megaminx-state.ts
4
+ const CENTER_INDEX = 10;
5
+ const STICKERS_PER_FACE = 11;
6
+ const MALFORMED_MOVE = "<malformed>";
7
+ const faceIndex = (face) => MEGAMINX_FACES.indexOf(face);
8
+ const isMoveAmount = (amount) => amount === 1 || amount === 2 || amount === 3 || amount === 4;
9
+ const isMegaminxFace = (face) => typeof face === "string" && MEGAMINX_FACES.includes(face);
10
+ const isBigTurnName = (name) => name === "R" || name === "D";
11
+ const cloneMegaminxImage = (image) => image.map((face) => [...face]);
12
+ const freezeMegaminxImage = (image) => {
13
+ const frozenFaces = image.map((face) => Object.freeze([...face]));
14
+ return Object.freeze(frozenFaces);
15
+ };
16
+ const createMegaminxState = (image) => {
17
+ if (image.length !== MEGAMINX_FACES.length || image.some((face) => face.length !== STICKERS_PER_FACE)) throw new RangeError("megaminx state must contain 12 faces of 11 stickers");
18
+ return Object.freeze({ image: freezeMegaminxImage(image) });
19
+ };
20
+ const cycleStickers = (image, first, second, third, fourth, fifth) => {
21
+ const [firstFace, firstSticker] = first;
22
+ const [secondFace, secondSticker] = second;
23
+ const [thirdFace, thirdSticker] = third;
24
+ const [fourthFace, fourthSticker] = fourth;
25
+ const [fifthFace, fifthSticker] = fifth;
26
+ const savedSticker = image[firstFace][firstSticker];
27
+ image[firstFace][firstSticker] = image[secondFace][secondSticker];
28
+ image[secondFace][secondSticker] = image[thirdFace][thirdSticker];
29
+ image[thirdFace][thirdSticker] = image[fourthFace][fourthSticker];
30
+ image[fourthFace][fourthSticker] = image[fifthFace][fifthSticker];
31
+ image[fifthFace][fifthSticker] = savedSticker;
32
+ };
33
+ const swapOnSide = (image, base, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker, fourthFace, fourthSticker, fifthFace, fifthSticker) => {
34
+ for (let index = 0; index < 3; index += 1) cycleStickers(image, [(firstFace + base) % 12, (firstSticker + index) % 10], [(secondFace + base) % 12, (secondSticker + index) % 10], [(thirdFace + base) % 12, (thirdSticker + index) % 10], [(fourthFace + base) % 12, (fourthSticker + index) % 10], [(fifthFace + base) % 12, (fifthSticker + index) % 10]);
35
+ };
36
+ const swapOnFace = (image, face, first, second, third, fourth, fifth) => {
37
+ cycleStickers(image, [face, first], [face, second], [face, third], [face, fourth], [face, fifth]);
38
+ };
39
+ const rotateFaceOnce = (image, face) => {
40
+ const position = faceIndex(face);
41
+ swapOnFace(image, position, 0, 8, 6, 4, 2);
42
+ swapOnFace(image, position, 1, 9, 7, 5, 3);
43
+ };
44
+ const turnFaceOnce = (image, face) => {
45
+ const position = faceIndex(face);
46
+ const base = position >= 6 ? 6 : 0;
47
+ switch (position % 6) {
48
+ case 0:
49
+ swapOnSide(image, base, 1, 6, 5, 4, 4, 2, 3, 0, 2, 8);
50
+ break;
51
+ case 1:
52
+ swapOnSide(image, base, 0, 0, 2, 0, 9, 6, 10, 6, 5, 2);
53
+ break;
54
+ case 2:
55
+ swapOnSide(image, base, 0, 2, 3, 2, 8, 4, 9, 4, 1, 4);
56
+ break;
57
+ case 3:
58
+ swapOnSide(image, base, 0, 4, 4, 4, 7, 2, 8, 2, 2, 6);
59
+ break;
60
+ case 4:
61
+ swapOnSide(image, base, 0, 6, 5, 6, 11, 0, 7, 0, 3, 8);
62
+ break;
63
+ case 5:
64
+ swapOnSide(image, base, 0, 8, 1, 8, 10, 8, 11, 8, 4, 0);
65
+ break;
66
+ }
67
+ rotateFaceOnce(image, face);
68
+ };
69
+ const applyRepeatedTurns = (image, amount, turn) => {
70
+ for (let index = 0; index < amount; index += 1) turn();
71
+ };
72
+ const cycleCenters = (image, firstFace, secondFace, thirdFace, fourthFace, fifthFace) => {
73
+ cycleStickers(image, [firstFace, CENTER_INDEX], [secondFace, CENTER_INDEX], [thirdFace, CENTER_INDEX], [fourthFace, CENTER_INDEX], [fifthFace, CENTER_INDEX]);
74
+ };
75
+ const swapWholeFace = (image, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker, fourthFace, fourthSticker, fifthFace, fifthSticker) => {
76
+ for (let index = 0; index < 10; index += 1) cycleStickers(image, [firstFace, (firstSticker + index) % 10], [secondFace, (secondSticker + index) % 10], [thirdFace, (thirdSticker + index) % 10], [fourthFace, (fourthSticker + index) % 10], [fifthFace, (fifthSticker + index) % 10]);
77
+ cycleCenters(image, firstFace, secondFace, thirdFace, fourthFace, fifthFace);
78
+ };
79
+ const bigTurnOnce = (image, face) => {
80
+ if (face === "DBR") {
81
+ for (let index = 0; index < 7; index += 1) cycleStickers(image, [0, (1 + index) % 10], [4, (3 + index) % 10], [11, (1 + index) % 10], [10, (1 + index) % 10], [1, (1 + index) % 10]);
82
+ cycleCenters(image, 0, 4, 11, 10, 1);
83
+ swapWholeFace(image, 2, 0, 3, 0, 7, 0, 6, 8, 9, 8);
84
+ rotateFaceOnce(image, "DBR");
85
+ return;
86
+ }
87
+ for (let index = 0; index < 7; index += 1) cycleStickers(image, [1, (9 + index) % 10], [2, (1 + index) % 10], [3, (3 + index) % 10], [4, (5 + index) % 10], [5, (7 + index) % 10]);
88
+ cycleCenters(image, 1, 2, 3, 4, 5);
89
+ swapWholeFace(image, 11, 0, 10, 8, 9, 6, 8, 4, 7, 2);
90
+ rotateFaceOnce(image, "D");
91
+ };
92
+ const bigTurnFace = (name) => name === "R" ? "DBR" : "D";
93
+ const validateMove = (move) => {
94
+ if (typeof move !== "object" || move === null) throw new InvalidMoveError(MALFORMED_MOVE, "megaminx");
95
+ if (move.type === "face") {
96
+ if (!isMegaminxFace(move.face) || !isMoveAmount(move.amount)) throw new InvalidMoveError(MALFORMED_MOVE, "megaminx");
97
+ return move;
98
+ }
99
+ if (move.type === "big-turn" && isBigTurnName(move.name) && isMoveAmount(move.amount)) return move;
100
+ throw new InvalidMoveError(MALFORMED_MOVE, "megaminx");
101
+ };
102
+ const createSolvedMegaminxState = () => createMegaminxState(MEGAMINX_FACES.map((_, face) => Array(STICKERS_PER_FACE).fill(face)));
103
+ const applyMegaminxMove = (state, move) => {
104
+ const validMove = validateMove(move);
105
+ const nextImage = cloneMegaminxImage(state.image);
106
+ if (validMove.type === "face") applyRepeatedTurns(nextImage, validMove.amount, () => turnFaceOnce(nextImage, validMove.face));
107
+ else applyRepeatedTurns(nextImage, validMove.amount, () => bigTurnOnce(nextImage, bigTurnFace(validMove.name)));
108
+ return createMegaminxState(nextImage);
109
+ };
110
+ const areMegaminxStatesEqual = (a, b) => a.image.every((face, faceIndexValue) => face.every((sticker, stickerIndex) => sticker === b.image[faceIndexValue]?.[stickerIndex]));
111
+ //#endregion
112
+ export { applyMegaminxMove, areMegaminxStatesEqual, createSolvedMegaminxState };
@@ -0,0 +1,14 @@
1
+ import { MegaminxMove } from "./megaminx-parser2.mjs";
2
+
3
+ //#region .build/vendor/scramble-puzzle/src/megaminx/megaminx-state.d.ts
4
+ type MegaminxFacelet = number;
5
+ type MegaminxFaceState = readonly MegaminxFacelet[];
6
+ type MegaminxImage = readonly MegaminxFaceState[];
7
+ interface MegaminxState {
8
+ readonly image: MegaminxImage;
9
+ }
10
+ declare const createSolvedMegaminxState: () => MegaminxState;
11
+ declare const applyMegaminxMove: (state: MegaminxState, move: MegaminxMove) => MegaminxState;
12
+ declare const areMegaminxStatesEqual: (a: MegaminxState, b: MegaminxState) => boolean;
13
+ //#endregion
14
+ export { MegaminxFaceState, MegaminxFacelet, MegaminxImage, MegaminxState, applyMegaminxMove, areMegaminxStatesEqual, createSolvedMegaminxState };
@@ -0,0 +1,112 @@
1
+ import { InvalidMoveError } from "../errors2.mjs";
2
+ import { MEGAMINX_FACES } from "./megaminx-parser2.mjs";
3
+ //#region .build/vendor/scramble-puzzle/src/megaminx/megaminx-state.ts
4
+ const CENTER_INDEX = 10;
5
+ const STICKERS_PER_FACE = 11;
6
+ const MALFORMED_MOVE = "<malformed>";
7
+ const faceIndex = (face) => MEGAMINX_FACES.indexOf(face);
8
+ const isMoveAmount = (amount) => amount === 1 || amount === 2 || amount === 3 || amount === 4;
9
+ const isMegaminxFace = (face) => typeof face === "string" && MEGAMINX_FACES.includes(face);
10
+ const isBigTurnName = (name) => name === "R" || name === "D";
11
+ const cloneMegaminxImage = (image) => image.map((face) => [...face]);
12
+ const freezeMegaminxImage = (image) => {
13
+ const frozenFaces = image.map((face) => Object.freeze([...face]));
14
+ return Object.freeze(frozenFaces);
15
+ };
16
+ const createMegaminxState = (image) => {
17
+ if (image.length !== MEGAMINX_FACES.length || image.some((face) => face.length !== STICKERS_PER_FACE)) throw new RangeError("megaminx state must contain 12 faces of 11 stickers");
18
+ return Object.freeze({ image: freezeMegaminxImage(image) });
19
+ };
20
+ const cycleStickers = (image, first, second, third, fourth, fifth) => {
21
+ const [firstFace, firstSticker] = first;
22
+ const [secondFace, secondSticker] = second;
23
+ const [thirdFace, thirdSticker] = third;
24
+ const [fourthFace, fourthSticker] = fourth;
25
+ const [fifthFace, fifthSticker] = fifth;
26
+ const savedSticker = image[firstFace][firstSticker];
27
+ image[firstFace][firstSticker] = image[secondFace][secondSticker];
28
+ image[secondFace][secondSticker] = image[thirdFace][thirdSticker];
29
+ image[thirdFace][thirdSticker] = image[fourthFace][fourthSticker];
30
+ image[fourthFace][fourthSticker] = image[fifthFace][fifthSticker];
31
+ image[fifthFace][fifthSticker] = savedSticker;
32
+ };
33
+ const swapOnSide = (image, base, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker, fourthFace, fourthSticker, fifthFace, fifthSticker) => {
34
+ for (let index = 0; index < 3; index += 1) cycleStickers(image, [(firstFace + base) % 12, (firstSticker + index) % 10], [(secondFace + base) % 12, (secondSticker + index) % 10], [(thirdFace + base) % 12, (thirdSticker + index) % 10], [(fourthFace + base) % 12, (fourthSticker + index) % 10], [(fifthFace + base) % 12, (fifthSticker + index) % 10]);
35
+ };
36
+ const swapOnFace = (image, face, first, second, third, fourth, fifth) => {
37
+ cycleStickers(image, [face, first], [face, second], [face, third], [face, fourth], [face, fifth]);
38
+ };
39
+ const rotateFaceOnce = (image, face) => {
40
+ const position = faceIndex(face);
41
+ swapOnFace(image, position, 0, 8, 6, 4, 2);
42
+ swapOnFace(image, position, 1, 9, 7, 5, 3);
43
+ };
44
+ const turnFaceOnce = (image, face) => {
45
+ const position = faceIndex(face);
46
+ const base = position >= 6 ? 6 : 0;
47
+ switch (position % 6) {
48
+ case 0:
49
+ swapOnSide(image, base, 1, 6, 5, 4, 4, 2, 3, 0, 2, 8);
50
+ break;
51
+ case 1:
52
+ swapOnSide(image, base, 0, 0, 2, 0, 9, 6, 10, 6, 5, 2);
53
+ break;
54
+ case 2:
55
+ swapOnSide(image, base, 0, 2, 3, 2, 8, 4, 9, 4, 1, 4);
56
+ break;
57
+ case 3:
58
+ swapOnSide(image, base, 0, 4, 4, 4, 7, 2, 8, 2, 2, 6);
59
+ break;
60
+ case 4:
61
+ swapOnSide(image, base, 0, 6, 5, 6, 11, 0, 7, 0, 3, 8);
62
+ break;
63
+ case 5:
64
+ swapOnSide(image, base, 0, 8, 1, 8, 10, 8, 11, 8, 4, 0);
65
+ break;
66
+ }
67
+ rotateFaceOnce(image, face);
68
+ };
69
+ const applyRepeatedTurns = (image, amount, turn) => {
70
+ for (let index = 0; index < amount; index += 1) turn();
71
+ };
72
+ const cycleCenters = (image, firstFace, secondFace, thirdFace, fourthFace, fifthFace) => {
73
+ cycleStickers(image, [firstFace, CENTER_INDEX], [secondFace, CENTER_INDEX], [thirdFace, CENTER_INDEX], [fourthFace, CENTER_INDEX], [fifthFace, CENTER_INDEX]);
74
+ };
75
+ const swapWholeFace = (image, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker, fourthFace, fourthSticker, fifthFace, fifthSticker) => {
76
+ for (let index = 0; index < 10; index += 1) cycleStickers(image, [firstFace, (firstSticker + index) % 10], [secondFace, (secondSticker + index) % 10], [thirdFace, (thirdSticker + index) % 10], [fourthFace, (fourthSticker + index) % 10], [fifthFace, (fifthSticker + index) % 10]);
77
+ cycleCenters(image, firstFace, secondFace, thirdFace, fourthFace, fifthFace);
78
+ };
79
+ const bigTurnOnce = (image, face) => {
80
+ if (face === "DBR") {
81
+ for (let index = 0; index < 7; index += 1) cycleStickers(image, [0, (1 + index) % 10], [4, (3 + index) % 10], [11, (1 + index) % 10], [10, (1 + index) % 10], [1, (1 + index) % 10]);
82
+ cycleCenters(image, 0, 4, 11, 10, 1);
83
+ swapWholeFace(image, 2, 0, 3, 0, 7, 0, 6, 8, 9, 8);
84
+ rotateFaceOnce(image, "DBR");
85
+ return;
86
+ }
87
+ for (let index = 0; index < 7; index += 1) cycleStickers(image, [1, (9 + index) % 10], [2, (1 + index) % 10], [3, (3 + index) % 10], [4, (5 + index) % 10], [5, (7 + index) % 10]);
88
+ cycleCenters(image, 1, 2, 3, 4, 5);
89
+ swapWholeFace(image, 11, 0, 10, 8, 9, 6, 8, 4, 7, 2);
90
+ rotateFaceOnce(image, "D");
91
+ };
92
+ const bigTurnFace = (name) => name === "R" ? "DBR" : "D";
93
+ const validateMove = (move) => {
94
+ if (typeof move !== "object" || move === null) throw new InvalidMoveError(MALFORMED_MOVE, "megaminx");
95
+ if (move.type === "face") {
96
+ if (!isMegaminxFace(move.face) || !isMoveAmount(move.amount)) throw new InvalidMoveError(MALFORMED_MOVE, "megaminx");
97
+ return move;
98
+ }
99
+ if (move.type === "big-turn" && isBigTurnName(move.name) && isMoveAmount(move.amount)) return move;
100
+ throw new InvalidMoveError(MALFORMED_MOVE, "megaminx");
101
+ };
102
+ const createSolvedMegaminxState = () => createMegaminxState(MEGAMINX_FACES.map((_, face) => Array(STICKERS_PER_FACE).fill(face)));
103
+ const applyMegaminxMove = (state, move) => {
104
+ const validMove = validateMove(move);
105
+ const nextImage = cloneMegaminxImage(state.image);
106
+ if (validMove.type === "face") applyRepeatedTurns(nextImage, validMove.amount, () => turnFaceOnce(nextImage, validMove.face));
107
+ else applyRepeatedTurns(nextImage, validMove.amount, () => bigTurnOnce(nextImage, bigTurnFace(validMove.name)));
108
+ return createMegaminxState(nextImage);
109
+ };
110
+ const areMegaminxStatesEqual = (a, b) => a.image.every((face, faceIndexValue) => face.every((sticker, stickerIndex) => sticker === b.image[faceIndexValue]?.[stickerIndex]));
111
+ //#endregion
112
+ export { applyMegaminxMove, areMegaminxStatesEqual, createSolvedMegaminxState };
@@ -0,0 +1,19 @@
1
+ import { WcaEventId } from "./events2.mjs";
2
+
3
+ //#region .build/vendor/scramble-puzzle/src/puzzle-definition.d.ts
4
+ interface PuzzleDefinition<State, Move> {
5
+ readonly id: string;
6
+ readonly eventIds: readonly WcaEventId[];
7
+ createSolvedState(): State;
8
+ parseAlgorithm(algorithm: string): readonly Move[];
9
+ applyMove(state: State, move: Move): State;
10
+ applyAlgorithm(state: State, algorithm: string): State;
11
+ isSolved(state: State): boolean;
12
+ normalizeState?(state: State): State;
13
+ }
14
+ interface AppliedPuzzleState<State> {
15
+ readonly puzzleId: string;
16
+ readonly state: State;
17
+ }
18
+ //#endregion
19
+ export { AppliedPuzzleState, PuzzleDefinition };
@@ -0,0 +1,8 @@
1
+ import { PuzzleDefinition } from "../puzzle-definition.mjs";
2
+ import { PyraminxMove } from "./pyraminx-parser2.mjs";
3
+ import { PyraminxState } from "./pyraminx-state2.mjs";
4
+
5
+ //#region .build/vendor/scramble-puzzle/src/pyraminx/pyraminx-definition.d.ts
6
+ declare const createPyraminxDefinition: () => PuzzleDefinition<PyraminxState, PyraminxMove>;
7
+ //#endregion
8
+ export { createPyraminxDefinition };
@@ -0,0 +1,18 @@
1
+ import { applyAlgorithm } from "../algorithm.mjs";
2
+ import { parsePyraminxAlgorithm } from "./pyraminx-parser.mjs";
3
+ import { applyPyraminxMove, arePyraminxStatesEqual, createSolvedPyraminxState } from "./pyraminx-state.mjs";
4
+ //#region ../scramble-puzzle/src/pyraminx/pyraminx-definition.ts
5
+ const createPyraminxDefinition = () => {
6
+ const definition = {
7
+ id: "pyraminx",
8
+ eventIds: ["pyram"],
9
+ createSolvedState: createSolvedPyraminxState,
10
+ parseAlgorithm: parsePyraminxAlgorithm,
11
+ applyMove: applyPyraminxMove,
12
+ applyAlgorithm: (state, algorithm) => applyAlgorithm(definition, state, algorithm),
13
+ isSolved: (state) => arePyraminxStatesEqual(state, createSolvedPyraminxState())
14
+ };
15
+ return definition;
16
+ };
17
+ //#endregion
18
+ export { createPyraminxDefinition };
@@ -0,0 +1,18 @@
1
+ import { applyAlgorithm } from "../algorithm2.mjs";
2
+ import { parsePyraminxAlgorithm } from "./pyraminx-parser2.mjs";
3
+ import { applyPyraminxMove, arePyraminxStatesEqual, createSolvedPyraminxState } from "./pyraminx-state2.mjs";
4
+ //#region .build/vendor/scramble-puzzle/src/pyraminx/pyraminx-definition.ts
5
+ const createPyraminxDefinition = () => {
6
+ const definition = {
7
+ id: "pyraminx",
8
+ eventIds: ["pyram"],
9
+ createSolvedState: createSolvedPyraminxState,
10
+ parseAlgorithm: parsePyraminxAlgorithm,
11
+ applyMove: applyPyraminxMove,
12
+ applyAlgorithm: (state, algorithm) => applyAlgorithm(definition, state, algorithm),
13
+ isSolved: (state) => arePyraminxStatesEqual(state, createSolvedPyraminxState())
14
+ };
15
+ return definition;
16
+ };
17
+ //#endregion
18
+ export { createPyraminxDefinition };
@@ -0,0 +1,5 @@
1
+ //#region ../scramble-puzzle/src/pyraminx/pyraminx-parser.d.ts
2
+ declare const PYRAMINX_FACES: readonly ["F", "D", "L", "R"];
3
+ type PyraminxFace = (typeof PYRAMINX_FACES)[number];
4
+ //#endregion
5
+ export { PyraminxFace };
@@ -0,0 +1,34 @@
1
+ import { InvalidMoveError } from "../errors.mjs";
2
+ import { splitAlgorithm } from "../algorithm.mjs";
3
+ //#region ../scramble-puzzle/src/pyraminx/pyraminx-parser.ts
4
+ const PYRAMINX_FACES = [
5
+ "F",
6
+ "D",
7
+ "L",
8
+ "R"
9
+ ];
10
+ const PYRAMINX_AXES = [
11
+ "U",
12
+ "L",
13
+ "R",
14
+ "B"
15
+ ];
16
+ const PYRAMINX_MOVE_PATTERN = /^([ULRBulrb])('?)$/;
17
+ const PYRAMINX_AXIS_SET = new Set(PYRAMINX_AXES);
18
+ const isPyraminxAxis = (face) => PYRAMINX_AXIS_SET.has(face);
19
+ const parsePyraminxMove = (token) => {
20
+ const match = token.match(PYRAMINX_MOVE_PATTERN);
21
+ if (!match) throw new InvalidMoveError(token, "pyraminx");
22
+ const [, rawFace, suffix] = match;
23
+ if (rawFace === void 0) throw new InvalidMoveError(token, "pyraminx");
24
+ const face = rawFace.toUpperCase();
25
+ if (!isPyraminxAxis(face)) throw new InvalidMoveError(token, "pyraminx");
26
+ return {
27
+ type: rawFace === face ? "turn" : "tip",
28
+ face,
29
+ amount: suffix === "'" ? 2 : 1
30
+ };
31
+ };
32
+ const parsePyraminxAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parsePyraminxMove);
33
+ //#endregion
34
+ export { PYRAMINX_AXES, PYRAMINX_FACES, parsePyraminxAlgorithm, parsePyraminxMove };
@@ -0,0 +1,21 @@
1
+ //#region .build/vendor/scramble-puzzle/src/pyraminx/pyraminx-parser.d.ts
2
+ declare const PYRAMINX_FACES: readonly ["F", "D", "L", "R"];
3
+ declare const PYRAMINX_AXES: readonly ["U", "L", "R", "B"];
4
+ type PyraminxFace = (typeof PYRAMINX_FACES)[number];
5
+ type PyraminxAxis = (typeof PYRAMINX_AXES)[number];
6
+ type PyraminxMoveAmount = 1 | 2;
7
+ interface PyraminxTurnMove {
8
+ readonly type: 'turn';
9
+ readonly face: PyraminxAxis;
10
+ readonly amount: PyraminxMoveAmount;
11
+ }
12
+ interface PyraminxTipMove {
13
+ readonly type: 'tip';
14
+ readonly face: PyraminxAxis;
15
+ readonly amount: PyraminxMoveAmount;
16
+ }
17
+ type PyraminxMove = PyraminxTurnMove | PyraminxTipMove;
18
+ declare const parsePyraminxMove: (token: string) => PyraminxMove;
19
+ declare const parsePyraminxAlgorithm: (algorithm: string) => readonly PyraminxMove[];
20
+ //#endregion
21
+ export { PYRAMINX_AXES, PYRAMINX_FACES, PyraminxAxis, PyraminxFace, PyraminxMove, PyraminxMoveAmount, PyraminxTipMove, PyraminxTurnMove, parsePyraminxAlgorithm, parsePyraminxMove };
@@ -0,0 +1,34 @@
1
+ import { InvalidMoveError } from "../errors2.mjs";
2
+ import { splitAlgorithm } from "../algorithm2.mjs";
3
+ //#region .build/vendor/scramble-puzzle/src/pyraminx/pyraminx-parser.ts
4
+ const PYRAMINX_FACES = [
5
+ "F",
6
+ "D",
7
+ "L",
8
+ "R"
9
+ ];
10
+ const PYRAMINX_AXES = [
11
+ "U",
12
+ "L",
13
+ "R",
14
+ "B"
15
+ ];
16
+ const PYRAMINX_MOVE_PATTERN = /^([ULRBulrb])('?)$/;
17
+ const PYRAMINX_AXIS_SET = new Set(PYRAMINX_AXES);
18
+ const isPyraminxAxis = (face) => PYRAMINX_AXIS_SET.has(face);
19
+ const parsePyraminxMove = (token) => {
20
+ const match = token.match(PYRAMINX_MOVE_PATTERN);
21
+ if (!match) throw new InvalidMoveError(token, "pyraminx");
22
+ const [, rawFace, suffix] = match;
23
+ if (rawFace === void 0) throw new InvalidMoveError(token, "pyraminx");
24
+ const face = rawFace.toUpperCase();
25
+ if (!isPyraminxAxis(face)) throw new InvalidMoveError(token, "pyraminx");
26
+ return {
27
+ type: rawFace === face ? "turn" : "tip",
28
+ face,
29
+ amount: suffix === "'" ? 2 : 1
30
+ };
31
+ };
32
+ const parsePyraminxAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parsePyraminxMove);
33
+ //#endregion
34
+ export { PYRAMINX_AXES, PYRAMINX_FACES, parsePyraminxAlgorithm, parsePyraminxMove };
@@ -0,0 +1,11 @@
1
+ import { PyraminxFace } from "./pyraminx-parser.mjs";
2
+
3
+ //#region ../scramble-puzzle/src/pyraminx/pyraminx-state.d.ts
4
+ type PyraminxFacelet = number;
5
+ type PyraminxFaceState = readonly PyraminxFacelet[];
6
+ type PyraminxImage = readonly PyraminxFaceState[];
7
+ interface PyraminxState {
8
+ readonly image: PyraminxImage;
9
+ }
10
+ //#endregion
11
+ export { PyraminxState };
@@ -0,0 +1,90 @@
1
+ import { InvalidMoveError } from "../errors.mjs";
2
+ import { PYRAMINX_AXES, PYRAMINX_FACES } from "./pyraminx-parser.mjs";
3
+ //#region ../scramble-puzzle/src/pyraminx/pyraminx-state.ts
4
+ const STICKERS_PER_FACE = 9;
5
+ const MALFORMED_MOVE = "<malformed>";
6
+ const isPyraminxAxis = (face) => typeof face === "string" && PYRAMINX_AXES.includes(face);
7
+ const isMoveAmount = (amount) => amount === 1 || amount === 2;
8
+ const axisIndex = (face) => PYRAMINX_AXES.indexOf(face);
9
+ const clonePyraminxImage = (image) => image.map((face) => [...face]);
10
+ const freezePyraminxImage = (image) => {
11
+ const frozenFaces = image.map((face) => Object.freeze([...face]));
12
+ return Object.freeze(frozenFaces);
13
+ };
14
+ const createPyraminxState = (image) => {
15
+ if (image.length !== PYRAMINX_FACES.length || image.some((face) => face.length !== STICKERS_PER_FACE)) throw new RangeError("pyraminx state must contain 4 faces of 9 stickers");
16
+ for (const face of image) for (const sticker of face) if (!Number.isSafeInteger(sticker) || sticker < 0 || sticker >= PYRAMINX_FACES.length) throw new RangeError("pyraminx stickers must be integer face indexes from 0 to 3");
17
+ return Object.freeze({ image: freezePyraminxImage(image) });
18
+ };
19
+ const swapStickers = (image, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker) => {
20
+ const savedSticker = image[firstFace][firstSticker];
21
+ image[firstFace][firstSticker] = image[secondFace][secondSticker];
22
+ image[secondFace][secondSticker] = image[thirdFace][thirdSticker];
23
+ image[thirdFace][thirdSticker] = savedSticker;
24
+ };
25
+ const turnTipOnce = (image, side) => {
26
+ switch (side) {
27
+ case 0:
28
+ swapStickers(image, 0, 0, 3, 0, 2, 3);
29
+ break;
30
+ case 1:
31
+ swapStickers(image, 0, 6, 2, 6, 1, 0);
32
+ break;
33
+ case 2:
34
+ swapStickers(image, 0, 3, 1, 3, 3, 6);
35
+ break;
36
+ case 3:
37
+ swapStickers(image, 1, 6, 2, 0, 3, 3);
38
+ break;
39
+ }
40
+ };
41
+ const turnOnce = (image, side) => {
42
+ switch (side) {
43
+ case 0:
44
+ swapStickers(image, 0, 8, 3, 8, 2, 2);
45
+ swapStickers(image, 0, 1, 3, 1, 2, 4);
46
+ swapStickers(image, 0, 2, 3, 2, 2, 5);
47
+ break;
48
+ case 1:
49
+ swapStickers(image, 2, 8, 1, 2, 0, 8);
50
+ swapStickers(image, 2, 7, 1, 1, 0, 7);
51
+ swapStickers(image, 2, 5, 1, 8, 0, 5);
52
+ break;
53
+ case 2:
54
+ swapStickers(image, 3, 8, 0, 5, 1, 5);
55
+ swapStickers(image, 3, 7, 0, 4, 1, 4);
56
+ swapStickers(image, 3, 5, 0, 2, 1, 2);
57
+ break;
58
+ case 3:
59
+ swapStickers(image, 1, 8, 2, 2, 3, 5);
60
+ swapStickers(image, 1, 7, 2, 1, 3, 4);
61
+ swapStickers(image, 1, 5, 2, 8, 3, 2);
62
+ break;
63
+ }
64
+ turnTipOnce(image, side);
65
+ };
66
+ const applyRepeatedTurns = (image, amount, turn) => {
67
+ for (let index = 0; index < amount; index += 1) turn();
68
+ };
69
+ const validateMove = (move) => {
70
+ if (typeof move !== "object" || move === null) throw new InvalidMoveError(MALFORMED_MOVE, "pyraminx");
71
+ if ((move.type === "turn" || move.type === "tip") && isPyraminxAxis(move.face) && isMoveAmount(move.amount)) return move;
72
+ throw new InvalidMoveError(MALFORMED_MOVE, "pyraminx");
73
+ };
74
+ const createSolvedPyraminxState = () => createPyraminxState(PYRAMINX_FACES.map((_, face) => Array(STICKERS_PER_FACE).fill(face)));
75
+ const applyPyraminxMove = (state, move) => {
76
+ const validMove = validateMove(move);
77
+ const nextImage = clonePyraminxImage(state.image);
78
+ const side = axisIndex(validMove.face);
79
+ applyRepeatedTurns(nextImage, validMove.amount, () => {
80
+ if (validMove.type === "tip") {
81
+ turnTipOnce(nextImage, side);
82
+ return;
83
+ }
84
+ turnOnce(nextImage, side);
85
+ });
86
+ return createPyraminxState(nextImage);
87
+ };
88
+ const arePyraminxStatesEqual = (a, b) => a.image.every((face, faceIndexValue) => face.every((sticker, stickerIndex) => sticker === b.image[faceIndexValue]?.[stickerIndex]));
89
+ //#endregion
90
+ export { applyPyraminxMove, arePyraminxStatesEqual, createSolvedPyraminxState };