@cubingcenter/scrambler 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
  2. package/dist/puzzles/cube3/scrambler.js +1 -0
  3. package/dist/puzzles/cube4/scrambler.js +3 -3
  4. package/dist/puzzles/index.d.ts +1 -0
  5. package/dist/puzzles/index.d.ts.map +1 -1
  6. package/dist/puzzles/index.js +3 -0
  7. package/dist/puzzles/pyraminx/facelets.d.ts +7 -0
  8. package/dist/puzzles/pyraminx/facelets.d.ts.map +1 -0
  9. package/dist/puzzles/pyraminx/facelets.js +97 -0
  10. package/dist/puzzles/pyraminx/index.d.ts +2 -0
  11. package/dist/puzzles/pyraminx/index.d.ts.map +1 -1
  12. package/dist/puzzles/pyraminx/index.js +1 -0
  13. package/dist/puzzles/pyraminx/moves.d.ts.map +1 -1
  14. package/dist/puzzles/pyraminx/moves.js +35 -38
  15. package/dist/puzzles/pyraminx/scrambler.d.ts.map +1 -1
  16. package/dist/puzzles/pyraminx/scrambler.js +12 -6
  17. package/dist/puzzles/skewb/facelets.d.ts +6 -0
  18. package/dist/puzzles/skewb/facelets.d.ts.map +1 -0
  19. package/dist/puzzles/skewb/facelets.js +71 -0
  20. package/dist/puzzles/skewb/index.d.ts +10 -0
  21. package/dist/puzzles/skewb/index.d.ts.map +1 -0
  22. package/dist/puzzles/skewb/index.js +8 -0
  23. package/dist/puzzles/skewb/moves.d.ts +19 -0
  24. package/dist/puzzles/skewb/moves.d.ts.map +1 -0
  25. package/dist/puzzles/skewb/moves.js +84 -0
  26. package/dist/puzzles/skewb/random-state.d.ts +3 -0
  27. package/dist/puzzles/skewb/random-state.d.ts.map +1 -0
  28. package/dist/puzzles/skewb/random-state.js +27 -0
  29. package/dist/puzzles/skewb/scrambler.d.ts +6 -0
  30. package/dist/puzzles/skewb/scrambler.d.ts.map +1 -0
  31. package/dist/puzzles/skewb/scrambler.js +52 -0
  32. package/dist/puzzles/skewb/solver.d.ts +11 -0
  33. package/dist/puzzles/skewb/solver.d.ts.map +1 -0
  34. package/dist/puzzles/skewb/solver.js +149 -0
  35. package/dist/puzzles/skewb/state.d.ts +6 -0
  36. package/dist/puzzles/skewb/state.d.ts.map +1 -0
  37. package/dist/puzzles/skewb/state.js +31 -0
  38. package/dist/puzzles/skewb/types.d.ts +25 -0
  39. package/dist/puzzles/skewb/types.d.ts.map +1 -0
  40. package/dist/puzzles/skewb/types.js +13 -0
  41. package/dist/puzzles/skewb/validation.d.ts +6 -0
  42. package/dist/puzzles/skewb/validation.d.ts.map +1 -0
  43. package/dist/puzzles/skewb/validation.js +69 -0
  44. package/dist-cjs/puzzles/cube3/scrambler.js +1 -0
  45. package/dist-cjs/puzzles/cube4/scrambler.js +3 -3
  46. package/dist-cjs/puzzles/index.js +4 -1
  47. package/dist-cjs/puzzles/pyraminx/facelets.js +103 -0
  48. package/dist-cjs/puzzles/pyraminx/index.js +6 -1
  49. package/dist-cjs/puzzles/pyraminx/moves.js +35 -38
  50. package/dist-cjs/puzzles/pyraminx/scrambler.js +12 -6
  51. package/dist-cjs/puzzles/skewb/facelets.js +77 -0
  52. package/dist-cjs/puzzles/skewb/index.js +38 -0
  53. package/dist-cjs/puzzles/skewb/moves.js +95 -0
  54. package/dist-cjs/puzzles/skewb/random-state.js +30 -0
  55. package/dist-cjs/puzzles/skewb/scrambler.js +56 -0
  56. package/dist-cjs/puzzles/skewb/solver.js +160 -0
  57. package/dist-cjs/puzzles/skewb/state.js +37 -0
  58. package/dist-cjs/puzzles/skewb/types.js +16 -0
  59. package/dist-cjs/puzzles/skewb/validation.js +75 -0
  60. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube3/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAW9F,eAAO,MAAM,sBAAsB,EAAE,iBAYpC,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CA+CzB"}
1
+ {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube3/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAW9F,eAAO,MAAM,sBAAsB,EAAE,iBAYpC,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CAgDzB"}
@@ -42,6 +42,7 @@ export async function generateCube3Scramble(options = {}) {
42
42
  metadata: {
43
43
  generator: "cube3-two-phase",
44
44
  generatorVersion: "1.0.0",
45
+ facelets,
45
46
  faceletString: formatCube3Facelets(facelets),
46
47
  state: JSON.parse(JSON.stringify(state)),
47
48
  solutionMoves: solution.moves,
@@ -7,9 +7,9 @@ export const cube4ScrambleGenerator = {
7
7
  eventId: "444",
8
8
  name: "4x4x4 Cube",
9
9
  puzzle: "cube-4x4",
10
- quality: "random-move",
11
- generator: "cube4-random-move",
12
- description: "Random-move 4x4 scramble with 40 moves."
10
+ quality: "random-state",
11
+ generator: "cubing-scramble",
12
+ description: "Random-state 4x4 scramble generated by cubing.js."
13
13
  },
14
14
  generate(options = {}) {
15
15
  return generateCube4Scramble(options);
@@ -7,4 +7,5 @@ export * as cube6x6 from "./cube6x6/index.js";
7
7
  export * as cube7x7 from "./cube7x7/index.js";
8
8
  export * as pyraminx from "./pyraminx/index.js";
9
9
  export * as clock from "./clock/index.js";
10
+ export * as skewb from "./skewb/index.js";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/puzzles/index.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/puzzles/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC"}
@@ -8,6 +8,7 @@ import { cube6ScrambleGenerator } from "./cube6x6/index.js";
8
8
  import { cube7ScrambleGenerator } from "./cube7x7/index.js";
9
9
  import { pyraminxScrambleGenerator } from "./pyraminx/index.js";
10
10
  import { clockScrambleGenerator } from "./clock/index.js";
11
+ import { skewbScrambleGenerator } from "./skewb/index.js";
11
12
  registerScrambleGenerator(cube2ScrambleGenerator);
12
13
  registerScrambleGenerator(cube3ScrambleGenerator);
13
14
  registerScrambleGenerator(cube4ScrambleGenerator);
@@ -17,6 +18,7 @@ registerScrambleGenerator(cube6ScrambleGenerator);
17
18
  registerScrambleGenerator(cube7ScrambleGenerator);
18
19
  registerScrambleGenerator(pyraminxScrambleGenerator);
19
20
  registerScrambleGenerator(clockScrambleGenerator);
21
+ registerScrambleGenerator(skewbScrambleGenerator);
20
22
  export * as cube2 from "./cube2/index.js";
21
23
  export * as cube3 from "./cube3/index.js";
22
24
  export * as cube4 from "./cube4/index.js";
@@ -26,3 +28,4 @@ export * as cube6x6 from "./cube6x6/index.js";
26
28
  export * as cube7x7 from "./cube7x7/index.js";
27
29
  export * as pyraminx from "./pyraminx/index.js";
28
30
  export * as clock from "./clock/index.js";
31
+ export * as skewb from "./skewb/index.js";
@@ -0,0 +1,7 @@
1
+ import type { PyraminxState } from "./types.js";
2
+ export type PyraminxFacelets = Record<"F" | "L" | "R" | "D", readonly string[]>;
3
+ export declare function createSolvedPyraminxFacelets(): PyraminxFacelets;
4
+ export declare function toPyraminxFacelets(state: PyraminxState): PyraminxFacelets;
5
+ export declare function formatPyraminxFacelets(facelets: PyraminxFacelets): string;
6
+ export declare function getPyraminxFaceOrder(): readonly ("F" | "L" | "R" | "D")[];
7
+ //# sourceMappingURL=facelets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facelets.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/facelets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAUhD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;AA6DhF,wBAAgB,4BAA4B,IAAI,gBAAgB,CAO/D;AAyBD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,CAiCzE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAEzE;AAED,wBAAgB,oBAAoB,IAAI,SAAS,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,CAEzE"}
@@ -0,0 +1,97 @@
1
+ const FACE_ORDER = ["F", "L", "R", "D"];
2
+ // positionId -> sticker slots (each slot = one triangle cell of the grid).
3
+ // Positions follow the scrambler piece model (moves.ts):
4
+ // edges 0..5 = UL, UR, UB, LR, LB, RB
5
+ // centers 0..3 = U, L, R, B
6
+ // tips 0..3 = U, L, R, B
7
+ //
8
+ // The slot layout is validated against the piece model by
9
+ // test/pyraminx-facelets.test.ts (single moves + randomized sequences).
10
+ const EDGE_POSITION_SLOTS = [
11
+ [["F", 1], ["L", 7]], // 0 UL
12
+ [["F", 3], ["R", 5]], // 1 UR
13
+ [["L", 2], ["R", 2]], // 2 UB
14
+ [["F", 6], ["D", 2]], // 3 LR
15
+ [["L", 5], ["D", 5]], // 4 LB
16
+ [["R", 7], ["D", 7]], // 5 RB
17
+ ];
18
+ const CENTER_POSITION_SLOTS = [
19
+ [["F", 2], ["L", 3], ["R", 1]], // 0 U
20
+ [["F", 5], ["L", 6], ["D", 1]], // 1 L
21
+ [["F", 7], ["R", 6], ["D", 3]], // 2 R
22
+ [["L", 1], ["R", 3], ["D", 6]], // 3 B
23
+ ];
24
+ const TIP_POSITION_SLOTS = [
25
+ [["F", 0], ["L", 4], ["R", 0]], // 0 U
26
+ [["F", 4], ["D", 0], ["L", 8]], // 1 L
27
+ [["F", 8], ["R", 8], ["D", 4]], // 2 R
28
+ [["L", 0], ["D", 8], ["R", 4]], // 3 B
29
+ ];
30
+ // pieceId -> sticker colors (canonical order aligned with the role order above)
31
+ const EDGE_PIECE_STICKERS = [
32
+ ["F", "L"], // 0 UL
33
+ ["F", "R"], // 1 UR
34
+ ["L", "R"], // 2 UB
35
+ ["F", "D"], // 3 LR
36
+ ["L", "D"], // 4 LB
37
+ ["R", "D"], // 5 RB
38
+ ];
39
+ const CENTER_PIECE_STICKERS = [
40
+ ["F", "L", "R"], // 0 U
41
+ ["F", "L", "D"], // 1 L
42
+ ["F", "R", "D"], // 2 R
43
+ ["L", "R", "D"], // 3 B
44
+ ];
45
+ const TIP_PIECE_STICKERS = [
46
+ ["F", "L", "R"], // 0 U
47
+ ["F", "D", "L"], // 1 L
48
+ ["F", "R", "D"], // 2 R
49
+ ["L", "D", "R"], // 3 B
50
+ ];
51
+ export function createSolvedPyraminxFacelets() {
52
+ return {
53
+ F: Array.from({ length: 9 }, () => "F"),
54
+ L: Array.from({ length: 9 }, () => "L"),
55
+ R: Array.from({ length: 9 }, () => "R"),
56
+ D: Array.from({ length: 9 }, () => "D"),
57
+ };
58
+ }
59
+ function createEmptyPyraminxFacelets() {
60
+ return {
61
+ F: Array(9).fill("?"),
62
+ L: Array(9).fill("?"),
63
+ R: Array(9).fill("?"),
64
+ D: Array(9).fill("?"),
65
+ };
66
+ }
67
+ function placeOrientedStickers(facelets, slots, stickers, orientation) {
68
+ for (let index = 0; index < slots.length; index += 1) {
69
+ const [face, stickerIndex] = slots[index];
70
+ const sticker = stickers[(index - orientation + stickers.length) % stickers.length];
71
+ const arr = facelets[face];
72
+ arr[stickerIndex] = sticker;
73
+ }
74
+ }
75
+ export function toPyraminxFacelets(state) {
76
+ const facelets = createEmptyPyraminxFacelets();
77
+ for (let position = 0; position < 6; position += 1) {
78
+ const piece = state.edgesPerm[position];
79
+ const orientation = state.edgesOrient[position];
80
+ placeOrientedStickers(facelets, EDGE_POSITION_SLOTS[position], EDGE_PIECE_STICKERS[piece], orientation);
81
+ }
82
+ for (let position = 0; position < 4; position += 1) {
83
+ const orientation = state.centers[position];
84
+ placeOrientedStickers(facelets, CENTER_POSITION_SLOTS[position], CENTER_PIECE_STICKERS[position], orientation);
85
+ }
86
+ for (let position = 0; position < 4; position += 1) {
87
+ const orientation = state.tips[position];
88
+ placeOrientedStickers(facelets, TIP_POSITION_SLOTS[position], TIP_PIECE_STICKERS[position], orientation);
89
+ }
90
+ return facelets;
91
+ }
92
+ export function formatPyraminxFacelets(facelets) {
93
+ return FACE_ORDER.map((face) => facelets[face].join("")).join("");
94
+ }
95
+ export function getPyraminxFaceOrder() {
96
+ return FACE_ORDER;
97
+ }
@@ -5,5 +5,7 @@ export { clonePyraminxState, createSolvedPyraminxState, pyraminxStatesEqual, isS
5
5
  export { permutationParity, validatePyraminxState, isAllowedRandomPyraminxState } from "./validation.js";
6
6
  export { generateRandomPyraminxState } from "./random-state.js";
7
7
  export { pyraminxScrambleGenerator, generatePyraminxScramble } from "./scrambler.js";
8
+ export { createSolvedPyraminxFacelets, formatPyraminxFacelets, getPyraminxFaceOrder, toPyraminxFacelets } from "./facelets.js";
9
+ export type { PyraminxFacelets } from "./facelets.js";
8
10
  export { solvePyraminx } from "./solver.js";
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,4BAA4B,EAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,2BAA2B,EAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,aAAa,EACd,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,4BAA4B,EAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,2BAA2B,EAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,gBAAgB,EACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACd,MAAM,aAAa,CAAC"}
@@ -4,4 +4,5 @@ export { clonePyraminxState, createSolvedPyraminxState, pyraminxStatesEqual, isS
4
4
  export { permutationParity, validatePyraminxState, isAllowedRandomPyraminxState } from "./validation.js";
5
5
  export { generateRandomPyraminxState } from "./random-state.js";
6
6
  export { pyraminxScrambleGenerator, generatePyraminxScramble } from "./scrambler.js";
7
+ export { createSolvedPyraminxFacelets, formatPyraminxFacelets, getPyraminxFaceOrder, toPyraminxFacelets } from "./facelets.js";
7
8
  export { solvePyraminx } from "./solver.js";
@@ -1 +1 @@
1
- {"version":3,"file":"moves.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/moves.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAqC,MAAM,YAAY,CAAC;AAKjG,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CA4BzF;AA8DD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,aAAa,CAE1G;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY,EAAE,CAEtF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAMxE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAE9E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAU7D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAKnE"}
1
+ {"version":3,"file":"moves.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/moves.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAqC,MAAM,YAAY,CAAC;AAKjG,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CA4BzF;AA2DD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,aAAa,CAE1G;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY,EAAE,CAEtF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAMxE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAE9E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAU7D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAKnE"}
@@ -30,56 +30,53 @@ function applySingleCoreMoveCW(state, face) {
30
30
  const centers = state.centers;
31
31
  const perm = state.edgesPerm;
32
32
  const orient = state.edgesOrient;
33
+ const tips = state.tips;
33
34
  // Clone arrays for temporary storage
34
35
  const prevPerm = [...perm];
35
36
  const prevOrient = [...orient];
36
37
  if (face === "U") {
37
- // Center
38
+ // U: UL -> UB -> UR -> UL with the physical orientation (matches viz)
38
39
  centers[0] = (centers[0] + 1) % 3;
39
- // Edges cycle: 0 -> 1 -> 2 -> 0 (UL -> UR -> UB -> UL)
40
- // No orientation flips for U
41
- perm[1] = prevPerm[0];
42
- perm[2] = prevPerm[1];
43
- perm[0] = prevPerm[2];
44
- orient[1] = prevOrient[0];
45
- orient[2] = prevOrient[1];
46
- orient[0] = prevOrient[2];
40
+ tips[0] = (tips[0] + 1) % 3;
41
+ perm[0] = prevPerm[1];
42
+ perm[1] = prevPerm[2];
43
+ perm[2] = prevPerm[0];
44
+ orient[0] = (prevOrient[1] + 1) % 2;
45
+ orient[1] = (prevOrient[2] + 1) % 2;
46
+ orient[2] = prevOrient[0];
47
47
  }
48
48
  else if (face === "L") {
49
- // Center
50
- centers[1] = (centers[1] + 1) % 3;
51
- // Edges cycle: 0 -> 4 -> 3 -> 0 (UL -> LB -> LR -> UL)
52
- // Flips: UL(0) flips, LB(4) flips, LR(3) does not flip
53
- perm[4] = prevPerm[0];
54
- perm[3] = prevPerm[4];
55
- perm[0] = prevPerm[3];
56
- orient[4] = (prevOrient[0] + 1) % 2;
57
- orient[3] = (prevOrient[4] + 1) % 2;
58
- orient[0] = prevOrient[3];
49
+ // L: UL -> LB -> LR -> UL (physical, matches viz)
50
+ centers[1] = (centers[1] + 2) % 3;
51
+ tips[1] = (tips[1] + 1) % 3;
52
+ perm[0] = prevPerm[4];
53
+ perm[3] = prevPerm[0];
54
+ perm[4] = prevPerm[3];
55
+ orient[0] = prevOrient[4];
56
+ orient[3] = (prevOrient[0] + 1) % 2;
57
+ orient[4] = (prevOrient[3] + 1) % 2;
59
58
  }
60
59
  else if (face === "R") {
61
- // Center
60
+ // R: UR -> LR -> RB -> UR (physical, matches viz)
62
61
  centers[2] = (centers[2] + 1) % 3;
63
- // Edges cycle: 1 -> 3 -> 5 -> 1 (UR -> LR -> RB -> UR)
64
- // Flips: UR(1) flips, LR(3) flips, RB(5) does not flip
65
- perm[3] = prevPerm[1];
66
- perm[5] = prevPerm[3];
67
- perm[1] = prevPerm[5];
68
- orient[3] = (prevOrient[1] + 1) % 2;
69
- orient[5] = (prevOrient[3] + 1) % 2;
70
- orient[1] = prevOrient[5];
62
+ tips[2] = (tips[2] + 1) % 3;
63
+ perm[1] = prevPerm[3];
64
+ perm[3] = prevPerm[5];
65
+ perm[5] = prevPerm[1];
66
+ orient[1] = (prevOrient[3] + 1) % 2;
67
+ orient[3] = (prevOrient[5] + 1) % 2;
68
+ orient[5] = prevOrient[1];
71
69
  }
72
70
  else if (face === "B") {
73
- // Center
74
- centers[3] = (centers[3] + 1) % 3;
75
- // Edges cycle: 2 -> 5 -> 4 -> 2 (UB -> RB -> LB -> UB)
76
- // Flips: UB(2) flips, RB(5) flips, LB(4) does not flip
77
- perm[5] = prevPerm[2];
78
- perm[4] = prevPerm[5];
79
- perm[2] = prevPerm[4];
80
- orient[5] = (prevOrient[2] + 1) % 2;
81
- orient[4] = (prevOrient[5] + 1) % 2;
82
- orient[2] = prevOrient[4];
71
+ // B: UB -> LB -> RB -> UB (physical, matches viz)
72
+ centers[3] = (centers[3] + 2) % 3;
73
+ tips[3] = (tips[3] + 1) % 3;
74
+ perm[2] = prevPerm[5];
75
+ perm[4] = prevPerm[2];
76
+ perm[5] = prevPerm[4];
77
+ orient[2] = prevOrient[5];
78
+ orient[4] = (prevOrient[2] + 1) % 2;
79
+ orient[5] = (prevOrient[4] + 1) % 2;
83
80
  }
84
81
  }
85
82
  export function applyPyraminxAlgorithm(state, moves) {
@@ -1 +1 @@
1
- {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAO9F,eAAO,MAAM,yBAAyB,EAAE,iBAYvC,CAAC;AAEF,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CAyCzB"}
1
+ {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/pyraminx/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAQ9F,eAAO,MAAM,yBAAyB,EAAE,iBAYvC,CAAC;AAEF,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CA+CzB"}
@@ -2,9 +2,10 @@ import { generateRandomPyraminxState } from "./random-state.js";
2
2
  import { createSolvedPyraminxState } from "./state.js";
3
3
  import { applyPyraminxAlgorithm, invertPyraminxAlgorithm } from "./moves.js";
4
4
  import { solvePyraminx } from "./solver.js";
5
+ import { formatPyraminxFacelets, toPyraminxFacelets } from "./facelets.js";
5
6
  export const pyraminxScrambleGenerator = {
6
7
  info: {
7
- eventId: "pyrso",
8
+ eventId: "pyra",
8
9
  name: "Pyraminx",
9
10
  puzzle: "pyraminx",
10
11
  quality: "random-state",
@@ -20,15 +21,17 @@ export async function generatePyraminxScramble(options = {}) {
20
21
  // Solve the core edges and centers
21
22
  const solution = solvePyraminx(state);
22
23
  const scrambleMoves = invertPyraminxAlgorithm(solution);
23
- // Append tips to scrambleMoves
24
+ // Append tips: layer moves already rotate tips, so we need the delta
25
+ // between the target tips and the tips produced by the core scramble.
26
+ const coreState = applyPyraminxAlgorithm(createSolvedPyraminxState(), scrambleMoves);
24
27
  const finalMoves = [...scrambleMoves];
25
28
  const tipsNotation = ["u", "l", "r", "b"];
26
29
  for (let i = 0; i < 4; i++) {
27
- const tipVal = state.tips[i];
28
- if (tipVal === 1) {
30
+ const delta = (state.tips[i] - coreState.tips[i] + 3) % 3;
31
+ if (delta === 1) {
29
32
  finalMoves.push(tipsNotation[i]);
30
33
  }
31
- else if (tipVal === 2) {
34
+ else if (delta === 2) {
32
35
  finalMoves.push(`${tipsNotation[i]}'`);
33
36
  }
34
37
  }
@@ -41,14 +44,17 @@ export async function generatePyraminxScramble(options = {}) {
41
44
  throw new Error("Generated Pyraminx scramble does not reproduce the target random state.");
42
45
  }
43
46
  }
47
+ const facelets = toPyraminxFacelets(state);
44
48
  return {
45
- eventId: "pyrso",
49
+ eventId: "pyra",
46
50
  scramble: finalMoves.join(" "),
47
51
  moves: finalMoves,
48
52
  quality: "random-state",
49
53
  generator: "pyraminx-ida-star",
50
54
  metadata: {
51
55
  state,
56
+ facelets,
57
+ faceletString: formatPyraminxFacelets(facelets),
52
58
  solutionMoves: solution,
53
59
  solutionDepth: solution.length
54
60
  }
@@ -0,0 +1,6 @@
1
+ import type { SkewbFacelets, SkewbState } from "./types.js";
2
+ export declare function createSolvedSkewbFacelets(): SkewbFacelets;
3
+ export declare function toSkewbFacelets(state: SkewbState): SkewbFacelets;
4
+ export declare function formatSkewbFacelets(facelets: SkewbFacelets): string;
5
+ export declare function getSkewbFaceOrder(): readonly string[];
6
+ //# sourceMappingURL=facelets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facelets.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/facelets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgC5D,wBAAgB,yBAAyB,IAAI,aAAa,CASzD;AAaD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAsBhE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CAEnE;AAED,wBAAgB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAErD"}
@@ -0,0 +1,71 @@
1
+ // Facelets model matching cubingcenter-viz/src/puzzles/skewb.ts
2
+ // Each face has 5 stickers: 0=center, 1=TL,2=TR,3=BL,4=BR (net layout)
3
+ const FACE_ORDER = ["U", "R", "F", "D", "L", "B"];
4
+ // Canonical sticker faces per corner position: [UD sticker, RL sticker, FB sticker]
5
+ const CORNER_STICKERS = [
6
+ ["U", "R", "F"],
7
+ ["U", "L", "F"],
8
+ ["U", "R", "B"],
9
+ ["U", "L", "B"],
10
+ ["D", "R", "F"],
11
+ ["D", "L", "F"],
12
+ ["D", "R", "B"],
13
+ ["D", "L", "B"],
14
+ ];
15
+ // Facelet index of each corner position on each of its 3 faces, aligned with CORNER_STICKERS order.
16
+ const CORNER_SLOTS = [
17
+ [["U", 4], ["R", 1], ["F", 2]],
18
+ [["U", 3], ["L", 2], ["F", 1]],
19
+ [["U", 2], ["R", 2], ["B", 1]],
20
+ [["U", 1], ["L", 1], ["B", 2]],
21
+ [["D", 2], ["R", 3], ["F", 4]],
22
+ [["D", 1], ["L", 4], ["F", 3]],
23
+ [["D", 4], ["R", 4], ["B", 3]],
24
+ [["D", 3], ["L", 3], ["B", 4]],
25
+ ];
26
+ export function createSolvedSkewbFacelets() {
27
+ return {
28
+ U: Array.from({ length: 5 }, () => "U"),
29
+ R: Array.from({ length: 5 }, () => "R"),
30
+ F: Array.from({ length: 5 }, () => "F"),
31
+ D: Array.from({ length: 5 }, () => "D"),
32
+ L: Array.from({ length: 5 }, () => "L"),
33
+ B: Array.from({ length: 5 }, () => "B"),
34
+ };
35
+ }
36
+ function createEmptySkewbFacelets() {
37
+ return {
38
+ U: Array(5).fill("?"),
39
+ R: Array(5).fill("?"),
40
+ F: Array(5).fill("?"),
41
+ D: Array(5).fill("?"),
42
+ L: Array(5).fill("?"),
43
+ B: Array(5).fill("?"),
44
+ };
45
+ }
46
+ export function toSkewbFacelets(state) {
47
+ const facelets = createEmptySkewbFacelets();
48
+ // centers
49
+ for (let face = 0; face < 6; face++) {
50
+ const targetFace = FACE_ORDER[face];
51
+ facelets[targetFace][0] = FACE_ORDER[state.centers[face]];
52
+ }
53
+ // corners
54
+ for (let pos = 0; pos < 8; pos++) {
55
+ const piece = state.corners.permutation[pos];
56
+ const ori = state.corners.orientation[pos];
57
+ const slots = CORNER_SLOTS[pos];
58
+ const stickers = CORNER_STICKERS[piece];
59
+ for (let i = 0; i < 3; i++) {
60
+ const [face, idx] = slots[i];
61
+ facelets[face][idx] = stickers[(i + 3 - ori) % 3];
62
+ }
63
+ }
64
+ return facelets;
65
+ }
66
+ export function formatSkewbFacelets(facelets) {
67
+ return FACE_ORDER.map((face) => facelets[face].join("")).join("");
68
+ }
69
+ export function getSkewbFaceOrder() {
70
+ return FACE_ORDER;
71
+ }
@@ -0,0 +1,10 @@
1
+ export { SKEWB_MOVES, SKEWB_FACES } from "./types.js";
2
+ export type { SkewbMove, SkewbState, SkewbFaceMove, SkewbRandomStateOptions, SkewbFacelets } from "./types.js";
3
+ export { applySkewbAlgorithm, applySkewbMove, formatSkewbAlgorithm, invertSkewbAlgorithm, invertSkewbMove, parseSkewbAlgorithm, parseSkewbMove, } from "./moves.js";
4
+ export { cloneSkewbState, createSolvedSkewbState, isSolvedSkewbState, skewbStatesEqual, } from "./state.js";
5
+ export { permutationParity, validateSkewbState, isAllowedRandomSkewbState, isOneMoveFromSolvedSkewbState } from "./validation.js";
6
+ export { generateRandomSkewbState } from "./random-state.js";
7
+ export { createSolvedSkewbFacelets, formatSkewbFacelets, getSkewbFaceOrder, toSkewbFacelets } from "./facelets.js";
8
+ export { solveSkewb, getStateIndex, getStateFromIndex } from "./solver.js";
9
+ export { generateSkewbScramble, skewbScrambleGenerator } from "./scrambler.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/G,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAClI,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { SKEWB_MOVES, SKEWB_FACES } from "./types.js";
2
+ export { applySkewbAlgorithm, applySkewbMove, formatSkewbAlgorithm, invertSkewbAlgorithm, invertSkewbMove, parseSkewbAlgorithm, parseSkewbMove, } from "./moves.js";
3
+ export { cloneSkewbState, createSolvedSkewbState, isSolvedSkewbState, skewbStatesEqual, } from "./state.js";
4
+ export { permutationParity, validateSkewbState, isAllowedRandomSkewbState, isOneMoveFromSolvedSkewbState } from "./validation.js";
5
+ export { generateRandomSkewbState } from "./random-state.js";
6
+ export { createSolvedSkewbFacelets, formatSkewbFacelets, getSkewbFaceOrder, toSkewbFacelets } from "./facelets.js";
7
+ export { solveSkewb, getStateIndex, getStateFromIndex } from "./solver.js";
8
+ export { generateSkewbScramble, skewbScrambleGenerator } from "./scrambler.js";
@@ -0,0 +1,19 @@
1
+ import type { SkewbMove, SkewbState } from "./types.js";
2
+ interface MoveTable {
3
+ corners: {
4
+ permutation: readonly number[];
5
+ orientation: readonly number[];
6
+ };
7
+ centers: readonly number[];
8
+ }
9
+ declare const MOVE_TABLES: Record<string, MoveTable>;
10
+ export declare function applySkewbMove(state: SkewbState, move: SkewbMove): SkewbState;
11
+ export declare function applySkewbAlgorithm(state: SkewbState, moves: readonly SkewbMove[]): SkewbState;
12
+ export declare function invertSkewbMove(move: SkewbMove): SkewbMove;
13
+ export declare function invertSkewbAlgorithm(moves: readonly SkewbMove[]): SkewbMove[];
14
+ export declare function parseSkewbMove(value: string): SkewbMove;
15
+ export declare function parseSkewbAlgorithm(algorithm: string): SkewbMove[];
16
+ export declare function formatSkewbAlgorithm(moves: readonly SkewbMove[]): string;
17
+ export declare function getAllSkewbMovesForTables(): readonly string[];
18
+ export { MOVE_TABLES };
19
+ //# sourceMappingURL=moves.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moves.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/moves.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxD,UAAU,SAAS;IACjB,OAAO,EAAE;QAAE,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAC5E,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,QAAA,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAyB1C,CAAC;AAkBF,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,CAS7E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,UAAU,CAE9F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAG1D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAE7E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAGvD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,CAIlE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAExE;AAGD,wBAAgB,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAE7D;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { SKEWB_MOVES } from "./types.js";
2
+ import { cloneSkewbState } from "./state.js";
3
+ const MOVE_TABLES = {
4
+ F: {
5
+ corners: { permutation: [0, 4, 1, 3, 2, 5, 6, 7], orientation: [1, 1, 1, 0, 1, 0, 0, 0] },
6
+ centers: [2, 0, 1, 3, 4, 5],
7
+ },
8
+ D: {
9
+ corners: { permutation: [5, 1, 2, 3, 4, 6, 0, 7], orientation: [2, 0, 0, 0, 2, 2, 2, 0] },
10
+ centers: [0, 2, 3, 1, 4, 5],
11
+ },
12
+ U: {
13
+ corners: { permutation: [0, 2, 7, 3, 4, 5, 6, 1], orientation: [0, 1, 1, 1, 0, 0, 0, 1] },
14
+ centers: [5, 1, 2, 3, 0, 4],
15
+ },
16
+ R: {
17
+ corners: { permutation: [0, 1, 4, 3, 7, 5, 6, 2], orientation: [0, 0, 1, 0, 1, 0, 1, 1] },
18
+ centers: [0, 3, 2, 5, 4, 1],
19
+ },
20
+ L: {
21
+ corners: { permutation: [0, 7, 2, 3, 1, 5, 6, 4], orientation: [0, 1, 0, 0, 1, 1, 0, 1] },
22
+ centers: [0, 1, 4, 2, 3, 5],
23
+ },
24
+ B: {
25
+ corners: { permutation: [0, 1, 2, 6, 4, 3, 5, 7], orientation: [0, 0, 0, 2, 0, 2, 2, 2] },
26
+ centers: [0, 1, 2, 4, 5, 3],
27
+ },
28
+ };
29
+ function applyFaceMove(state, table) {
30
+ const perm = state.corners.permutation;
31
+ const orient = state.corners.orientation;
32
+ const centers = state.centers;
33
+ const newPerm = table.corners.permutation.map((src) => perm[src]);
34
+ const newOrient = table.corners.permutation.map((src, tgt) => (orient[src] + table.corners.orientation[tgt]) % 3);
35
+ const newCenters = table.centers.map((src) => centers[src]);
36
+ for (let i = 0; i < perm.length; i++)
37
+ perm[i] = newPerm[i];
38
+ for (let i = 0; i < orient.length; i++)
39
+ orient[i] = newOrient[i];
40
+ for (let i = 0; i < centers.length; i++)
41
+ centers[i] = newCenters[i];
42
+ }
43
+ export function applySkewbMove(state, move) {
44
+ const face = move[0].toUpperCase();
45
+ const suffix = move.slice(1);
46
+ const table = MOVE_TABLES[face];
47
+ if (!table)
48
+ throw new Error(`Unknown Skewb move: ${move}`);
49
+ const repetitions = suffix === "'" || suffix === "2" ? 2 : 1;
50
+ const next = cloneSkewbState(state);
51
+ for (let i = 0; i < repetitions; i++)
52
+ applyFaceMove(next, table);
53
+ return next;
54
+ }
55
+ export function applySkewbAlgorithm(state, moves) {
56
+ return moves.reduce((current, move) => applySkewbMove(current, move), state);
57
+ }
58
+ export function invertSkewbMove(move) {
59
+ if (move.endsWith("'"))
60
+ return move.slice(0, -1);
61
+ return `${move}'`;
62
+ }
63
+ export function invertSkewbAlgorithm(moves) {
64
+ return [...moves].reverse().map(invertSkewbMove);
65
+ }
66
+ export function parseSkewbMove(value) {
67
+ if (SKEWB_MOVES.includes(value))
68
+ return value;
69
+ throw new Error(`Invalid Skewb move: ${value}`);
70
+ }
71
+ export function parseSkewbAlgorithm(algorithm) {
72
+ const trimmed = algorithm.trim();
73
+ if (trimmed.length === 0)
74
+ return [];
75
+ return trimmed.split(/\s+/).map(parseSkewbMove);
76
+ }
77
+ export function formatSkewbAlgorithm(moves) {
78
+ return moves.join(" ");
79
+ }
80
+ // For internal use by solver (needs all 6 faces for table generation)
81
+ export function getAllSkewbMovesForTables() {
82
+ return ["R", "U", "L", "B", "F", "D"].flatMap((f) => [f, `${f}'`]);
83
+ }
84
+ export { MOVE_TABLES };
@@ -0,0 +1,3 @@
1
+ import type { SkewbRandomStateOptions, SkewbState } from "./types.js";
2
+ export declare function generateRandomSkewbState(options?: SkewbRandomStateOptions): SkewbState;
3
+ //# sourceMappingURL=random-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"random-state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/random-state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMtE,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,uBAA4B,GAAG,UAAU,CAS1F"}
@@ -0,0 +1,27 @@
1
+ import { createRandomSource } from "../../random/index.js";
2
+ import { isAllowedRandomSkewbState } from "./validation.js";
3
+ import { applySkewbMove } from "./moves.js";
4
+ import { createSolvedSkewbState } from "./state.js";
5
+ import { SKEWB_MOVES } from "./types.js";
6
+ export function generateRandomSkewbState(options = {}) {
7
+ const random = createRandomSource(options.seed);
8
+ const rejectTrivial = options.rejectTrivial ?? true;
9
+ for (let attempt = 0; attempt < 100; attempt++) {
10
+ const state = createLegalRandomState(random);
11
+ if (!rejectTrivial || isAllowedRandomSkewbState(state))
12
+ return state;
13
+ }
14
+ throw new Error("Unable to generate a non-trivial random Skewb state.");
15
+ }
16
+ function createLegalRandomState(random) {
17
+ // Generate a random reachable Skewb state via random walk from solved.
18
+ // Skewb has 3,149,280 reachable states with WCA moves (fixed corner).
19
+ // A walk of 30+ moves is sufficient to approach uniform distribution.
20
+ let state = createSolvedSkewbState();
21
+ const walkLength = 30 + random.nextInt(5); // 30-34 moves
22
+ for (let i = 0; i < walkLength; i++) {
23
+ const move = random.choice([...SKEWB_MOVES]);
24
+ state = applySkewbMove(state, move);
25
+ }
26
+ return state;
27
+ }
@@ -0,0 +1,6 @@
1
+ import type { ScrambleGenerator, ScrambleOptions, ScrambleResult } from "../../core/index.js";
2
+ export declare const skewbScrambleGenerator: ScrambleGenerator;
3
+ export declare function generateSkewbScramble(options?: ScrambleOptions & {
4
+ skipValidation?: boolean;
5
+ }): Promise<ScrambleResult>;
6
+ //# sourceMappingURL=scrambler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAO9F,eAAO,MAAM,sBAAsB,EAAE,iBAYpC,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CAiCzB"}