@cubingcenter/scrambler 0.5.3 → 0.6.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.
- package/README.md +24 -9
- package/dist/cli/index.js +0 -0
- package/dist/core/api.d.ts.map +1 -1
- package/dist/core/api.js +11 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.d.ts +4 -2
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +3 -1
- package/dist/puzzles/cube4/random-state.d.ts +16 -0
- package/dist/puzzles/cube4/random-state.d.ts.map +1 -0
- package/dist/puzzles/cube4/random-state.js +76 -0
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts +18 -0
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/browser-loader.js +95 -0
- package/dist/puzzles/cube4/reduction/center1.d.ts +65 -0
- package/dist/puzzles/cube4/reduction/center1.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/center1.js +245 -0
- package/dist/puzzles/cube4/reduction/center2.d.ts +91 -0
- package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/center2.js +449 -0
- package/dist/puzzles/cube4/reduction/center3.d.ts +47 -0
- package/dist/puzzles/cube4/reduction/center3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/center3.js +278 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts +100 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/edge3.js +511 -0
- package/dist/puzzles/cube4/reduction/generated/center1-distance.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center1-manifest.json +46 -0
- package/dist/puzzles/cube4/reduction/generated/center1-move-maps.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center2-ct-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +87 -0
- package/dist/puzzles/cube4/reduction/generated/center2-pruning.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center2-rl-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center3-manifest.json +40 -0
- package/dist/puzzles/cube4/reduction/generated/center3-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center3-pruning.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/edge3-distances.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/edge3-manifest.json +12 -0
- package/dist/puzzles/cube4/reduction/geometry.d.ts +33 -0
- package/dist/puzzles/cube4/reduction/geometry.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/geometry.js +302 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts +17 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/node-loader.js +98 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.d.ts +130 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.js +281 -0
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts +42 -0
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/phase3-search.js +133 -0
- package/dist/puzzles/cube4/reduction/phase3.d.ts +34 -0
- package/dist/puzzles/cube4/reduction/phase3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/phase3.js +83 -0
- package/dist/puzzles/cube4/reduction/phase4.d.ts +35 -0
- package/dist/puzzles/cube4/reduction/phase4.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/phase4.js +82 -0
- package/dist/puzzles/cube4/reduction/solve.d.ts +31 -0
- package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/solve.js +311 -0
- package/dist/puzzles/cube4/scrambler.d.ts +9 -1
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +123 -81
- package/dist/puzzles/cube4/types.d.ts +6 -0
- package/dist/puzzles/cube4/types.d.ts.map +1 -1
- package/dist/puzzles/cube4/validation.d.ts +6 -0
- package/dist/puzzles/cube4/validation.d.ts.map +1 -0
- package/dist/puzzles/cube4/validation.js +91 -0
- package/dist/puzzles/fto/coordinates.d.ts +53 -0
- package/dist/puzzles/fto/coordinates.d.ts.map +1 -0
- package/dist/puzzles/fto/coordinates.js +228 -0
- package/dist/puzzles/fto/facelets.d.ts +6 -0
- package/dist/puzzles/fto/facelets.d.ts.map +1 -0
- package/dist/puzzles/fto/facelets.js +99 -0
- package/dist/puzzles/fto/index.d.ts +12 -0
- package/dist/puzzles/fto/index.d.ts.map +1 -0
- package/dist/puzzles/fto/index.js +13 -0
- package/dist/puzzles/fto/moves.d.ts +12 -0
- package/dist/puzzles/fto/moves.d.ts.map +1 -0
- package/dist/puzzles/fto/moves.js +115 -0
- package/dist/puzzles/fto/random-state.d.ts +17 -0
- package/dist/puzzles/fto/random-state.d.ts.map +1 -0
- package/dist/puzzles/fto/random-state.js +40 -0
- package/dist/puzzles/fto/scrambler.d.ts +6 -0
- package/dist/puzzles/fto/scrambler.d.ts.map +1 -0
- package/dist/puzzles/fto/scrambler.js +49 -0
- package/dist/puzzles/fto/solver/engine.d.ts +18 -0
- package/dist/puzzles/fto/solver/engine.d.ts.map +1 -0
- package/dist/puzzles/fto/solver/engine.js +1168 -0
- package/dist/puzzles/fto/solver/index.d.ts +2 -0
- package/dist/puzzles/fto/solver/index.d.ts.map +1 -0
- package/dist/puzzles/fto/solver/index.js +1 -0
- package/dist/puzzles/fto/state.d.ts +16 -0
- package/dist/puzzles/fto/state.d.ts.map +1 -0
- package/dist/puzzles/fto/state.js +61 -0
- package/dist/puzzles/fto/types.d.ts +32 -0
- package/dist/puzzles/fto/types.d.ts.map +1 -0
- package/dist/puzzles/fto/types.js +46 -0
- package/dist/puzzles/fto/validation.d.ts +19 -0
- package/dist/puzzles/fto/validation.d.ts.map +1 -0
- package/dist/puzzles/fto/validation.js +143 -0
- package/dist/puzzles/index.d.ts +2 -0
- package/dist/puzzles/index.d.ts.map +1 -1
- package/dist/puzzles/index.js +6 -0
- package/dist/puzzles/skewb/index.d.ts +1 -1
- package/dist/puzzles/skewb/index.d.ts.map +1 -1
- package/dist/puzzles/skewb/index.js +1 -1
- package/dist/puzzles/skewb/random-state.d.ts.map +1 -1
- package/dist/puzzles/skewb/random-state.js +4 -1
- package/dist/puzzles/sq1/facelets.d.ts +12 -0
- package/dist/puzzles/sq1/facelets.d.ts.map +1 -0
- package/dist/puzzles/sq1/facelets.js +26 -0
- package/dist/puzzles/sq1/index.d.ts +10 -0
- package/dist/puzzles/sq1/index.d.ts.map +1 -0
- package/dist/puzzles/sq1/index.js +11 -0
- package/dist/puzzles/sq1/moves.d.ts +55 -0
- package/dist/puzzles/sq1/moves.d.ts.map +1 -0
- package/dist/puzzles/sq1/moves.js +220 -0
- package/dist/puzzles/sq1/random-state.d.ts +6 -0
- package/dist/puzzles/sq1/random-state.d.ts.map +1 -0
- package/dist/puzzles/sq1/random-state.js +49 -0
- package/dist/puzzles/sq1/scrambler.d.ts +10 -0
- package/dist/puzzles/sq1/scrambler.d.ts.map +1 -0
- package/dist/puzzles/sq1/scrambler.js +90 -0
- package/dist/puzzles/sq1/solver/browser-loader.d.ts +5 -0
- package/dist/puzzles/sq1/solver/browser-loader.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/browser-loader.js +92 -0
- package/dist/puzzles/sq1/solver/full-cube.d.ts +53 -0
- package/dist/puzzles/sq1/solver/full-cube.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/full-cube.js +281 -0
- package/dist/puzzles/sq1/solver/generated/manifest.json +50 -0
- package/dist/puzzles/sq1/solver/generated/shape-bottom-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-idx.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-prun.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-top-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-twist-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-bottom-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-prun.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-top-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-twist-move.bin +0 -0
- package/dist/puzzles/sq1/solver/index.d.ts +5 -0
- package/dist/puzzles/sq1/solver/index.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/index.js +4 -0
- package/dist/puzzles/sq1/solver/node-loader.d.ts +4 -0
- package/dist/puzzles/sq1/solver/node-loader.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/node-loader.js +113 -0
- package/dist/puzzles/sq1/solver/search.d.ts +27 -0
- package/dist/puzzles/sq1/solver/search.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/search.js +225 -0
- package/dist/puzzles/sq1/solver/shape.d.ts +22 -0
- package/dist/puzzles/sq1/solver/shape.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/shape.js +185 -0
- package/dist/puzzles/sq1/solver/square.d.ts +10 -0
- package/dist/puzzles/sq1/solver/square.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/square.js +90 -0
- package/dist/puzzles/sq1/solver/table-metadata.d.ts +48 -0
- package/dist/puzzles/sq1/solver/table-metadata.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/table-metadata.js +47 -0
- package/dist/puzzles/sq1/solver/tables.d.ts +17 -0
- package/dist/puzzles/sq1/solver/tables.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/tables.js +66 -0
- package/dist/puzzles/sq1/state.d.ts +10 -0
- package/dist/puzzles/sq1/state.d.ts.map +1 -0
- package/dist/puzzles/sq1/state.js +74 -0
- package/dist/puzzles/sq1/types.d.ts +32 -0
- package/dist/puzzles/sq1/types.d.ts.map +1 -0
- package/dist/puzzles/sq1/types.js +1 -0
- package/dist/puzzles/sq1/validation.d.ts +7 -0
- package/dist/puzzles/sq1/validation.d.ts.map +1 -0
- package/dist/puzzles/sq1/validation.js +64 -0
- package/dist/random/prng.d.ts.map +1 -1
- package/dist/random/prng.js +9 -4
- package/dist-cjs/core/api.js +11 -1
- package/dist-cjs/puzzles/cube4/index.js +11 -4
- package/dist-cjs/puzzles/cube4/random-state.js +79 -0
- package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +100 -0
- package/dist-cjs/puzzles/cube4/reduction/center1.js +258 -0
- package/dist-cjs/puzzles/cube4/reduction/center2.js +462 -0
- package/dist-cjs/puzzles/cube4/reduction/center3.js +284 -0
- package/dist-cjs/puzzles/cube4/reduction/edge3.js +522 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center1-distance.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center1-manifest.json +46 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center1-move-maps.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-ct-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +87 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-rl-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center3-manifest.json +40 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center3-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center3-pruning.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/edge3-distances.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/edge3-manifest.json +12 -0
- package/dist-cjs/puzzles/cube4/reduction/geometry.js +308 -0
- package/dist-cjs/puzzles/cube4/reduction/node-loader.js +104 -0
- package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +294 -0
- package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +138 -0
- package/dist-cjs/puzzles/cube4/reduction/phase3.js +86 -0
- package/dist-cjs/puzzles/cube4/reduction/phase4.js +87 -0
- package/dist-cjs/puzzles/cube4/reduction/solve.js +314 -0
- package/dist-cjs/puzzles/cube4/scrambler.js +122 -79
- package/dist-cjs/puzzles/cube4/validation.js +97 -0
- package/dist-cjs/puzzles/fto/coordinates.js +240 -0
- package/dist-cjs/puzzles/fto/facelets.js +104 -0
- package/dist-cjs/puzzles/fto/index.js +68 -0
- package/dist-cjs/puzzles/fto/moves.js +126 -0
- package/dist-cjs/puzzles/fto/random-state.js +43 -0
- package/dist-cjs/puzzles/fto/scrambler.js +53 -0
- package/dist-cjs/puzzles/fto/solver/engine.js +1175 -0
- package/dist-cjs/puzzles/fto/solver/index.js +9 -0
- package/dist-cjs/puzzles/fto/state.js +69 -0
- package/dist-cjs/puzzles/fto/types.js +49 -0
- package/dist-cjs/puzzles/fto/validation.js +147 -0
- package/dist-cjs/puzzles/index.js +7 -1
- package/dist-cjs/puzzles/skewb/index.js +2 -1
- package/dist-cjs/puzzles/skewb/random-state.js +4 -1
- package/dist-cjs/puzzles/sq1/facelets.js +30 -0
- package/dist-cjs/puzzles/sq1/index.js +52 -0
- package/dist-cjs/puzzles/sq1/moves.js +234 -0
- package/dist-cjs/puzzles/sq1/random-state.js +52 -0
- package/dist-cjs/puzzles/sq1/scrambler.js +95 -0
- package/dist-cjs/puzzles/sq1/solver/browser-loader.js +97 -0
- package/dist-cjs/puzzles/sq1/solver/full-cube.js +289 -0
- package/dist-cjs/puzzles/sq1/solver/generated/manifest.json +50 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-bottom-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-idx.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-prun.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-top-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-twist-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-bottom-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-prun.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-top-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-twist-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/index.js +18 -0
- package/dist-cjs/puzzles/sq1/solver/node-loader.js +120 -0
- package/dist-cjs/puzzles/sq1/solver/search.js +229 -0
- package/dist-cjs/puzzles/sq1/solver/shape.js +191 -0
- package/dist-cjs/puzzles/sq1/solver/square.js +93 -0
- package/dist-cjs/puzzles/sq1/solver/table-metadata.js +50 -0
- package/dist-cjs/puzzles/sq1/solver/tables.js +106 -0
- package/dist-cjs/puzzles/sq1/state.js +81 -0
- package/dist-cjs/puzzles/sq1/types.js +2 -0
- package/dist-cjs/puzzles/sq1/validation.js +68 -0
- package/dist-cjs/random/prng.js +9 -4
- package/package.json +43 -14
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { cloneSquare1State } from "./state.js";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the puzzle is in a state where a slice (/) turn is physically possible.
|
|
4
|
+
* Both top and bottom layers must have clean cuts at 11/0 (Back seam) and 5/6 (Front seam).
|
|
5
|
+
*/
|
|
6
|
+
export function isSliceable(state) {
|
|
7
|
+
// Top layer seam at 11/0
|
|
8
|
+
if (state.top[11].isCorner && state.top[0].isCorner && state.top[11].pieceId === state.top[0].pieceId) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
// Top layer seam at 5/6
|
|
12
|
+
if (state.top[5].isCorner && state.top[6].isCorner && state.top[5].pieceId === state.top[6].pieceId) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
// Bottom layer seam at 11/0
|
|
16
|
+
if (state.bottom[11].isCorner && state.bottom[0].isCorner && state.bottom[11].pieceId === state.bottom[0].pieceId) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
// Bottom layer seam at 5/6
|
|
20
|
+
if (state.bottom[5].isCorner && state.bottom[6].isCorner && state.bottom[5].pieceId === state.bottom[6].pieceId) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Applies a clockwise turn of the top layer by u * 30 degrees (u in range -5..6 or any integer).
|
|
27
|
+
*/
|
|
28
|
+
export function applyTopTurn(state, u) {
|
|
29
|
+
const normU = ((u % 12) + 12) % 12;
|
|
30
|
+
if (normU === 0)
|
|
31
|
+
return cloneSquare1State(state);
|
|
32
|
+
const newTop = Array.from({ length: 12 }, (_, i) => ({
|
|
33
|
+
...state.top[(i - normU + 12) % 12],
|
|
34
|
+
}));
|
|
35
|
+
return {
|
|
36
|
+
top: newTop,
|
|
37
|
+
bottom: state.bottom.map((s) => ({ ...s })),
|
|
38
|
+
middle: state.middle,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Applies a turn of the bottom layer by d * 30 degrees (d in range -5..6 or any integer).
|
|
43
|
+
*/
|
|
44
|
+
export function applyBottomTurn(state, d) {
|
|
45
|
+
const normD = ((d % 12) + 12) % 12;
|
|
46
|
+
if (normD === 0)
|
|
47
|
+
return cloneSquare1State(state);
|
|
48
|
+
const newBottom = Array.from({ length: 12 }, (_, i) => ({
|
|
49
|
+
...state.bottom[(i - normD + 12) % 12],
|
|
50
|
+
}));
|
|
51
|
+
return {
|
|
52
|
+
top: state.top.map((s) => ({ ...s })),
|
|
53
|
+
bottom: newBottom,
|
|
54
|
+
middle: state.middle,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Applies simultaneous top (u) and bottom (d) turns.
|
|
59
|
+
*/
|
|
60
|
+
export function applyTurn(state, u, d) {
|
|
61
|
+
const normU = ((u % 12) + 12) % 12;
|
|
62
|
+
const normD = ((d % 12) + 12) % 12;
|
|
63
|
+
const newTop = normU === 0
|
|
64
|
+
? state.top.map((s) => ({ ...s }))
|
|
65
|
+
: Array.from({ length: 12 }, (_, i) => ({ ...state.top[(i - normU + 12) % 12] }));
|
|
66
|
+
const newBottom = normD === 0
|
|
67
|
+
? state.bottom.map((s) => ({ ...s }))
|
|
68
|
+
: Array.from({ length: 12 }, (_, i) => ({ ...state.bottom[(i - normD + 12) % 12] }));
|
|
69
|
+
return {
|
|
70
|
+
top: newTop,
|
|
71
|
+
bottom: newBottom,
|
|
72
|
+
middle: state.middle,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Applies a slice (/) move, swapping the right half of top (slots 6..11)
|
|
77
|
+
* with the right half of bottom (slots 0..5).
|
|
78
|
+
*/
|
|
79
|
+
export function applySlice(state) {
|
|
80
|
+
if (!isSliceable(state)) {
|
|
81
|
+
throw new Error("Square-1: cannot slice non-sliceable state (corner cuts across seam)");
|
|
82
|
+
}
|
|
83
|
+
const next = cloneSquare1State(state);
|
|
84
|
+
for (let k = 0; k < 6; k++) {
|
|
85
|
+
const topSlot = 6 + k;
|
|
86
|
+
const bottomSlot = k;
|
|
87
|
+
const pieceFromBottom = { ...state.bottom[bottomSlot] };
|
|
88
|
+
const pieceFromTop = { ...state.top[topSlot] };
|
|
89
|
+
next.top[topSlot] = pieceFromBottom;
|
|
90
|
+
next.bottom[bottomSlot] = pieceFromTop;
|
|
91
|
+
}
|
|
92
|
+
next.middle = 1 - next.middle;
|
|
93
|
+
return next;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns all (u, d) turns from the current state that lead to a sliceable state.
|
|
97
|
+
* u and d are within range [-5, 6].
|
|
98
|
+
*/
|
|
99
|
+
export function getValidTurns(state) {
|
|
100
|
+
const valid = [];
|
|
101
|
+
for (let u = -5; u <= 6; u++) {
|
|
102
|
+
for (let d = -5; d <= 6; d++) {
|
|
103
|
+
const turned = applyTurn(state, u, d);
|
|
104
|
+
if (isSliceable(turned)) {
|
|
105
|
+
valid.push([u, d]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return valid;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Parses a Square-1 algorithm string into individual move tokens.
|
|
113
|
+
* Supported tokens: "/", "(u, d)", "(u, d) /", etc.
|
|
114
|
+
*/
|
|
115
|
+
export function parseSquare1Algorithm(alg) {
|
|
116
|
+
if (!alg)
|
|
117
|
+
return [];
|
|
118
|
+
const trimmed = alg.trim();
|
|
119
|
+
if (!trimmed)
|
|
120
|
+
return [];
|
|
121
|
+
// Match (u, d) or /
|
|
122
|
+
const regex = /(\/\s*|\(\s*-?\d+\s*,\s*-?\d+\s*\)\s*)/g;
|
|
123
|
+
const tokens = [];
|
|
124
|
+
let match;
|
|
125
|
+
while ((match = regex.exec(trimmed)) !== null) {
|
|
126
|
+
const token = match[1].trim();
|
|
127
|
+
if (token) {
|
|
128
|
+
tokens.push(token);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (tokens.length === 0) {
|
|
132
|
+
return trimmed.split(/\s+/);
|
|
133
|
+
}
|
|
134
|
+
return tokens;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Formats an array of Square-1 move tokens into standard WCA notation.
|
|
138
|
+
*/
|
|
139
|
+
export function formatSquare1Algorithm(moves) {
|
|
140
|
+
return moves.join(" ").replace(/\s*\/\s*/g, " / ").replace(/\s+/g, " ").trim();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Applies a single move token to the Square-1 state.
|
|
144
|
+
* Token can be "/", "(u, d)", or "(u, d) /".
|
|
145
|
+
*/
|
|
146
|
+
export function applySquare1Move(state, move) {
|
|
147
|
+
const clean = move.trim();
|
|
148
|
+
if (!clean)
|
|
149
|
+
return state;
|
|
150
|
+
if (clean === "/") {
|
|
151
|
+
return applySlice(state);
|
|
152
|
+
}
|
|
153
|
+
// Check if it's (u, d) or (u, d) /
|
|
154
|
+
const turnMatch = clean.match(/^\(\s*(-?\d+)\s*,\s*(-?\d+)\s*\)(\s*\/)?$/);
|
|
155
|
+
if (turnMatch) {
|
|
156
|
+
const u = parseInt(turnMatch[1], 10);
|
|
157
|
+
const d = parseInt(turnMatch[2], 10);
|
|
158
|
+
let s = applyTurn(state, u, d);
|
|
159
|
+
if (turnMatch[3]) {
|
|
160
|
+
s = applySlice(s);
|
|
161
|
+
}
|
|
162
|
+
return s;
|
|
163
|
+
}
|
|
164
|
+
throw new Error(`Square-1: unrecognized move '${move}'`);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Applies a full algorithm to a Square-1 state.
|
|
168
|
+
*/
|
|
169
|
+
export function applySquare1Algorithm(state, alg) {
|
|
170
|
+
const moves = Array.isArray(alg) ? alg : parseSquare1Algorithm(alg);
|
|
171
|
+
let current = state;
|
|
172
|
+
for (const move of moves) {
|
|
173
|
+
current = applySquare1Move(current, move);
|
|
174
|
+
}
|
|
175
|
+
return current;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Inverts a single Square-1 move token.
|
|
179
|
+
*/
|
|
180
|
+
export function invertSquare1Move(move) {
|
|
181
|
+
const clean = move.trim();
|
|
182
|
+
if (!clean || clean === "/")
|
|
183
|
+
return clean;
|
|
184
|
+
const turnMatch = clean.match(/^\(?\s*(-?\d+)\s*,\s*(-?\d+)\s*\)?(\s*\/)?$/);
|
|
185
|
+
if (turnMatch) {
|
|
186
|
+
const u = parseInt(turnMatch[1], 10);
|
|
187
|
+
const d = parseInt(turnMatch[2], 10);
|
|
188
|
+
const invU = u === 0 ? 0 : ((-u % 12) + 12) % 12 > 6 ? (((-u % 12) + 12) % 12) - 12 : ((-u % 12) + 12) % 12;
|
|
189
|
+
const invD = d === 0 ? 0 : ((-d % 12) + 12) % 12 > 6 ? (((-d % 12) + 12) % 12) - 12 : ((-d % 12) + 12) % 12;
|
|
190
|
+
return turnMatch[3] ? `/ (${invU}, ${invD})` : `(${invU}, ${invD})`;
|
|
191
|
+
}
|
|
192
|
+
return clean;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Inverts an entire Square-1 algorithm sequence.
|
|
196
|
+
*/
|
|
197
|
+
export function invertSquare1Algorithm(alg) {
|
|
198
|
+
const moves = Array.isArray(alg) ? alg : parseSquare1Algorithm(alg);
|
|
199
|
+
const inverted = [];
|
|
200
|
+
for (let i = moves.length - 1; i >= 0; i--) {
|
|
201
|
+
const m = moves[i].trim();
|
|
202
|
+
if (m === "/") {
|
|
203
|
+
inverted.push("/");
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const turnMatch = m.match(/^\(?\s*(-?\d+)\s*,\s*(-?\d+)\s*\)?(\s*\/)?$/);
|
|
207
|
+
if (turnMatch) {
|
|
208
|
+
const u = parseInt(turnMatch[1], 10);
|
|
209
|
+
const d = parseInt(turnMatch[2], 10);
|
|
210
|
+
const invU = u === 0 ? 0 : ((-u % 12) + 12) % 12 > 6 ? (((-u % 12) + 12) % 12) - 12 : ((-u % 12) + 12) % 12;
|
|
211
|
+
const invD = d === 0 ? 0 : ((-d % 12) + 12) % 12 > 6 ? (((-d % 12) + 12) % 12) - 12 : ((-d % 12) + 12) % 12;
|
|
212
|
+
if (turnMatch[3]) {
|
|
213
|
+
inverted.push("/");
|
|
214
|
+
}
|
|
215
|
+
inverted.push(`(${invU}, ${invD})`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return inverted;
|
|
220
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Square1RandomStateOptions, Square1State } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Samples an exact uniform random legal state for Square-1.
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateRandomSquare1State(options?: Square1RandomStateOptions): Square1State;
|
|
6
|
+
//# sourceMappingURL=random-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random-state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/sq1/random-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAU1E;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,yBAA8B,GACtC,YAAY,CAgDd"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createRandomSource } from "../../random/index.js";
|
|
2
|
+
import { FullCube, Square1Searcher, INVERSE_SOLUTION, getSquare1SolverTablesSync } from "./solver/index.js";
|
|
3
|
+
import { createSolvedSquare1State, isSolvedSquare1State } from "./state.js";
|
|
4
|
+
import { applySquare1Algorithm } from "./moves.js";
|
|
5
|
+
/**
|
|
6
|
+
* Samples an exact uniform random legal state for Square-1.
|
|
7
|
+
*/
|
|
8
|
+
export function generateRandomSquare1State(options = {}) {
|
|
9
|
+
const random = createRandomSource(options.seed);
|
|
10
|
+
const rejectTrivial = options.rejectTrivial ?? true;
|
|
11
|
+
const tables = getSquare1SolverTablesSync();
|
|
12
|
+
const searcher = new Square1Searcher(tables);
|
|
13
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
14
|
+
const shapeIdx = tables.shapeIdx[random.nextInt(3678)];
|
|
15
|
+
const cube = new FullCube();
|
|
16
|
+
let corner = (0x01234567 << 1) | 0x11111111;
|
|
17
|
+
let edge = 0x01234567 << 1;
|
|
18
|
+
let n_corner = 8;
|
|
19
|
+
let n_edge = 8;
|
|
20
|
+
for (let i = 0; i < 24; i++) {
|
|
21
|
+
if (((shapeIdx >> i) & 1) === 0) {
|
|
22
|
+
// edge
|
|
23
|
+
const rnd = random.nextInt(n_edge) << 2;
|
|
24
|
+
cube.setPiece(23 - i, (edge >> rnd) & 0xf);
|
|
25
|
+
const m = (1 << rnd) - 1;
|
|
26
|
+
edge = (edge & m) + ((edge >> 4) & ~m);
|
|
27
|
+
n_edge--;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// corner
|
|
31
|
+
const rnd = random.nextInt(n_corner) << 2;
|
|
32
|
+
cube.setPiece(23 - i, (corner >> rnd) & 0xf);
|
|
33
|
+
cube.setPiece(22 - i, (corner >> rnd) & 0xf);
|
|
34
|
+
const m = (1 << rnd) - 1;
|
|
35
|
+
corner = (corner & m) + ((corner >> 4) & ~m);
|
|
36
|
+
n_corner--;
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
cube.ml = random.nextInt(2);
|
|
41
|
+
const sol = searcher.solution(cube, INVERSE_SOLUTION);
|
|
42
|
+
const state = applySquare1Algorithm(createSolvedSquare1State(), sol.moves);
|
|
43
|
+
if (rejectTrivial && isSolvedSquare1State(state)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
return state;
|
|
47
|
+
}
|
|
48
|
+
throw new Error("Unable to generate a non-trivial random Square-1 state.");
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ScrambleGenerator, ScrambleOptions, ScrambleResult } from "../../core/index.js";
|
|
2
|
+
import type { Square1RandomStateOptions } from "./types.js";
|
|
3
|
+
export declare const sq1ScrambleGenerator: ScrambleGenerator;
|
|
4
|
+
export declare function generateSquare1Scramble(options?: ScrambleOptions & Square1RandomStateOptions & {
|
|
5
|
+
skipValidation?: boolean;
|
|
6
|
+
}): Promise<ScrambleResult>;
|
|
7
|
+
export declare function generateSquare1ScrambleSync(options?: ScrambleOptions & Square1RandomStateOptions & {
|
|
8
|
+
skipValidation?: boolean;
|
|
9
|
+
}): ScrambleResult;
|
|
10
|
+
//# sourceMappingURL=scrambler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/sq1/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,EACf,MAAM,qBAAqB,CAAC;AAoB7B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,eAAO,MAAM,oBAAoB,EAAE,iBAalC,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,eAAe,GAAG,yBAAyB,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACvF,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,eAAe,GAAG,yBAAyB,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACvF,cAAc,CA2EhB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createRandomSource } from "../../random/index.js";
|
|
2
|
+
import { Square1Searcher, INVERSE_SOLUTION, FullCube, areSquare1TablesLoaded, ensureSquare1TablesLoaded, getSquare1SolverTablesSync } from "./solver/index.js";
|
|
3
|
+
import { createSolvedSquare1State, isSolvedSquare1State } from "./state.js";
|
|
4
|
+
import { applySquare1Algorithm, invertSquare1Algorithm } from "./moves.js";
|
|
5
|
+
import { toSquare1Facelets, formatSquare1Facelets } from "./facelets.js";
|
|
6
|
+
export const sq1ScrambleGenerator = {
|
|
7
|
+
info: {
|
|
8
|
+
eventId: "sq1",
|
|
9
|
+
name: "Square-1",
|
|
10
|
+
puzzle: "square1",
|
|
11
|
+
quality: "random-state",
|
|
12
|
+
generator: "sq1-two-phase",
|
|
13
|
+
description: "Random-state Square-1 scramble generated by a two-phase reduction solver."
|
|
14
|
+
},
|
|
15
|
+
generate(options = {}) {
|
|
16
|
+
return generateSquare1Scramble(options);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export async function generateSquare1Scramble(options = {}) {
|
|
20
|
+
if (!areSquare1TablesLoaded()) {
|
|
21
|
+
await ensureSquare1TablesLoaded();
|
|
22
|
+
}
|
|
23
|
+
return generateSquare1ScrambleSync(options);
|
|
24
|
+
}
|
|
25
|
+
export function generateSquare1ScrambleSync(options = {}) {
|
|
26
|
+
const tables = getSquare1SolverTablesSync();
|
|
27
|
+
const searcher = new Square1Searcher(tables);
|
|
28
|
+
const random = createRandomSource(options.seed);
|
|
29
|
+
const rejectTrivial = options.rejectTrivial ?? true;
|
|
30
|
+
let scramble = "";
|
|
31
|
+
let moves = [];
|
|
32
|
+
let state = createSolvedSquare1State();
|
|
33
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
34
|
+
const shapeIdx = tables.shapeIdx[random.nextInt(3678)];
|
|
35
|
+
const cube = new FullCube();
|
|
36
|
+
let corner = (0x01234567 << 1) | 0x11111111;
|
|
37
|
+
let edge = 0x01234567 << 1;
|
|
38
|
+
let n_corner = 8;
|
|
39
|
+
let n_edge = 8;
|
|
40
|
+
for (let idx = 0; idx < 24; idx++) {
|
|
41
|
+
if (((shapeIdx >> idx) & 1) === 0) {
|
|
42
|
+
const rnd = random.nextInt(n_edge) << 2;
|
|
43
|
+
cube.setPiece(23 - idx, (edge >> rnd) & 0xf);
|
|
44
|
+
const m = (1 << rnd) - 1;
|
|
45
|
+
edge = (edge & m) + ((edge >> 4) & ~m);
|
|
46
|
+
n_edge--;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const rnd = random.nextInt(n_corner) << 2;
|
|
50
|
+
cube.setPiece(23 - idx, (corner >> rnd) & 0xf);
|
|
51
|
+
cube.setPiece(22 - idx, (corner >> rnd) & 0xf);
|
|
52
|
+
const m = (1 << rnd) - 1;
|
|
53
|
+
corner = (corner & m) + ((corner >> 4) & ~m);
|
|
54
|
+
n_corner--;
|
|
55
|
+
idx++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
cube.ml = random.nextInt(2);
|
|
59
|
+
const sol = searcher.solution(cube, INVERSE_SOLUTION);
|
|
60
|
+
moves = sol.moves;
|
|
61
|
+
scramble = sol.scramble;
|
|
62
|
+
state = applySquare1Algorithm(createSolvedSquare1State(), moves);
|
|
63
|
+
if (rejectTrivial && isSolvedSquare1State(state)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
const solutionMoves = invertSquare1Algorithm(moves);
|
|
69
|
+
const facelets = toSquare1Facelets(state);
|
|
70
|
+
const faceletString = formatSquare1Facelets(facelets);
|
|
71
|
+
const result = {
|
|
72
|
+
eventId: "sq1",
|
|
73
|
+
scramble,
|
|
74
|
+
moves,
|
|
75
|
+
quality: "random-state",
|
|
76
|
+
generator: "sq1-two-phase",
|
|
77
|
+
metadata: {
|
|
78
|
+
totalSlashes: moves.filter((m) => m === "/").length,
|
|
79
|
+
solutionDepth: solutionMoves.filter((m) => m === "/").length,
|
|
80
|
+
solutionMoves,
|
|
81
|
+
state,
|
|
82
|
+
facelets,
|
|
83
|
+
faceletString
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
if (options.seed !== undefined) {
|
|
87
|
+
result.seed = options.seed;
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Square1SolverTables } from "./tables.js";
|
|
2
|
+
export declare function getCachedBrowserTables(): Square1SolverTables | undefined;
|
|
3
|
+
export declare function clearCachedBrowserTables(): void;
|
|
4
|
+
export declare function loadBrowserTables(baseUrl?: string): Promise<Square1SolverTables>;
|
|
5
|
+
//# sourceMappingURL=browser-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/sq1/solver/browser-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAMvD,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,SAAS,CAExE;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,wBAAsB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA2CtF"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { SQ1_SOLVER_TABLE_METADATA } from "./table-metadata.js";
|
|
2
|
+
import { fetchTableBuffer } from "../../shared/compressed-fetch.js";
|
|
3
|
+
const TABLES_DIR = "puzzles/sq1/solver/generated";
|
|
4
|
+
let cachedBrowserTables;
|
|
5
|
+
export function getCachedBrowserTables() {
|
|
6
|
+
return cachedBrowserTables;
|
|
7
|
+
}
|
|
8
|
+
export function clearCachedBrowserTables() {
|
|
9
|
+
cachedBrowserTables = undefined;
|
|
10
|
+
}
|
|
11
|
+
export async function loadBrowserTables(baseUrl) {
|
|
12
|
+
if (cachedBrowserTables) {
|
|
13
|
+
return cachedBrowserTables;
|
|
14
|
+
}
|
|
15
|
+
const resolved = resolveBaseUrl(baseUrl);
|
|
16
|
+
const manifest = await fetchManifest(resolved);
|
|
17
|
+
const [shapeIdx, shapePrun, shapeTopMove, shapeBottomMove, shapeTwistMove, squareTwistMove, squareTopMove, squareBottomMove, squarePrun] = await Promise.all([
|
|
18
|
+
fetchInt32Table(resolved, manifest.files.shapeIdx, SQ1_SOLVER_TABLE_METADATA.shapeIdx.entries),
|
|
19
|
+
fetchInt8Table(resolved, manifest.files.shapePrun, SQ1_SOLVER_TABLE_METADATA.shapePrun.entries),
|
|
20
|
+
fetchInt32Table(resolved, manifest.files.shapeTopMove, SQ1_SOLVER_TABLE_METADATA.shapeTopMove.entries),
|
|
21
|
+
fetchInt32Table(resolved, manifest.files.shapeBottomMove, SQ1_SOLVER_TABLE_METADATA.shapeBottomMove.entries),
|
|
22
|
+
fetchInt32Table(resolved, manifest.files.shapeTwistMove, SQ1_SOLVER_TABLE_METADATA.shapeTwistMove.entries),
|
|
23
|
+
fetchUint16Table(resolved, manifest.files.squareTwistMove, SQ1_SOLVER_TABLE_METADATA.squareTwistMove.entries),
|
|
24
|
+
fetchUint16Table(resolved, manifest.files.squareTopMove, SQ1_SOLVER_TABLE_METADATA.squareTopMove.entries),
|
|
25
|
+
fetchUint16Table(resolved, manifest.files.squareBottomMove, SQ1_SOLVER_TABLE_METADATA.squareBottomMove.entries),
|
|
26
|
+
fetchInt8Table(resolved, manifest.files.squarePrun, SQ1_SOLVER_TABLE_METADATA.squarePrun.entries),
|
|
27
|
+
]);
|
|
28
|
+
cachedBrowserTables = {
|
|
29
|
+
shapeIdx,
|
|
30
|
+
shapePrun,
|
|
31
|
+
shapeTopMove,
|
|
32
|
+
shapeBottomMove,
|
|
33
|
+
shapeTwistMove,
|
|
34
|
+
squareTwistMove,
|
|
35
|
+
squareTopMove,
|
|
36
|
+
squareBottomMove,
|
|
37
|
+
squarePrun
|
|
38
|
+
};
|
|
39
|
+
return cachedBrowserTables;
|
|
40
|
+
}
|
|
41
|
+
function resolveBaseUrl(provided) {
|
|
42
|
+
if (provided) {
|
|
43
|
+
return provided.replace(/\/$/, "");
|
|
44
|
+
}
|
|
45
|
+
if (typeof document !== "undefined") {
|
|
46
|
+
const script = document.currentScript;
|
|
47
|
+
if (script?.src) {
|
|
48
|
+
const base = new URL(".", script.src).href;
|
|
49
|
+
return base.replace(/\/$/, "");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return ".";
|
|
53
|
+
}
|
|
54
|
+
async function fetchManifest(baseUrl) {
|
|
55
|
+
const url = `${baseUrl}/${TABLES_DIR}/manifest.json`;
|
|
56
|
+
const response = await fetch(url);
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
throw new Error(`Failed to load Square-1 solver table manifest from ${url}: ${response.status} ${response.statusText}`);
|
|
59
|
+
}
|
|
60
|
+
return (await response.json());
|
|
61
|
+
}
|
|
62
|
+
async function fetchInt32Table(baseUrl, entry, expectedEntries) {
|
|
63
|
+
const buffer = await fetchTableBuffer(baseUrl, TABLES_DIR, entry.file, { compressed: entry.compressed !== false });
|
|
64
|
+
if (buffer.byteLength !== expectedEntries * 4) {
|
|
65
|
+
throw new Error(`Invalid byte size for ${entry.file}`);
|
|
66
|
+
}
|
|
67
|
+
const values = new Int32Array(expectedEntries);
|
|
68
|
+
const view = new DataView(buffer);
|
|
69
|
+
for (let i = 0; i < values.length; i++) {
|
|
70
|
+
values[i] = view.getInt32(i * 4, true);
|
|
71
|
+
}
|
|
72
|
+
return values;
|
|
73
|
+
}
|
|
74
|
+
async function fetchUint16Table(baseUrl, entry, expectedEntries) {
|
|
75
|
+
const buffer = await fetchTableBuffer(baseUrl, TABLES_DIR, entry.file, { compressed: entry.compressed !== false });
|
|
76
|
+
if (buffer.byteLength !== expectedEntries * 2) {
|
|
77
|
+
throw new Error(`Invalid byte size for ${entry.file}`);
|
|
78
|
+
}
|
|
79
|
+
const values = new Uint16Array(expectedEntries);
|
|
80
|
+
const view = new DataView(buffer);
|
|
81
|
+
for (let i = 0; i < values.length; i++) {
|
|
82
|
+
values[i] = view.getUint16(i * 2, true);
|
|
83
|
+
}
|
|
84
|
+
return values;
|
|
85
|
+
}
|
|
86
|
+
async function fetchInt8Table(baseUrl, entry, expectedEntries) {
|
|
87
|
+
const buffer = await fetchTableBuffer(baseUrl, TABLES_DIR, entry.file, { compressed: entry.compressed !== false });
|
|
88
|
+
if (buffer.byteLength !== expectedEntries) {
|
|
89
|
+
throw new Error(`Invalid byte size for ${entry.file}`);
|
|
90
|
+
}
|
|
91
|
+
return new Int8Array(buffer);
|
|
92
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Square1State } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Low-level bitwise representation of Square-1 state.
|
|
4
|
+
*
|
|
5
|
+
* Each layer is split into left and right 6-slot halves (24 bits per half, 4 bits per slot):
|
|
6
|
+
* - `ul`: top left (slots 0..5)
|
|
7
|
+
* - `ur`: top right (slots 6..11)
|
|
8
|
+
* - `dl`: bottom right / left (slots 0..5 of bottom)
|
|
9
|
+
* - `dr`: bottom left / right (slots 6..11 of bottom)
|
|
10
|
+
* - `ml`: middle layer state (0 = solved, 1 = flipped)
|
|
11
|
+
*
|
|
12
|
+
* Piece encoding in 4-bit values:
|
|
13
|
+
* - Corners: values with LSB 1 (1, 3, 5, 7, 9, 11, 13, 15) -> pieceId = (val >> 1) in [0..7]
|
|
14
|
+
* - Edges: values with LSB 0 (0, 2, 4, 6, 8, 10, 12, 14) -> pieceId = (val >> 1) + 8 in [8..15]
|
|
15
|
+
*/
|
|
16
|
+
export declare class FullCube {
|
|
17
|
+
ul: number;
|
|
18
|
+
ur: number;
|
|
19
|
+
dl: number;
|
|
20
|
+
dr: number;
|
|
21
|
+
ml: number;
|
|
22
|
+
copy(c: FullCube): void;
|
|
23
|
+
isSolved(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Applies move token:
|
|
26
|
+
* - 0: slice /
|
|
27
|
+
* - >0: top layer turn
|
|
28
|
+
* - <0: bottom layer turn
|
|
29
|
+
*/
|
|
30
|
+
doMove(move: number): void;
|
|
31
|
+
pieceAt(idx: number): number;
|
|
32
|
+
setPiece(idx: number, value: number): void;
|
|
33
|
+
getParity(): number;
|
|
34
|
+
getShapeIdx(shapeIdxTable: Int32Array): number;
|
|
35
|
+
getSquare(): {
|
|
36
|
+
edgeperm: number;
|
|
37
|
+
cornperm: number;
|
|
38
|
+
topEdgeFirst: boolean;
|
|
39
|
+
botEdgeFirst: boolean;
|
|
40
|
+
ml: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export declare function get8Perm(arr: Uint8Array): number;
|
|
44
|
+
export declare function set8Perm(arr: Uint8Array, idx: number): void;
|
|
45
|
+
/**
|
|
46
|
+
* Converts a FullCube instance to a high-level Square1State.
|
|
47
|
+
*/
|
|
48
|
+
export declare function fullCubeToState(cube: FullCube): Square1State;
|
|
49
|
+
/**
|
|
50
|
+
* Converts a high-level Square1State to a FullCube.
|
|
51
|
+
*/
|
|
52
|
+
export declare function stateToFullCube(state: Square1State): FullCube;
|
|
53
|
+
//# sourceMappingURL=full-cube.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-cube.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/sq1/solver/full-cube.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,YAAY,EAAgB,MAAM,aAAa,CAAC;AAG3E;;;;;;;;;;;;;GAaG;AACH,qBAAa,QAAQ;IACnB,EAAE,EAAE,MAAM,CAAY;IACtB,EAAE,EAAE,MAAM,CAAY;IACtB,EAAE,EAAE,MAAM,CAAY;IACtB,EAAE,EAAE,MAAM,CAAY;IACtB,EAAE,EAAE,MAAM,CAAK;IAEf,IAAI,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IAQvB,QAAQ,IAAI,OAAO;IAUnB;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA6B1B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAc5B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAoB1C,SAAS,IAAI,MAAM;IAqBnB,WAAW,CAAC,aAAa,EAAE,UAAU,GAAG,MAAM;IAyB9C,SAAS,IAAI;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,OAAO,CAAC;QACtB,YAAY,EAAE,OAAO,CAAC;QACtB,EAAE,EAAE,MAAM,CAAC;KACZ;CAuBF;AAmBD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAShD;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAY3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,CAkD5D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,QAAQ,CAe7D"}
|