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.
- package/CHANGELOG.md +17 -0
- package/LICENSE +674 -0
- package/NOTICE +11 -0
- package/README.md +49 -0
- package/dist/scramble-core/src/batch.mjs +18 -0
- package/dist/scramble-core/src/generator.d.mts +35 -0
- package/dist/scramble-core/src/generator.mjs +136 -0
- package/dist/scramble-core/src/generators/clock.d.mts +11 -0
- package/dist/scramble-core/src/generators/clock.mjs +32 -0
- package/dist/scramble-core/src/generators/cube-random-turns.d.mts +11 -0
- package/dist/scramble-core/src/generators/cube-random-turns.mjs +54 -0
- package/dist/scramble-core/src/generators/four-by-four.d.mts +14 -0
- package/dist/scramble-core/src/generators/four-by-four.mjs +43 -0
- package/dist/scramble-core/src/generators/megaminx.d.mts +11 -0
- package/dist/scramble-core/src/generators/megaminx.mjs +18 -0
- package/dist/scramble-core/src/generators/pyraminx.d.mts +11 -0
- package/dist/scramble-core/src/generators/pyraminx.mjs +17 -0
- package/dist/scramble-core/src/generators/skewb.d.mts +11 -0
- package/dist/scramble-core/src/generators/skewb.mjs +17 -0
- package/dist/scramble-core/src/generators/square1.d.mts +11 -0
- package/dist/scramble-core/src/generators/square1.mjs +28 -0
- package/dist/scramble-core/src/generators/three-by-three.d.mts +25 -0
- package/dist/scramble-core/src/generators/three-by-three.mjs +85 -0
- package/dist/scramble-core/src/generators/two-by-two.d.mts +11 -0
- package/dist/scramble-core/src/generators/two-by-two.mjs +17 -0
- package/dist/scramble-core/src/random-source.d.mts +7 -0
- package/dist/scramble-core/src/random-source.mjs +8 -0
- package/dist/scramble-core/src/solvers/min2phase/coord-cube.mjs +10 -0
- package/dist/scramble-core/src/solvers/min2phase/cubie-cube.mjs +246 -0
- package/dist/scramble-core/src/solvers/min2phase/engine.mjs +1281 -0
- package/dist/scramble-core/src/solvers/min2phase/search-wca.mjs +21 -0
- package/dist/scramble-core/src/solvers/min2phase/search.mjs +25 -0
- package/dist/scramble-core/src/solvers/min2phase/tools.mjs +169 -0
- package/dist/scramble-core/src/solvers/min2phase/util.mjs +30 -0
- package/dist/scramble-core/src/solvers/pyraminx-solver.d.mts +17 -0
- package/dist/scramble-core/src/solvers/pyraminx-solver.mjs +350 -0
- package/dist/scramble-core/src/solvers/skewb-solver.d.mts +15 -0
- package/dist/scramble-core/src/solvers/skewb-solver.mjs +399 -0
- package/dist/scramble-core/src/solvers/sq12phase/full-cube.mjs +212 -0
- package/dist/scramble-core/src/solvers/sq12phase/search.mjs +520 -0
- package/dist/scramble-core/src/solvers/sq12phase/shape.mjs +214 -0
- package/dist/scramble-core/src/solvers/sq12phase/square.mjs +135 -0
- package/dist/scramble-core/src/solvers/threephase/center.mjs +798 -0
- package/dist/scramble-core/src/solvers/threephase/edge.mjs +632 -0
- package/dist/scramble-core/src/solvers/threephase/full-cube.mjs +554 -0
- package/dist/scramble-core/src/solvers/threephase/search.mjs +262 -0
- package/dist/scramble-core/src/solvers/threephase/tables.mjs +201 -0
- package/dist/scramble-core/src/solvers/two-by-two-solver.d.mts +15 -0
- package/dist/scramble-core/src/solvers/two-by-two-solver.mjs +298 -0
- package/dist/scramble-core.d.mts +15 -0
- package/dist/scramble-core.mjs +15 -0
- package/dist/scramble-image/src/color.d.mts +12 -0
- package/dist/scramble-image/src/color.mjs +11 -0
- package/dist/scramble-image/src/render.d.mts +10 -0
- package/dist/scramble-image/src/render.mjs +71 -0
- package/dist/scramble-image/src/renderers/clock.d.mts +6 -0
- package/dist/scramble-image/src/renderers/clock.mjs +145 -0
- package/dist/scramble-image/src/renderers/cube-isometric.d.mts +8 -0
- package/dist/scramble-image/src/renderers/cube-isometric.mjs +204 -0
- package/dist/scramble-image/src/renderers/cube-net.d.mts +8 -0
- package/dist/scramble-image/src/renderers/cube-net.mjs +52 -0
- package/dist/scramble-image/src/renderers/megaminx-isometric.d.mts +9 -0
- package/dist/scramble-image/src/renderers/megaminx-isometric.mjs +320 -0
- package/dist/scramble-image/src/renderers/megaminx.d.mts +9 -0
- package/dist/scramble-image/src/renderers/megaminx.mjs +173 -0
- package/dist/scramble-image/src/renderers/pyraminx-isometric.d.mts +9 -0
- package/dist/scramble-image/src/renderers/pyraminx-isometric.mjs +185 -0
- package/dist/scramble-image/src/renderers/pyraminx.d.mts +9 -0
- package/dist/scramble-image/src/renderers/pyraminx.mjs +111 -0
- package/dist/scramble-image/src/renderers/skewb-isometric.d.mts +9 -0
- package/dist/scramble-image/src/renderers/skewb-isometric.mjs +233 -0
- package/dist/scramble-image/src/renderers/skewb.d.mts +9 -0
- package/dist/scramble-image/src/renderers/skewb.mjs +187 -0
- package/dist/scramble-image/src/renderers/square1.d.mts +10 -0
- package/dist/scramble-image/src/renderers/square1.mjs +253 -0
- package/dist/scramble-image/src/svg/svg-document.d.mts +6 -0
- package/dist/scramble-image/src/svg/svg-document.mjs +7 -0
- package/dist/scramble-image/src/svg/svg-elements.d.mts +15 -0
- package/dist/scramble-image/src/svg/svg-elements.mjs +25 -0
- package/dist/scramble-image/src/svg/svg-serialize.mjs +29 -0
- package/dist/scramble-image.d.mts +15 -0
- package/dist/scramble-image.mjs +15 -0
- package/dist/scramble-puzzle/src/algorithm.d.mts +8 -0
- package/dist/scramble-puzzle/src/algorithm.mjs +16 -0
- package/dist/scramble-puzzle/src/algorithm2.mjs +16 -0
- package/dist/scramble-puzzle/src/clock/clock-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/clock/clock-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/clock/clock-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/clock/clock-parser.d.mts +18 -0
- package/dist/scramble-puzzle/src/clock/clock-parser.mjs +35 -0
- package/dist/scramble-puzzle/src/clock/clock-parser2.mjs +35 -0
- package/dist/scramble-puzzle/src/clock/clock-state.d.mts +8 -0
- package/dist/scramble-puzzle/src/clock/clock-state.mjs +212 -0
- package/dist/scramble-puzzle/src/clock/clock-state2.d.mts +13 -0
- package/dist/scramble-puzzle/src/clock/clock-state2.mjs +212 -0
- package/dist/scramble-puzzle/src/cube/cube-definition.d.mts +9 -0
- package/dist/scramble-puzzle/src/cube/cube-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/cube/cube-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/cube/cube-move.d.mts +4 -0
- package/dist/scramble-puzzle/src/cube/cube-move2.d.mts +17 -0
- package/dist/scramble-puzzle/src/cube/cube-parser.d.mts +7 -0
- package/dist/scramble-puzzle/src/cube/cube-parser.mjs +60 -0
- package/dist/scramble-puzzle/src/cube/cube-parser2.mjs +60 -0
- package/dist/scramble-puzzle/src/cube/cube-state.d.mts +12 -0
- package/dist/scramble-puzzle/src/cube/cube-state.mjs +187 -0
- package/dist/scramble-puzzle/src/cube/cube-state2.d.mts +15 -0
- package/dist/scramble-puzzle/src/cube/cube-state2.mjs +187 -0
- package/dist/scramble-puzzle/src/errors.d.mts +15 -0
- package/dist/scramble-puzzle/src/errors.mjs +24 -0
- package/dist/scramble-puzzle/src/errors2.mjs +30 -0
- package/dist/scramble-puzzle/src/events.d.mts +5 -0
- package/dist/scramble-puzzle/src/events.mjs +90 -0
- package/dist/scramble-puzzle/src/events2.d.mts +98 -0
- package/dist/scramble-puzzle/src/events2.mjs +109 -0
- package/dist/scramble-puzzle/src/index.mjs +22 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser.d.mts +5 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser.mjs +57 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.d.mts +20 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.mjs +57 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state.d.mts +9 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state.mjs +112 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state2.d.mts +14 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state2.mjs +112 -0
- package/dist/scramble-puzzle/src/puzzle-definition.d.mts +19 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.d.mts +5 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.mjs +34 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.d.mts +21 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.mjs +34 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.d.mts +11 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.mjs +90 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.d.mts +14 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.mjs +90 -0
- package/dist/scramble-puzzle/src/registry.d.mts +11 -0
- package/dist/scramble-puzzle/src/registry.mjs +13 -0
- package/dist/scramble-puzzle/src/skewb/skewb-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/skewb/skewb-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/skewb/skewb-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser.d.mts +5 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser.mjs +33 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser2.d.mts +14 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser2.mjs +33 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state.d.mts +11 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state.mjs +75 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state2.d.mts +14 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state2.mjs +75 -0
- package/dist/scramble-puzzle/src/square1/square1-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/square1/square1-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/square1/square1-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/square1/square1-parser.d.mts +17 -0
- package/dist/scramble-puzzle/src/square1/square1-parser.mjs +43 -0
- package/dist/scramble-puzzle/src/square1/square1-parser2.mjs +47 -0
- package/dist/scramble-puzzle/src/square1/square1-state.d.mts +9 -0
- package/dist/scramble-puzzle/src/square1/square1-state.mjs +115 -0
- package/dist/scramble-puzzle/src/square1/square1-state2.d.mts +21 -0
- package/dist/scramble-puzzle/src/square1/square1-state2.mjs +115 -0
- package/dist/scramble-puzzle.d.mts +25 -0
- package/dist/scramble-puzzle.mjs +23 -0
- package/package.json +37 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
//#region .build/vendor/scramble-core/src/solvers/two-by-two-solver.ts
|
|
2
|
+
const ERROR_PREFIX = "@cubegin/scramble-core";
|
|
3
|
+
const N_PERM = 5040;
|
|
4
|
+
const N_ORIENT = 729;
|
|
5
|
+
const N_MOVES = 9;
|
|
6
|
+
const MAX_LENGTH = 20;
|
|
7
|
+
const MOVE_TO_STRING = [
|
|
8
|
+
"U",
|
|
9
|
+
"U2",
|
|
10
|
+
"U'",
|
|
11
|
+
"R",
|
|
12
|
+
"R2",
|
|
13
|
+
"R'",
|
|
14
|
+
"F",
|
|
15
|
+
"F2",
|
|
16
|
+
"F'"
|
|
17
|
+
];
|
|
18
|
+
const INVERSE_MOVE_TO_STRING = [
|
|
19
|
+
"U'",
|
|
20
|
+
"U2",
|
|
21
|
+
"U",
|
|
22
|
+
"R'",
|
|
23
|
+
"R2",
|
|
24
|
+
"R",
|
|
25
|
+
"F'",
|
|
26
|
+
"F2",
|
|
27
|
+
"F"
|
|
28
|
+
];
|
|
29
|
+
const FACT = [
|
|
30
|
+
1,
|
|
31
|
+
1,
|
|
32
|
+
2,
|
|
33
|
+
6,
|
|
34
|
+
24,
|
|
35
|
+
120,
|
|
36
|
+
720
|
|
37
|
+
];
|
|
38
|
+
const COST_U = 8;
|
|
39
|
+
const COST_U_LOW = 20;
|
|
40
|
+
const COST_U2 = 10;
|
|
41
|
+
const COST_U3 = 7;
|
|
42
|
+
const COST_R = 6;
|
|
43
|
+
const COST_R2 = 10;
|
|
44
|
+
const COST_R3 = 6;
|
|
45
|
+
const COST_F = 10;
|
|
46
|
+
const COST_F2 = 30;
|
|
47
|
+
const COST_F3 = 19;
|
|
48
|
+
const COST_REGRIP = 20;
|
|
49
|
+
let cachedTables;
|
|
50
|
+
const packPerm = (cubies) => {
|
|
51
|
+
let index = 0;
|
|
52
|
+
let value = 106181136;
|
|
53
|
+
for (let position = 0; position < 6; position += 1) {
|
|
54
|
+
const shiftedCubie = (cubies[position] & 7) << 2;
|
|
55
|
+
index = (7 - position) * index + (value >> shiftedCubie & 7);
|
|
56
|
+
value -= 17895696 << shiftedCubie;
|
|
57
|
+
}
|
|
58
|
+
return index;
|
|
59
|
+
};
|
|
60
|
+
const unpackPerm = (permutation, cubies) => {
|
|
61
|
+
let remaining = permutation;
|
|
62
|
+
let value = 106181136;
|
|
63
|
+
for (let position = 0; position < 6; position += 1) {
|
|
64
|
+
const divisor = FACT[6 - position];
|
|
65
|
+
let cubie = Math.floor(remaining / divisor);
|
|
66
|
+
remaining -= cubie * divisor;
|
|
67
|
+
cubie <<= 2;
|
|
68
|
+
cubies[position] = value >> cubie & 7;
|
|
69
|
+
const mask = (1 << cubie) - 1;
|
|
70
|
+
value = (value & mask) + (value >> 4 & ~mask);
|
|
71
|
+
}
|
|
72
|
+
cubies[6] = value;
|
|
73
|
+
};
|
|
74
|
+
const packOrient = (cubies) => {
|
|
75
|
+
let orientation = 0;
|
|
76
|
+
for (let position = 0; position < 6; position += 1) orientation = 3 * orientation + (cubies[position] >> 3);
|
|
77
|
+
return orientation;
|
|
78
|
+
};
|
|
79
|
+
const unpackOrient = (orientation, cubies) => {
|
|
80
|
+
let remaining = orientation;
|
|
81
|
+
let orientationSum = 0;
|
|
82
|
+
for (let position = 5; position >= 0; position -= 1) {
|
|
83
|
+
const cubieOrientation = remaining % 3;
|
|
84
|
+
cubies[position] = cubieOrientation << 3;
|
|
85
|
+
orientationSum += cubieOrientation;
|
|
86
|
+
remaining = Math.floor(remaining / 3);
|
|
87
|
+
}
|
|
88
|
+
cubies[6] = (42424242 - orientationSum) % 3 << 3;
|
|
89
|
+
};
|
|
90
|
+
const cycle = (cubies, first, second, third, fourth, times) => {
|
|
91
|
+
for (let count = 0; count < times; count += 1) {
|
|
92
|
+
const previousFourth = cubies[fourth];
|
|
93
|
+
cubies[fourth] = cubies[third];
|
|
94
|
+
cubies[third] = cubies[second];
|
|
95
|
+
cubies[second] = cubies[first];
|
|
96
|
+
cubies[first] = previousFourth;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const cycleAndOrient = (cubies, first, second, third, fourth, times) => {
|
|
100
|
+
for (let count = 0; count < times; count += 1) {
|
|
101
|
+
const previousFourth = cubies[fourth];
|
|
102
|
+
cubies[fourth] = (cubies[third] + 8) % 24;
|
|
103
|
+
cubies[third] = (cubies[second] + 16) % 24;
|
|
104
|
+
cubies[second] = (cubies[first] + 8) % 24;
|
|
105
|
+
cubies[first] = (previousFourth + 16) % 24;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const moveCubies = (cubies, move) => {
|
|
109
|
+
const face = Math.floor(move / 3);
|
|
110
|
+
const times = move % 3 + 1;
|
|
111
|
+
switch (face) {
|
|
112
|
+
case 0:
|
|
113
|
+
cycle(cubies, 1, 3, 2, 0, times);
|
|
114
|
+
break;
|
|
115
|
+
case 1:
|
|
116
|
+
cycleAndOrient(cubies, 0, 2, 6, 4, times);
|
|
117
|
+
break;
|
|
118
|
+
case 2:
|
|
119
|
+
cycleAndOrient(cubies, 1, 0, 4, 5, times);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const copyCubies = (source, target) => {
|
|
124
|
+
for (let index = 0; index < source.length; index += 1) target[index] = source[index];
|
|
125
|
+
};
|
|
126
|
+
const createMoveTables = () => {
|
|
127
|
+
const movePerm = Array.from({ length: N_PERM }, () => new Uint16Array(N_MOVES));
|
|
128
|
+
const moveOrient = Array.from({ length: N_ORIENT }, () => new Uint16Array(N_MOVES));
|
|
129
|
+
const cubies = Array.from({ length: 7 }, () => 0);
|
|
130
|
+
const movedCubies = Array.from({ length: 7 }, () => 0);
|
|
131
|
+
for (let permutation = 0; permutation < N_PERM; permutation += 1) {
|
|
132
|
+
unpackPerm(permutation, cubies);
|
|
133
|
+
for (let move = 0; move < N_MOVES; move += 1) {
|
|
134
|
+
copyCubies(cubies, movedCubies);
|
|
135
|
+
moveCubies(movedCubies, move);
|
|
136
|
+
movePerm[permutation][move] = packPerm(movedCubies);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (let orientation = 0; orientation < N_ORIENT; orientation += 1) {
|
|
140
|
+
unpackOrient(orientation, cubies);
|
|
141
|
+
for (let move = 0; move < N_MOVES; move += 1) {
|
|
142
|
+
copyCubies(cubies, movedCubies);
|
|
143
|
+
moveCubies(movedCubies, move);
|
|
144
|
+
moveOrient[orientation][move] = packOrient(movedCubies);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
movePerm,
|
|
149
|
+
moveOrient
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const createPruningTable = (size, moves) => {
|
|
153
|
+
const pruning = new Int8Array(size);
|
|
154
|
+
pruning.fill(-1);
|
|
155
|
+
pruning[0] = 0;
|
|
156
|
+
let done = 1;
|
|
157
|
+
for (let length = 0; done < size; length += 1) for (let coordinate = 0; coordinate < size; coordinate += 1) {
|
|
158
|
+
if (pruning[coordinate] !== length) continue;
|
|
159
|
+
for (let move = 0; move < N_MOVES; move += 1) {
|
|
160
|
+
const nextCoordinate = moves[coordinate][move];
|
|
161
|
+
if (pruning[nextCoordinate] !== -1) continue;
|
|
162
|
+
pruning[nextCoordinate] = length + 1;
|
|
163
|
+
done += 1;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return pruning;
|
|
167
|
+
};
|
|
168
|
+
const createTables = () => {
|
|
169
|
+
const { movePerm, moveOrient } = createMoveTables();
|
|
170
|
+
return {
|
|
171
|
+
movePerm,
|
|
172
|
+
moveOrient,
|
|
173
|
+
prunPerm: createPruningTable(N_PERM, movePerm),
|
|
174
|
+
prunOrient: createPruningTable(N_ORIENT, moveOrient)
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
const getTables = () => {
|
|
178
|
+
cachedTables ??= createTables();
|
|
179
|
+
return cachedTables;
|
|
180
|
+
};
|
|
181
|
+
const validateCoordinate = (coordinateName, coordinate, maxExclusive) => {
|
|
182
|
+
if (!Number.isSafeInteger(coordinate) || coordinate < 0 || coordinate >= maxExclusive) throw new RangeError(`${ERROR_PREFIX}: 2x2 ${coordinateName} must be an integer from 0 to ${maxExclusive - 1}`);
|
|
183
|
+
};
|
|
184
|
+
const validateState = (state) => {
|
|
185
|
+
validateCoordinate("permutation", state.permutation, N_PERM);
|
|
186
|
+
validateCoordinate("orientation", state.orientation, N_ORIENT);
|
|
187
|
+
};
|
|
188
|
+
const validateLength = (length) => {
|
|
189
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > MAX_LENGTH) throw new RangeError(`${ERROR_PREFIX}: 2x2 solve length must be an integer from 0 to ${MAX_LENGTH}`);
|
|
190
|
+
};
|
|
191
|
+
const computeCost = (solution, index, currentCost, grip) => {
|
|
192
|
+
if (index < 0) return currentCost;
|
|
193
|
+
switch (solution[index]) {
|
|
194
|
+
case 0: return computeCost(solution, index - 1, currentCost + COST_U3, grip);
|
|
195
|
+
case 1: return computeCost(solution, index - 1, currentCost + COST_U2, grip);
|
|
196
|
+
case 2:
|
|
197
|
+
if (grip === 0) return computeCost(solution, index - 1, currentCost + COST_U, 0);
|
|
198
|
+
if (grip === -1) return Math.min(computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_U, 0), computeCost(solution, index - 1, currentCost + COST_U_LOW, grip));
|
|
199
|
+
return computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_U, 0);
|
|
200
|
+
case 3:
|
|
201
|
+
if (grip > -1) return computeCost(solution, index - 1, currentCost + COST_R3, grip - 1);
|
|
202
|
+
return computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_R3, -1);
|
|
203
|
+
case 4:
|
|
204
|
+
if (grip !== 0) return computeCost(solution, index - 1, currentCost + COST_R2, -grip);
|
|
205
|
+
return Math.min(computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_R2, -1), computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_R2, 1));
|
|
206
|
+
case 5:
|
|
207
|
+
if (grip < 1) return computeCost(solution, index - 1, currentCost + COST_R, grip + 1);
|
|
208
|
+
return computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_R, 1);
|
|
209
|
+
case 6:
|
|
210
|
+
if (grip !== 0) return computeCost(solution, index - 1, currentCost + COST_F3, grip);
|
|
211
|
+
return Math.min(computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_F3, -1), computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_F3, 1));
|
|
212
|
+
case 7:
|
|
213
|
+
if (grip === -1) return computeCost(solution, index - 1, currentCost + COST_F2, -1);
|
|
214
|
+
return computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_F2, -1);
|
|
215
|
+
case 8:
|
|
216
|
+
if (grip === -1) return computeCost(solution, index - 1, currentCost + COST_F, -1);
|
|
217
|
+
return computeCost(solution, index - 1, currentCost + COST_REGRIP + COST_F, -1);
|
|
218
|
+
default: return -1;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const search = ({ permutation, orientation, depth, length, lastMove, solution, bestSolution, tables }) => {
|
|
222
|
+
if (length === 0) {
|
|
223
|
+
if (permutation !== 0 || orientation !== 0) return false;
|
|
224
|
+
const cost = computeCost(solution, depth, 0, 0);
|
|
225
|
+
if (cost < bestSolution[depth]) {
|
|
226
|
+
for (let index = 0; index < depth; index += 1) bestSolution[index] = solution[index];
|
|
227
|
+
bestSolution[depth] = cost;
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
if (tables.prunPerm[permutation] > length || tables.prunOrient[orientation] > length) return false;
|
|
232
|
+
let solutionFound = false;
|
|
233
|
+
for (let move = 0; move < N_MOVES; move += 1) {
|
|
234
|
+
if (Math.floor(move / 3) === Math.floor(lastMove / 3)) continue;
|
|
235
|
+
solution[depth] = move;
|
|
236
|
+
solutionFound = search({
|
|
237
|
+
permutation: tables.movePerm[permutation][move],
|
|
238
|
+
orientation: tables.moveOrient[orientation][move],
|
|
239
|
+
depth: depth + 1,
|
|
240
|
+
length: length - 1,
|
|
241
|
+
lastMove: move,
|
|
242
|
+
solution,
|
|
243
|
+
bestSolution,
|
|
244
|
+
tables
|
|
245
|
+
}) || solutionFound;
|
|
246
|
+
}
|
|
247
|
+
return solutionFound;
|
|
248
|
+
};
|
|
249
|
+
const formatSolution = (solution, length, inverse) => {
|
|
250
|
+
if (length === 0) return "";
|
|
251
|
+
const moves = [];
|
|
252
|
+
if (inverse) for (let index = length - 1; index >= 0; index -= 1) moves.push(INVERSE_MOVE_TO_STRING[solution[index]]);
|
|
253
|
+
else for (let index = 0; index < length; index += 1) moves.push(MOVE_TO_STRING[solution[index]]);
|
|
254
|
+
return moves.join(" ");
|
|
255
|
+
};
|
|
256
|
+
var TwoByTwoSolver = class {
|
|
257
|
+
randomState(random) {
|
|
258
|
+
const state = {
|
|
259
|
+
permutation: random.nextInt(N_PERM),
|
|
260
|
+
orientation: random.nextInt(N_ORIENT)
|
|
261
|
+
};
|
|
262
|
+
validateState(state);
|
|
263
|
+
return state;
|
|
264
|
+
}
|
|
265
|
+
solveIn(state, maxLength) {
|
|
266
|
+
return this.solve(state, maxLength, false, false);
|
|
267
|
+
}
|
|
268
|
+
generateExactly(state, length) {
|
|
269
|
+
const scramble = this.solve(state, length, true, true);
|
|
270
|
+
if (scramble === null) throw new Error(`${ERROR_PREFIX}: could not generate a 2x2 scramble exactly ${length} moves long`);
|
|
271
|
+
return scramble;
|
|
272
|
+
}
|
|
273
|
+
solve(state, desiredLength, exactLength, inverse) {
|
|
274
|
+
validateState(state);
|
|
275
|
+
validateLength(desiredLength);
|
|
276
|
+
const tables = getTables();
|
|
277
|
+
const solution = Array.from({ length: MAX_LENGTH + 1 }, () => 0);
|
|
278
|
+
const bestSolution = Array.from({ length: MAX_LENGTH + 1 }, () => 0);
|
|
279
|
+
let length = exactLength ? desiredLength : 0;
|
|
280
|
+
while (length <= desiredLength) {
|
|
281
|
+
bestSolution[length] = 42424242;
|
|
282
|
+
if (search({
|
|
283
|
+
permutation: state.permutation,
|
|
284
|
+
orientation: state.orientation,
|
|
285
|
+
depth: 0,
|
|
286
|
+
length,
|
|
287
|
+
lastMove: 42,
|
|
288
|
+
solution,
|
|
289
|
+
bestSolution,
|
|
290
|
+
tables
|
|
291
|
+
})) return formatSolution(bestSolution, length, inverse);
|
|
292
|
+
length += 1;
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
//#endregion
|
|
298
|
+
export { TwoByTwoSolver };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RandomSource, createMathRandomSource } from "./scramble-core/src/random-source.mjs";
|
|
2
|
+
import { DefaultScrambleGeneratorOptions, EventScrambleGenerator, GenerateOptions, ScrambleGenerator, ScrambleGeneratorOptions, ScrambleResult, createDefaultScrambleGenerator, createScrambleGenerator } from "./scramble-core/src/generator.mjs";
|
|
3
|
+
import { ClockScrambleOptions, generateClockScramble } from "./scramble-core/src/generators/clock.mjs";
|
|
4
|
+
import { CubeRandomTurnOptions, generateCubeRandomTurnScramble } from "./scramble-core/src/generators/cube-random-turns.mjs";
|
|
5
|
+
import { FourByFourScrambleOptions, generateFourByFourNoInspectionScramble, generateFourByFourScramble } from "./scramble-core/src/generators/four-by-four.mjs";
|
|
6
|
+
import { MegaminxScrambleOptions, generateMegaminxScramble } from "./scramble-core/src/generators/megaminx.mjs";
|
|
7
|
+
import { PyraminxScrambleOptions, generatePyraminxScramble } from "./scramble-core/src/generators/pyraminx.mjs";
|
|
8
|
+
import { SkewbScrambleOptions, generateSkewbScramble } from "./scramble-core/src/generators/skewb.mjs";
|
|
9
|
+
import { SquareOneScrambleOptions, generateSquareOneScramble } from "./scramble-core/src/generators/square1.mjs";
|
|
10
|
+
import { MultiBlindScrambleOptions, ThreeByThreeScrambleOptions, generateMultiBlindScramble, generateThreeByThreeFewestMovesScramble, generateThreeByThreeNoInspectionScramble, generateThreeByThreeScramble } from "./scramble-core/src/generators/three-by-three.mjs";
|
|
11
|
+
import { TwoByTwoScrambleOptions, generateTwoByTwoScramble } from "./scramble-core/src/generators/two-by-two.mjs";
|
|
12
|
+
import { PyraminxSolver, PyraminxSolverState } from "./scramble-core/src/solvers/pyraminx-solver.mjs";
|
|
13
|
+
import { SkewbSolver, SkewbSolverState } from "./scramble-core/src/solvers/skewb-solver.mjs";
|
|
14
|
+
import { TwoByTwoSolver, TwoByTwoState } from "./scramble-core/src/solvers/two-by-two-solver.mjs";
|
|
15
|
+
export { type ClockScrambleOptions, type CubeRandomTurnOptions, type DefaultScrambleGeneratorOptions, type EventScrambleGenerator, type FourByFourScrambleOptions, type GenerateOptions, type MegaminxScrambleOptions, type MultiBlindScrambleOptions, type PyraminxScrambleOptions, PyraminxSolver, type PyraminxSolverState, type RandomSource, type ScrambleGenerator, type ScrambleGeneratorOptions, type ScrambleResult, type SkewbScrambleOptions, SkewbSolver, type SkewbSolverState, type SquareOneScrambleOptions, type ThreeByThreeScrambleOptions, type TwoByTwoScrambleOptions, TwoByTwoSolver, type TwoByTwoState, createDefaultScrambleGenerator, createMathRandomSource, createScrambleGenerator, generateClockScramble, generateCubeRandomTurnScramble, generateFourByFourNoInspectionScramble, generateFourByFourScramble, generateMegaminxScramble, generateMultiBlindScramble, generatePyraminxScramble, generateSkewbScramble, generateSquareOneScramble, generateThreeByThreeFewestMovesScramble, generateThreeByThreeNoInspectionScramble, generateThreeByThreeScramble, generateTwoByTwoScramble };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { generateClockScramble } from "./scramble-core/src/generators/clock.mjs";
|
|
2
|
+
import { generateCubeRandomTurnScramble } from "./scramble-core/src/generators/cube-random-turns.mjs";
|
|
3
|
+
import { generateFourByFourNoInspectionScramble, generateFourByFourScramble } from "./scramble-core/src/generators/four-by-four.mjs";
|
|
4
|
+
import { generateMegaminxScramble } from "./scramble-core/src/generators/megaminx.mjs";
|
|
5
|
+
import { PyraminxSolver } from "./scramble-core/src/solvers/pyraminx-solver.mjs";
|
|
6
|
+
import { generatePyraminxScramble } from "./scramble-core/src/generators/pyraminx.mjs";
|
|
7
|
+
import { SkewbSolver } from "./scramble-core/src/solvers/skewb-solver.mjs";
|
|
8
|
+
import { generateSkewbScramble } from "./scramble-core/src/generators/skewb.mjs";
|
|
9
|
+
import { generateSquareOneScramble } from "./scramble-core/src/generators/square1.mjs";
|
|
10
|
+
import { generateMultiBlindScramble, generateThreeByThreeFewestMovesScramble, generateThreeByThreeNoInspectionScramble, generateThreeByThreeScramble } from "./scramble-core/src/generators/three-by-three.mjs";
|
|
11
|
+
import { TwoByTwoSolver } from "./scramble-core/src/solvers/two-by-two-solver.mjs";
|
|
12
|
+
import { generateTwoByTwoScramble } from "./scramble-core/src/generators/two-by-two.mjs";
|
|
13
|
+
import { createDefaultScrambleGenerator, createScrambleGenerator } from "./scramble-core/src/generator.mjs";
|
|
14
|
+
import { createMathRandomSource } from "./scramble-core/src/random-source.mjs";
|
|
15
|
+
export { PyraminxSolver, SkewbSolver, TwoByTwoSolver, createDefaultScrambleGenerator, createMathRandomSource, createScrambleGenerator, generateClockScramble, generateCubeRandomTurnScramble, generateFourByFourNoInspectionScramble, generateFourByFourScramble, generateMegaminxScramble, generateMultiBlindScramble, generatePyraminxScramble, generateSkewbScramble, generateSquareOneScramble, generateThreeByThreeFewestMovesScramble, generateThreeByThreeNoInspectionScramble, generateThreeByThreeScramble, generateTwoByTwoScramble };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region .build/vendor/scramble-image/src/color.d.ts
|
|
2
|
+
type HexColor = `#${string}`;
|
|
3
|
+
declare const DEFAULT_CUBE_COLORS: Readonly<{
|
|
4
|
+
R: "#ff0000";
|
|
5
|
+
U: "#ffffff";
|
|
6
|
+
F: "#00ff00";
|
|
7
|
+
L: "#ff8000";
|
|
8
|
+
D: "#ffff00";
|
|
9
|
+
B: "#0000ff";
|
|
10
|
+
}>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { DEFAULT_CUBE_COLORS, HexColor };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WcaEventId } from "../../scramble-puzzle/src/events.mjs";
|
|
2
|
+
|
|
3
|
+
//#region .build/vendor/scramble-image/src/render.d.ts
|
|
4
|
+
type ScrambleImageView = 'net' | 'isometric';
|
|
5
|
+
interface ScrambleImageOptions {
|
|
6
|
+
view?: ScrambleImageView;
|
|
7
|
+
}
|
|
8
|
+
declare const renderScrambleImage: (eventId: WcaEventId, scramble: string, options?: ScrambleImageOptions) => string;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { ScrambleImageOptions, ScrambleImageView, renderScrambleImage };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { WCA_EVENT_INFO } from "../../scramble-puzzle/src/events.mjs";
|
|
2
|
+
import { createCubeDefinition } from "../../scramble-puzzle/src/cube/cube-definition.mjs";
|
|
3
|
+
import { createClockDefinition } from "../../scramble-puzzle/src/clock/clock-definition.mjs";
|
|
4
|
+
import { createMegaminxDefinition } from "../../scramble-puzzle/src/megaminx/megaminx-definition.mjs";
|
|
5
|
+
import { createPyraminxDefinition } from "../../scramble-puzzle/src/pyraminx/pyraminx-definition.mjs";
|
|
6
|
+
import { createSkewbDefinition } from "../../scramble-puzzle/src/skewb/skewb-definition.mjs";
|
|
7
|
+
import { createSquareOneDefinition } from "../../scramble-puzzle/src/square1/square1-definition.mjs";
|
|
8
|
+
import "../../scramble-puzzle/src/index.mjs";
|
|
9
|
+
import { renderClockState } from "./renderers/clock.mjs";
|
|
10
|
+
import { renderCubeIsometric } from "./renderers/cube-isometric.mjs";
|
|
11
|
+
import { renderCubeNet } from "./renderers/cube-net.mjs";
|
|
12
|
+
import { renderMegaminxIsometricState } from "./renderers/megaminx-isometric.mjs";
|
|
13
|
+
import { renderMegaminxState } from "./renderers/megaminx.mjs";
|
|
14
|
+
import { renderPyraminxIsometricState } from "./renderers/pyraminx-isometric.mjs";
|
|
15
|
+
import { renderPyraminxState } from "./renderers/pyraminx.mjs";
|
|
16
|
+
import { renderSkewbIsometricState } from "./renderers/skewb-isometric.mjs";
|
|
17
|
+
import { renderSkewbState } from "./renderers/skewb.mjs";
|
|
18
|
+
import { renderSquareOneState } from "./renderers/square1.mjs";
|
|
19
|
+
//#region .build/vendor/scramble-image/src/render.ts
|
|
20
|
+
const CUBE_SIZE_BY_EVENT = {
|
|
21
|
+
"222": 2,
|
|
22
|
+
"333": 3,
|
|
23
|
+
"333bld": 3,
|
|
24
|
+
"333fm": 3,
|
|
25
|
+
"333oh": 3,
|
|
26
|
+
"333mbld": 3,
|
|
27
|
+
"444": 4,
|
|
28
|
+
"444bld": 4,
|
|
29
|
+
"555": 5,
|
|
30
|
+
"555bld": 5,
|
|
31
|
+
"666": 6,
|
|
32
|
+
"777": 7
|
|
33
|
+
};
|
|
34
|
+
const renderScrambleImage = (eventId, scramble, options = {}) => {
|
|
35
|
+
const eventInfo = WCA_EVENT_INFO[eventId];
|
|
36
|
+
const view = options.view ?? "net";
|
|
37
|
+
switch (eventInfo.puzzleId) {
|
|
38
|
+
case "cube": {
|
|
39
|
+
const size = CUBE_SIZE_BY_EVENT[eventId];
|
|
40
|
+
if (!size) throw new Error(`@cubegin/scramble-image: event '${eventId}' is not renderable yet`);
|
|
41
|
+
const cube = createCubeDefinition(size, [eventId]);
|
|
42
|
+
const state = cube.applyAlgorithm(cube.createSolvedState(), scramble);
|
|
43
|
+
return view === "isometric" ? renderCubeIsometric(state) : renderCubeNet(state);
|
|
44
|
+
}
|
|
45
|
+
case "clock": {
|
|
46
|
+
const clock = createClockDefinition();
|
|
47
|
+
return renderClockState(clock.applyAlgorithm(clock.createSolvedState(), scramble));
|
|
48
|
+
}
|
|
49
|
+
case "megaminx": {
|
|
50
|
+
const megaminx = createMegaminxDefinition();
|
|
51
|
+
const state = megaminx.applyAlgorithm(megaminx.createSolvedState(), scramble);
|
|
52
|
+
return view === "isometric" ? renderMegaminxIsometricState(state) : renderMegaminxState(state);
|
|
53
|
+
}
|
|
54
|
+
case "pyraminx": {
|
|
55
|
+
const pyraminx = createPyraminxDefinition();
|
|
56
|
+
const state = pyraminx.applyAlgorithm(pyraminx.createSolvedState(), scramble);
|
|
57
|
+
return view === "isometric" ? renderPyraminxIsometricState(state) : renderPyraminxState(state);
|
|
58
|
+
}
|
|
59
|
+
case "skewb": {
|
|
60
|
+
const skewb = createSkewbDefinition();
|
|
61
|
+
const state = skewb.applyAlgorithm(skewb.createSolvedState(), scramble);
|
|
62
|
+
return view === "isometric" ? renderSkewbIsometricState(state) : renderSkewbState(state);
|
|
63
|
+
}
|
|
64
|
+
case "square1": {
|
|
65
|
+
const squareOne = createSquareOneDefinition();
|
|
66
|
+
return renderSquareOneState(squareOne.applyAlgorithm(squareOne.createSolvedState(), scramble));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
export { renderScrambleImage };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { createSvgDocument } from "../svg/svg-document.mjs";
|
|
2
|
+
import { circle, group, path } from "../svg/svg-elements.mjs";
|
|
3
|
+
//#region .build/vendor/scramble-image/src/renderers/clock.ts
|
|
4
|
+
const RADIUS = 70;
|
|
5
|
+
const CLOCK_RADIUS = 14;
|
|
6
|
+
const CLOCK_OUTER_RADIUS = 21;
|
|
7
|
+
const POINT_RADIUS = (CLOCK_RADIUS + CLOCK_OUTER_RADIUS) / 2;
|
|
8
|
+
const TICK_MARK_RADIUS = 1;
|
|
9
|
+
const TOP_TICK_MARK_RADIUS = 2;
|
|
10
|
+
const ARROW_HEIGHT = 10;
|
|
11
|
+
const ARROW_RADIUS = 2;
|
|
12
|
+
const PIN_RADIUS = 4;
|
|
13
|
+
const GAP = 5;
|
|
14
|
+
const WIDTH = 4 * (RADIUS + GAP);
|
|
15
|
+
const HEIGHT = 2 * (RADIUS + GAP);
|
|
16
|
+
const ARROW_ANGLE = Math.PI / 2 - Math.acos(ARROW_RADIUS / ARROW_HEIGHT);
|
|
17
|
+
const COLORS = {
|
|
18
|
+
front: "#113366",
|
|
19
|
+
frontClock: "#ccddee",
|
|
20
|
+
frontTopClock: "#ffcc44",
|
|
21
|
+
frontHand: "#113366",
|
|
22
|
+
frontPin: "#88aacc",
|
|
23
|
+
back: "#ccddee",
|
|
24
|
+
backClock: "#113366",
|
|
25
|
+
backTopClock: "#cc6600",
|
|
26
|
+
backHand: "#ccddee",
|
|
27
|
+
backPin: "#446699",
|
|
28
|
+
stroke: "#000000"
|
|
29
|
+
};
|
|
30
|
+
const frontColors = {
|
|
31
|
+
body: COLORS.front,
|
|
32
|
+
clock: COLORS.frontClock,
|
|
33
|
+
topClock: COLORS.frontTopClock,
|
|
34
|
+
hand: COLORS.frontHand,
|
|
35
|
+
pin: COLORS.frontPin
|
|
36
|
+
};
|
|
37
|
+
const backColors = {
|
|
38
|
+
body: COLORS.back,
|
|
39
|
+
clock: COLORS.backClock,
|
|
40
|
+
topClock: COLORS.backTopClock,
|
|
41
|
+
hand: COLORS.backHand,
|
|
42
|
+
pin: COLORS.backPin
|
|
43
|
+
};
|
|
44
|
+
const translate = (x, y) => `translate(${x} ${y})`;
|
|
45
|
+
const clockCenter = (sideIndex, clockIndex) => {
|
|
46
|
+
const sideCenterX = (sideIndex * 2 + 1) * (RADIUS + GAP);
|
|
47
|
+
const sideCenterY = RADIUS + GAP;
|
|
48
|
+
return [sideCenterX + 2 * (clockIndex % 3 - 1) * CLOCK_OUTER_RADIUS, sideCenterY + 2 * (Math.floor(clockIndex / 3) - 1) * CLOCK_OUTER_RADIUS];
|
|
49
|
+
};
|
|
50
|
+
const handPath = () => {
|
|
51
|
+
const x = ARROW_RADIUS * Math.cos(ARROW_ANGLE);
|
|
52
|
+
const y = -ARROW_RADIUS * Math.sin(ARROW_ANGLE);
|
|
53
|
+
return `M 0 0 L ${x} ${y} L 0 ${-ARROW_HEIGHT} L ${-x} ${y} Z`;
|
|
54
|
+
};
|
|
55
|
+
const sideColorFor = (sideIndex, rightSideUp) => {
|
|
56
|
+
if (sideIndex === 0) return rightSideUp ? frontColors : backColors;
|
|
57
|
+
return rightSideUp ? backColors : frontColors;
|
|
58
|
+
};
|
|
59
|
+
const handColorForClock = (clockIndex, rightSideUp) => {
|
|
60
|
+
return clockIndex < 9 !== rightSideUp ? backColors : frontColors;
|
|
61
|
+
};
|
|
62
|
+
const drawSideBackground = (sideIndex, colors) => {
|
|
63
|
+
const centerX = (sideIndex * 2 + 1) * (RADIUS + GAP);
|
|
64
|
+
const centerY = RADIUS + GAP;
|
|
65
|
+
const nodes = [];
|
|
66
|
+
for (const offsetX of [-2 * CLOCK_OUTER_RADIUS, 2 * CLOCK_OUTER_RADIUS]) for (const offsetY of [-2 * CLOCK_OUTER_RADIUS, 2 * CLOCK_OUTER_RADIUS]) nodes.push(circle({
|
|
67
|
+
cx: centerX + offsetX,
|
|
68
|
+
cy: centerY + offsetY,
|
|
69
|
+
r: CLOCK_OUTER_RADIUS,
|
|
70
|
+
fill: colors.body,
|
|
71
|
+
stroke: COLORS.stroke,
|
|
72
|
+
"stroke-width": 2
|
|
73
|
+
}));
|
|
74
|
+
nodes.push(circle({
|
|
75
|
+
cx: centerX,
|
|
76
|
+
cy: centerY,
|
|
77
|
+
r: RADIUS,
|
|
78
|
+
fill: colors.body,
|
|
79
|
+
stroke: COLORS.stroke,
|
|
80
|
+
"stroke-width": 2
|
|
81
|
+
}));
|
|
82
|
+
for (let clock = 0; clock < 9; clock += 1) {
|
|
83
|
+
const [clockX, clockY] = clockCenter(sideIndex, clock);
|
|
84
|
+
const ticks = [];
|
|
85
|
+
for (let tick = 0; tick < 12; tick += 1) ticks.push(circle({
|
|
86
|
+
cx: 0,
|
|
87
|
+
cy: -POINT_RADIUS,
|
|
88
|
+
r: tick === 0 ? TOP_TICK_MARK_RADIUS : TICK_MARK_RADIUS,
|
|
89
|
+
fill: tick === 0 ? colors.topClock : colors.clock,
|
|
90
|
+
transform: `rotate(${tick * 30})`
|
|
91
|
+
}));
|
|
92
|
+
nodes.push(group({ transform: translate(clockX, clockY) }, [circle({
|
|
93
|
+
cx: 0,
|
|
94
|
+
cy: 0,
|
|
95
|
+
r: CLOCK_RADIUS,
|
|
96
|
+
fill: colors.clock,
|
|
97
|
+
stroke: COLORS.stroke,
|
|
98
|
+
"stroke-width": 1
|
|
99
|
+
}), ...ticks]));
|
|
100
|
+
}
|
|
101
|
+
return nodes;
|
|
102
|
+
};
|
|
103
|
+
const drawHand = (clockIndex, position, rightSideUp) => {
|
|
104
|
+
const [x, y] = clockCenter(clockIndex < 9 ? 0 : 1, clockIndex % 9);
|
|
105
|
+
const colors = handColorForClock(clockIndex, rightSideUp);
|
|
106
|
+
return group({ transform: `${translate(x, y)} rotate(${position * 30} 0 0)` }, [path({
|
|
107
|
+
d: handPath(),
|
|
108
|
+
fill: colors.hand,
|
|
109
|
+
stroke: colors.hand,
|
|
110
|
+
"stroke-width": 2,
|
|
111
|
+
"stroke-linejoin": "round"
|
|
112
|
+
}), circle({
|
|
113
|
+
cx: 0,
|
|
114
|
+
cy: 0,
|
|
115
|
+
r: ARROW_RADIUS,
|
|
116
|
+
fill: colors.hand,
|
|
117
|
+
stroke: colors.hand,
|
|
118
|
+
"stroke-width": 2
|
|
119
|
+
})]);
|
|
120
|
+
};
|
|
121
|
+
const drawPins = (rightSideUp) => {
|
|
122
|
+
const pins = [];
|
|
123
|
+
for (const sideIndex of [0, 1]) {
|
|
124
|
+
const centerX = (sideIndex * 2 + 1) * (RADIUS + GAP);
|
|
125
|
+
const centerY = RADIUS + GAP;
|
|
126
|
+
const colors = sideIndex === 0 ? rightSideUp ? backColors : frontColors : rightSideUp ? frontColors : backColors;
|
|
127
|
+
for (const offsetX of [-CLOCK_OUTER_RADIUS, CLOCK_OUTER_RADIUS]) for (const offsetY of [-CLOCK_OUTER_RADIUS, CLOCK_OUTER_RADIUS]) pins.push(circle({
|
|
128
|
+
cx: centerX + offsetX,
|
|
129
|
+
cy: centerY + offsetY,
|
|
130
|
+
r: PIN_RADIUS,
|
|
131
|
+
fill: colors.pin
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
return pins;
|
|
135
|
+
};
|
|
136
|
+
const renderClockState = (state) => {
|
|
137
|
+
return createSvgDocument(WIDTH, HEIGHT, [
|
|
138
|
+
...drawSideBackground(0, sideColorFor(0, state.rightSideUp)),
|
|
139
|
+
...drawSideBackground(1, sideColorFor(1, state.rightSideUp)),
|
|
140
|
+
...state.positions.map((position, index) => drawHand(index, position, state.rightSideUp)),
|
|
141
|
+
...drawPins(state.rightSideUp)
|
|
142
|
+
]);
|
|
143
|
+
};
|
|
144
|
+
//#endregion
|
|
145
|
+
export { renderClockState };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CubeFacelet, CubeState } from "../../../scramble-puzzle/src/cube/cube-state.mjs";
|
|
2
|
+
import { HexColor } from "../color.mjs";
|
|
3
|
+
|
|
4
|
+
//#region .build/vendor/scramble-image/src/renderers/cube-isometric.d.ts
|
|
5
|
+
type CubeIsometricColorScheme = Partial<Record<CubeFacelet, HexColor>>;
|
|
6
|
+
declare const renderCubeIsometric: (state: CubeState, colorScheme?: CubeIsometricColorScheme) => string;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { CubeIsometricColorScheme, renderCubeIsometric };
|