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,14 @@
|
|
|
1
|
+
import { PyraminxFace, PyraminxMove } from "./pyraminx-parser2.mjs";
|
|
2
|
+
|
|
3
|
+
//#region .build/vendor/scramble-puzzle/src/pyraminx/pyraminx-state.d.ts
|
|
4
|
+
type PyraminxFacelet = number;
|
|
5
|
+
type PyraminxFaceState = readonly PyraminxFacelet[];
|
|
6
|
+
type PyraminxImage = readonly PyraminxFaceState[];
|
|
7
|
+
interface PyraminxState {
|
|
8
|
+
readonly image: PyraminxImage;
|
|
9
|
+
}
|
|
10
|
+
declare const createSolvedPyraminxState: () => PyraminxState;
|
|
11
|
+
declare const applyPyraminxMove: (state: PyraminxState, move: PyraminxMove) => PyraminxState;
|
|
12
|
+
declare const arePyraminxStatesEqual: (a: PyraminxState, b: PyraminxState) => boolean;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { PyraminxFaceState, PyraminxFacelet, PyraminxImage, PyraminxState, applyPyraminxMove, arePyraminxStatesEqual, createSolvedPyraminxState };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors2.mjs";
|
|
2
|
+
import { PYRAMINX_AXES, PYRAMINX_FACES } from "./pyraminx-parser2.mjs";
|
|
3
|
+
//#region .build/vendor/scramble-puzzle/src/pyraminx/pyraminx-state.ts
|
|
4
|
+
const STICKERS_PER_FACE = 9;
|
|
5
|
+
const MALFORMED_MOVE = "<malformed>";
|
|
6
|
+
const isPyraminxAxis = (face) => typeof face === "string" && PYRAMINX_AXES.includes(face);
|
|
7
|
+
const isMoveAmount = (amount) => amount === 1 || amount === 2;
|
|
8
|
+
const axisIndex = (face) => PYRAMINX_AXES.indexOf(face);
|
|
9
|
+
const clonePyraminxImage = (image) => image.map((face) => [...face]);
|
|
10
|
+
const freezePyraminxImage = (image) => {
|
|
11
|
+
const frozenFaces = image.map((face) => Object.freeze([...face]));
|
|
12
|
+
return Object.freeze(frozenFaces);
|
|
13
|
+
};
|
|
14
|
+
const createPyraminxState = (image) => {
|
|
15
|
+
if (image.length !== PYRAMINX_FACES.length || image.some((face) => face.length !== STICKERS_PER_FACE)) throw new RangeError("pyraminx state must contain 4 faces of 9 stickers");
|
|
16
|
+
for (const face of image) for (const sticker of face) if (!Number.isSafeInteger(sticker) || sticker < 0 || sticker >= PYRAMINX_FACES.length) throw new RangeError("pyraminx stickers must be integer face indexes from 0 to 3");
|
|
17
|
+
return Object.freeze({ image: freezePyraminxImage(image) });
|
|
18
|
+
};
|
|
19
|
+
const swapStickers = (image, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker) => {
|
|
20
|
+
const savedSticker = image[firstFace][firstSticker];
|
|
21
|
+
image[firstFace][firstSticker] = image[secondFace][secondSticker];
|
|
22
|
+
image[secondFace][secondSticker] = image[thirdFace][thirdSticker];
|
|
23
|
+
image[thirdFace][thirdSticker] = savedSticker;
|
|
24
|
+
};
|
|
25
|
+
const turnTipOnce = (image, side) => {
|
|
26
|
+
switch (side) {
|
|
27
|
+
case 0:
|
|
28
|
+
swapStickers(image, 0, 0, 3, 0, 2, 3);
|
|
29
|
+
break;
|
|
30
|
+
case 1:
|
|
31
|
+
swapStickers(image, 0, 6, 2, 6, 1, 0);
|
|
32
|
+
break;
|
|
33
|
+
case 2:
|
|
34
|
+
swapStickers(image, 0, 3, 1, 3, 3, 6);
|
|
35
|
+
break;
|
|
36
|
+
case 3:
|
|
37
|
+
swapStickers(image, 1, 6, 2, 0, 3, 3);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const turnOnce = (image, side) => {
|
|
42
|
+
switch (side) {
|
|
43
|
+
case 0:
|
|
44
|
+
swapStickers(image, 0, 8, 3, 8, 2, 2);
|
|
45
|
+
swapStickers(image, 0, 1, 3, 1, 2, 4);
|
|
46
|
+
swapStickers(image, 0, 2, 3, 2, 2, 5);
|
|
47
|
+
break;
|
|
48
|
+
case 1:
|
|
49
|
+
swapStickers(image, 2, 8, 1, 2, 0, 8);
|
|
50
|
+
swapStickers(image, 2, 7, 1, 1, 0, 7);
|
|
51
|
+
swapStickers(image, 2, 5, 1, 8, 0, 5);
|
|
52
|
+
break;
|
|
53
|
+
case 2:
|
|
54
|
+
swapStickers(image, 3, 8, 0, 5, 1, 5);
|
|
55
|
+
swapStickers(image, 3, 7, 0, 4, 1, 4);
|
|
56
|
+
swapStickers(image, 3, 5, 0, 2, 1, 2);
|
|
57
|
+
break;
|
|
58
|
+
case 3:
|
|
59
|
+
swapStickers(image, 1, 8, 2, 2, 3, 5);
|
|
60
|
+
swapStickers(image, 1, 7, 2, 1, 3, 4);
|
|
61
|
+
swapStickers(image, 1, 5, 2, 8, 3, 2);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
turnTipOnce(image, side);
|
|
65
|
+
};
|
|
66
|
+
const applyRepeatedTurns = (image, amount, turn) => {
|
|
67
|
+
for (let index = 0; index < amount; index += 1) turn();
|
|
68
|
+
};
|
|
69
|
+
const validateMove = (move) => {
|
|
70
|
+
if (typeof move !== "object" || move === null) throw new InvalidMoveError(MALFORMED_MOVE, "pyraminx");
|
|
71
|
+
if ((move.type === "turn" || move.type === "tip") && isPyraminxAxis(move.face) && isMoveAmount(move.amount)) return move;
|
|
72
|
+
throw new InvalidMoveError(MALFORMED_MOVE, "pyraminx");
|
|
73
|
+
};
|
|
74
|
+
const createSolvedPyraminxState = () => createPyraminxState(PYRAMINX_FACES.map((_, face) => Array(STICKERS_PER_FACE).fill(face)));
|
|
75
|
+
const applyPyraminxMove = (state, move) => {
|
|
76
|
+
const validMove = validateMove(move);
|
|
77
|
+
const nextImage = clonePyraminxImage(state.image);
|
|
78
|
+
const side = axisIndex(validMove.face);
|
|
79
|
+
applyRepeatedTurns(nextImage, validMove.amount, () => {
|
|
80
|
+
if (validMove.type === "tip") {
|
|
81
|
+
turnTipOnce(nextImage, side);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
turnOnce(nextImage, side);
|
|
85
|
+
});
|
|
86
|
+
return createPyraminxState(nextImage);
|
|
87
|
+
};
|
|
88
|
+
const arePyraminxStatesEqual = (a, b) => a.image.every((face, faceIndexValue) => face.every((sticker, stickerIndex) => sticker === b.image[faceIndexValue]?.[stickerIndex]));
|
|
89
|
+
//#endregion
|
|
90
|
+
export { applyPyraminxMove, arePyraminxStatesEqual, createSolvedPyraminxState };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { WcaEventId } from "./events2.mjs";
|
|
2
|
+
import { PuzzleDefinition } from "./puzzle-definition.mjs";
|
|
3
|
+
|
|
4
|
+
//#region .build/vendor/scramble-puzzle/src/registry.d.ts
|
|
5
|
+
type AnyPuzzleDefinition<State = unknown, Move = unknown> = PuzzleDefinition<State, Move>;
|
|
6
|
+
interface PuzzleRegistry<Definition extends AnyPuzzleDefinition = never> {
|
|
7
|
+
getByEventId(eventId: WcaEventId): Definition;
|
|
8
|
+
}
|
|
9
|
+
declare const createPuzzleRegistry: <Definition extends AnyPuzzleDefinition>(definitions: readonly Definition[]) => PuzzleRegistry<Definition>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AnyPuzzleDefinition, PuzzleRegistry, createPuzzleRegistry };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UnregisteredPuzzleError } from "./errors2.mjs";
|
|
2
|
+
//#region .build/vendor/scramble-puzzle/src/registry.ts
|
|
3
|
+
const createPuzzleRegistry = (definitions) => {
|
|
4
|
+
const definitionsByEventId = /* @__PURE__ */ new Map();
|
|
5
|
+
for (const definition of definitions) for (const eventId of definition.eventIds) definitionsByEventId.set(eventId, definition);
|
|
6
|
+
return { getByEventId(eventId) {
|
|
7
|
+
const definition = definitionsByEventId.get(eventId);
|
|
8
|
+
if (definition === void 0) throw new UnregisteredPuzzleError(eventId);
|
|
9
|
+
return definition;
|
|
10
|
+
} };
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { createPuzzleRegistry };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PuzzleDefinition } from "../puzzle-definition.mjs";
|
|
2
|
+
import { SkewbMove } from "./skewb-parser2.mjs";
|
|
3
|
+
import { SkewbState } from "./skewb-state2.mjs";
|
|
4
|
+
|
|
5
|
+
//#region .build/vendor/scramble-puzzle/src/skewb/skewb-definition.d.ts
|
|
6
|
+
declare const createSkewbDefinition: () => PuzzleDefinition<SkewbState, SkewbMove>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { createSkewbDefinition };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { applyAlgorithm } from "../algorithm.mjs";
|
|
2
|
+
import { parseSkewbAlgorithm } from "./skewb-parser.mjs";
|
|
3
|
+
import { applySkewbMove, areSkewbStatesEqual, createSolvedSkewbState } from "./skewb-state.mjs";
|
|
4
|
+
//#region ../scramble-puzzle/src/skewb/skewb-definition.ts
|
|
5
|
+
const createSkewbDefinition = () => {
|
|
6
|
+
const definition = {
|
|
7
|
+
id: "skewb",
|
|
8
|
+
eventIds: ["skewb"],
|
|
9
|
+
createSolvedState: createSolvedSkewbState,
|
|
10
|
+
parseAlgorithm: parseSkewbAlgorithm,
|
|
11
|
+
applyMove: applySkewbMove,
|
|
12
|
+
applyAlgorithm: (state, algorithm) => applyAlgorithm(definition, state, algorithm),
|
|
13
|
+
isSolved: (state) => areSkewbStatesEqual(state, createSolvedSkewbState())
|
|
14
|
+
};
|
|
15
|
+
return definition;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createSkewbDefinition };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { applyAlgorithm } from "../algorithm2.mjs";
|
|
2
|
+
import { parseSkewbAlgorithm } from "./skewb-parser2.mjs";
|
|
3
|
+
import { applySkewbMove, areSkewbStatesEqual, createSolvedSkewbState } from "./skewb-state2.mjs";
|
|
4
|
+
//#region .build/vendor/scramble-puzzle/src/skewb/skewb-definition.ts
|
|
5
|
+
const createSkewbDefinition = () => {
|
|
6
|
+
const definition = {
|
|
7
|
+
id: "skewb",
|
|
8
|
+
eventIds: ["skewb"],
|
|
9
|
+
createSolvedState: createSolvedSkewbState,
|
|
10
|
+
parseAlgorithm: parseSkewbAlgorithm,
|
|
11
|
+
applyMove: applySkewbMove,
|
|
12
|
+
applyAlgorithm: (state, algorithm) => applyAlgorithm(definition, state, algorithm),
|
|
13
|
+
isSolved: (state) => areSkewbStatesEqual(state, createSolvedSkewbState())
|
|
14
|
+
};
|
|
15
|
+
return definition;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createSkewbDefinition };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors.mjs";
|
|
2
|
+
import { splitAlgorithm } from "../algorithm.mjs";
|
|
3
|
+
//#region ../scramble-puzzle/src/skewb/skewb-parser.ts
|
|
4
|
+
const SKEWB_FACES = [
|
|
5
|
+
"U",
|
|
6
|
+
"R",
|
|
7
|
+
"F",
|
|
8
|
+
"D",
|
|
9
|
+
"L",
|
|
10
|
+
"B"
|
|
11
|
+
];
|
|
12
|
+
const SKEWB_AXES = [
|
|
13
|
+
"R",
|
|
14
|
+
"U",
|
|
15
|
+
"L",
|
|
16
|
+
"B"
|
|
17
|
+
];
|
|
18
|
+
const SKEWB_MOVE_PATTERN = /^([RULB])('?)$/;
|
|
19
|
+
const SKEWB_AXIS_SET = new Set(SKEWB_AXES);
|
|
20
|
+
const isSkewbAxis = (face) => SKEWB_AXIS_SET.has(face);
|
|
21
|
+
const parseSkewbMove = (token) => {
|
|
22
|
+
const match = token.match(SKEWB_MOVE_PATTERN);
|
|
23
|
+
if (!match) throw new InvalidMoveError(token, "skewb");
|
|
24
|
+
const [, face, suffix] = match;
|
|
25
|
+
if (face === void 0 || !isSkewbAxis(face)) throw new InvalidMoveError(token, "skewb");
|
|
26
|
+
return {
|
|
27
|
+
face,
|
|
28
|
+
amount: suffix === "'" ? 2 : 1
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
const parseSkewbAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parseSkewbMove);
|
|
32
|
+
//#endregion
|
|
33
|
+
export { SKEWB_AXES, SKEWB_FACES, parseSkewbAlgorithm, parseSkewbMove };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region .build/vendor/scramble-puzzle/src/skewb/skewb-parser.d.ts
|
|
2
|
+
declare const SKEWB_FACES: readonly ["U", "R", "F", "D", "L", "B"];
|
|
3
|
+
declare const SKEWB_AXES: readonly ["R", "U", "L", "B"];
|
|
4
|
+
type SkewbFace = (typeof SKEWB_FACES)[number];
|
|
5
|
+
type SkewbAxis = (typeof SKEWB_AXES)[number];
|
|
6
|
+
type SkewbMoveAmount = 1 | 2;
|
|
7
|
+
interface SkewbMove {
|
|
8
|
+
readonly face: SkewbAxis;
|
|
9
|
+
readonly amount: SkewbMoveAmount;
|
|
10
|
+
}
|
|
11
|
+
declare const parseSkewbMove: (token: string) => SkewbMove;
|
|
12
|
+
declare const parseSkewbAlgorithm: (algorithm: string) => readonly SkewbMove[];
|
|
13
|
+
//#endregion
|
|
14
|
+
export { SKEWB_AXES, SKEWB_FACES, SkewbAxis, SkewbFace, SkewbMove, SkewbMoveAmount, parseSkewbAlgorithm, parseSkewbMove };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors2.mjs";
|
|
2
|
+
import { splitAlgorithm } from "../algorithm2.mjs";
|
|
3
|
+
//#region .build/vendor/scramble-puzzle/src/skewb/skewb-parser.ts
|
|
4
|
+
const SKEWB_FACES = [
|
|
5
|
+
"U",
|
|
6
|
+
"R",
|
|
7
|
+
"F",
|
|
8
|
+
"D",
|
|
9
|
+
"L",
|
|
10
|
+
"B"
|
|
11
|
+
];
|
|
12
|
+
const SKEWB_AXES = [
|
|
13
|
+
"R",
|
|
14
|
+
"U",
|
|
15
|
+
"L",
|
|
16
|
+
"B"
|
|
17
|
+
];
|
|
18
|
+
const SKEWB_MOVE_PATTERN = /^([RULB])('?)$/;
|
|
19
|
+
const SKEWB_AXIS_SET = new Set(SKEWB_AXES);
|
|
20
|
+
const isSkewbAxis = (face) => SKEWB_AXIS_SET.has(face);
|
|
21
|
+
const parseSkewbMove = (token) => {
|
|
22
|
+
const match = token.match(SKEWB_MOVE_PATTERN);
|
|
23
|
+
if (!match) throw new InvalidMoveError(token, "skewb");
|
|
24
|
+
const [, face, suffix] = match;
|
|
25
|
+
if (face === void 0 || !isSkewbAxis(face)) throw new InvalidMoveError(token, "skewb");
|
|
26
|
+
return {
|
|
27
|
+
face,
|
|
28
|
+
amount: suffix === "'" ? 2 : 1
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
const parseSkewbAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parseSkewbMove);
|
|
32
|
+
//#endregion
|
|
33
|
+
export { SKEWB_AXES, SKEWB_FACES, parseSkewbAlgorithm, parseSkewbMove };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SkewbFace } from "./skewb-parser.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../scramble-puzzle/src/skewb/skewb-state.d.ts
|
|
4
|
+
type SkewbFacelet = number;
|
|
5
|
+
type SkewbFaceState = readonly SkewbFacelet[];
|
|
6
|
+
type SkewbImage = readonly SkewbFaceState[];
|
|
7
|
+
interface SkewbState {
|
|
8
|
+
readonly image: SkewbImage;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { SkewbState };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors.mjs";
|
|
2
|
+
import { SKEWB_AXES, SKEWB_FACES } from "./skewb-parser.mjs";
|
|
3
|
+
//#region ../scramble-puzzle/src/skewb/skewb-state.ts
|
|
4
|
+
const STICKERS_PER_FACE = 5;
|
|
5
|
+
const MALFORMED_MOVE = "<malformed>";
|
|
6
|
+
const isSkewbAxis = (face) => typeof face === "string" && SKEWB_AXES.includes(face);
|
|
7
|
+
const isMoveAmount = (amount) => amount === 1 || amount === 2;
|
|
8
|
+
const axisIndex = (face) => SKEWB_AXES.indexOf(face);
|
|
9
|
+
const cloneSkewbImage = (image) => image.map((face) => [...face]);
|
|
10
|
+
const freezeSkewbImage = (image) => {
|
|
11
|
+
const frozenFaces = image.map((face) => Object.freeze([...face]));
|
|
12
|
+
return Object.freeze(frozenFaces);
|
|
13
|
+
};
|
|
14
|
+
const createSkewbState = (image) => {
|
|
15
|
+
if (image.length !== SKEWB_FACES.length || image.some((face) => face.length !== STICKERS_PER_FACE)) throw new RangeError("skewb state must contain 6 faces of 5 stickers");
|
|
16
|
+
for (const face of image) for (const sticker of face) if (!Number.isSafeInteger(sticker) || sticker < 0 || sticker >= SKEWB_FACES.length) throw new RangeError("skewb stickers must be integer face indexes from 0 to 5");
|
|
17
|
+
return Object.freeze({ image: freezeSkewbImage(image) });
|
|
18
|
+
};
|
|
19
|
+
const swapStickers = (image, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker) => {
|
|
20
|
+
const savedSticker = image[firstFace][firstSticker];
|
|
21
|
+
image[firstFace][firstSticker] = image[secondFace][secondSticker];
|
|
22
|
+
image[secondFace][secondSticker] = image[thirdFace][thirdSticker];
|
|
23
|
+
image[thirdFace][thirdSticker] = savedSticker;
|
|
24
|
+
};
|
|
25
|
+
const turnOnce = (image, axis) => {
|
|
26
|
+
switch (axis) {
|
|
27
|
+
case 0:
|
|
28
|
+
swapStickers(image, 2, 0, 3, 0, 1, 0);
|
|
29
|
+
swapStickers(image, 2, 4, 3, 2, 1, 3);
|
|
30
|
+
swapStickers(image, 2, 2, 3, 1, 1, 4);
|
|
31
|
+
swapStickers(image, 2, 3, 3, 4, 1, 1);
|
|
32
|
+
swapStickers(image, 4, 4, 5, 3, 0, 4);
|
|
33
|
+
break;
|
|
34
|
+
case 1:
|
|
35
|
+
swapStickers(image, 0, 0, 1, 0, 5, 0);
|
|
36
|
+
swapStickers(image, 0, 2, 1, 2, 5, 1);
|
|
37
|
+
swapStickers(image, 0, 4, 1, 4, 5, 2);
|
|
38
|
+
swapStickers(image, 0, 1, 1, 1, 5, 3);
|
|
39
|
+
swapStickers(image, 4, 1, 2, 2, 3, 4);
|
|
40
|
+
break;
|
|
41
|
+
case 2:
|
|
42
|
+
swapStickers(image, 4, 0, 5, 0, 3, 0);
|
|
43
|
+
swapStickers(image, 4, 3, 5, 4, 3, 3);
|
|
44
|
+
swapStickers(image, 4, 1, 5, 3, 3, 1);
|
|
45
|
+
swapStickers(image, 4, 4, 5, 2, 3, 4);
|
|
46
|
+
swapStickers(image, 2, 3, 0, 1, 1, 4);
|
|
47
|
+
break;
|
|
48
|
+
case 3:
|
|
49
|
+
swapStickers(image, 1, 0, 3, 0, 5, 0);
|
|
50
|
+
swapStickers(image, 1, 4, 3, 4, 5, 3);
|
|
51
|
+
swapStickers(image, 1, 3, 3, 3, 5, 1);
|
|
52
|
+
swapStickers(image, 1, 2, 3, 2, 5, 4);
|
|
53
|
+
swapStickers(image, 0, 2, 2, 4, 4, 3);
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const applyRepeatedTurns = (image, amount, turn) => {
|
|
58
|
+
for (let index = 0; index < amount; index += 1) turn();
|
|
59
|
+
};
|
|
60
|
+
const validateMove = (move) => {
|
|
61
|
+
if (typeof move !== "object" || move === null) throw new InvalidMoveError(MALFORMED_MOVE, "skewb");
|
|
62
|
+
if (isSkewbAxis(move.face) && isMoveAmount(move.amount)) return move;
|
|
63
|
+
throw new InvalidMoveError(MALFORMED_MOVE, "skewb");
|
|
64
|
+
};
|
|
65
|
+
const createSolvedSkewbState = () => createSkewbState(SKEWB_FACES.map((_, face) => Array(STICKERS_PER_FACE).fill(face)));
|
|
66
|
+
const applySkewbMove = (state, move) => {
|
|
67
|
+
const validMove = validateMove(move);
|
|
68
|
+
const nextImage = cloneSkewbImage(state.image);
|
|
69
|
+
const axis = axisIndex(validMove.face);
|
|
70
|
+
applyRepeatedTurns(nextImage, validMove.amount, () => turnOnce(nextImage, axis));
|
|
71
|
+
return createSkewbState(nextImage);
|
|
72
|
+
};
|
|
73
|
+
const areSkewbStatesEqual = (a, b) => a.image.every((face, faceIndexValue) => face.every((sticker, stickerIndex) => sticker === b.image[faceIndexValue]?.[stickerIndex]));
|
|
74
|
+
//#endregion
|
|
75
|
+
export { applySkewbMove, areSkewbStatesEqual, createSolvedSkewbState };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SkewbFace, SkewbMove } from "./skewb-parser2.mjs";
|
|
2
|
+
|
|
3
|
+
//#region .build/vendor/scramble-puzzle/src/skewb/skewb-state.d.ts
|
|
4
|
+
type SkewbFacelet = number;
|
|
5
|
+
type SkewbFaceState = readonly SkewbFacelet[];
|
|
6
|
+
type SkewbImage = readonly SkewbFaceState[];
|
|
7
|
+
interface SkewbState {
|
|
8
|
+
readonly image: SkewbImage;
|
|
9
|
+
}
|
|
10
|
+
declare const createSolvedSkewbState: () => SkewbState;
|
|
11
|
+
declare const applySkewbMove: (state: SkewbState, move: SkewbMove) => SkewbState;
|
|
12
|
+
declare const areSkewbStatesEqual: (a: SkewbState, b: SkewbState) => boolean;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { SkewbFaceState, SkewbFacelet, SkewbImage, SkewbState, applySkewbMove, areSkewbStatesEqual, createSolvedSkewbState };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors2.mjs";
|
|
2
|
+
import { SKEWB_AXES, SKEWB_FACES } from "./skewb-parser2.mjs";
|
|
3
|
+
//#region .build/vendor/scramble-puzzle/src/skewb/skewb-state.ts
|
|
4
|
+
const STICKERS_PER_FACE = 5;
|
|
5
|
+
const MALFORMED_MOVE = "<malformed>";
|
|
6
|
+
const isSkewbAxis = (face) => typeof face === "string" && SKEWB_AXES.includes(face);
|
|
7
|
+
const isMoveAmount = (amount) => amount === 1 || amount === 2;
|
|
8
|
+
const axisIndex = (face) => SKEWB_AXES.indexOf(face);
|
|
9
|
+
const cloneSkewbImage = (image) => image.map((face) => [...face]);
|
|
10
|
+
const freezeSkewbImage = (image) => {
|
|
11
|
+
const frozenFaces = image.map((face) => Object.freeze([...face]));
|
|
12
|
+
return Object.freeze(frozenFaces);
|
|
13
|
+
};
|
|
14
|
+
const createSkewbState = (image) => {
|
|
15
|
+
if (image.length !== SKEWB_FACES.length || image.some((face) => face.length !== STICKERS_PER_FACE)) throw new RangeError("skewb state must contain 6 faces of 5 stickers");
|
|
16
|
+
for (const face of image) for (const sticker of face) if (!Number.isSafeInteger(sticker) || sticker < 0 || sticker >= SKEWB_FACES.length) throw new RangeError("skewb stickers must be integer face indexes from 0 to 5");
|
|
17
|
+
return Object.freeze({ image: freezeSkewbImage(image) });
|
|
18
|
+
};
|
|
19
|
+
const swapStickers = (image, firstFace, firstSticker, secondFace, secondSticker, thirdFace, thirdSticker) => {
|
|
20
|
+
const savedSticker = image[firstFace][firstSticker];
|
|
21
|
+
image[firstFace][firstSticker] = image[secondFace][secondSticker];
|
|
22
|
+
image[secondFace][secondSticker] = image[thirdFace][thirdSticker];
|
|
23
|
+
image[thirdFace][thirdSticker] = savedSticker;
|
|
24
|
+
};
|
|
25
|
+
const turnOnce = (image, axis) => {
|
|
26
|
+
switch (axis) {
|
|
27
|
+
case 0:
|
|
28
|
+
swapStickers(image, 2, 0, 3, 0, 1, 0);
|
|
29
|
+
swapStickers(image, 2, 4, 3, 2, 1, 3);
|
|
30
|
+
swapStickers(image, 2, 2, 3, 1, 1, 4);
|
|
31
|
+
swapStickers(image, 2, 3, 3, 4, 1, 1);
|
|
32
|
+
swapStickers(image, 4, 4, 5, 3, 0, 4);
|
|
33
|
+
break;
|
|
34
|
+
case 1:
|
|
35
|
+
swapStickers(image, 0, 0, 1, 0, 5, 0);
|
|
36
|
+
swapStickers(image, 0, 2, 1, 2, 5, 1);
|
|
37
|
+
swapStickers(image, 0, 4, 1, 4, 5, 2);
|
|
38
|
+
swapStickers(image, 0, 1, 1, 1, 5, 3);
|
|
39
|
+
swapStickers(image, 4, 1, 2, 2, 3, 4);
|
|
40
|
+
break;
|
|
41
|
+
case 2:
|
|
42
|
+
swapStickers(image, 4, 0, 5, 0, 3, 0);
|
|
43
|
+
swapStickers(image, 4, 3, 5, 4, 3, 3);
|
|
44
|
+
swapStickers(image, 4, 1, 5, 3, 3, 1);
|
|
45
|
+
swapStickers(image, 4, 4, 5, 2, 3, 4);
|
|
46
|
+
swapStickers(image, 2, 3, 0, 1, 1, 4);
|
|
47
|
+
break;
|
|
48
|
+
case 3:
|
|
49
|
+
swapStickers(image, 1, 0, 3, 0, 5, 0);
|
|
50
|
+
swapStickers(image, 1, 4, 3, 4, 5, 3);
|
|
51
|
+
swapStickers(image, 1, 3, 3, 3, 5, 1);
|
|
52
|
+
swapStickers(image, 1, 2, 3, 2, 5, 4);
|
|
53
|
+
swapStickers(image, 0, 2, 2, 4, 4, 3);
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const applyRepeatedTurns = (image, amount, turn) => {
|
|
58
|
+
for (let index = 0; index < amount; index += 1) turn();
|
|
59
|
+
};
|
|
60
|
+
const validateMove = (move) => {
|
|
61
|
+
if (typeof move !== "object" || move === null) throw new InvalidMoveError(MALFORMED_MOVE, "skewb");
|
|
62
|
+
if (isSkewbAxis(move.face) && isMoveAmount(move.amount)) return move;
|
|
63
|
+
throw new InvalidMoveError(MALFORMED_MOVE, "skewb");
|
|
64
|
+
};
|
|
65
|
+
const createSolvedSkewbState = () => createSkewbState(SKEWB_FACES.map((_, face) => Array(STICKERS_PER_FACE).fill(face)));
|
|
66
|
+
const applySkewbMove = (state, move) => {
|
|
67
|
+
const validMove = validateMove(move);
|
|
68
|
+
const nextImage = cloneSkewbImage(state.image);
|
|
69
|
+
const axis = axisIndex(validMove.face);
|
|
70
|
+
applyRepeatedTurns(nextImage, validMove.amount, () => turnOnce(nextImage, axis));
|
|
71
|
+
return createSkewbState(nextImage);
|
|
72
|
+
};
|
|
73
|
+
const areSkewbStatesEqual = (a, b) => a.image.every((face, faceIndexValue) => face.every((sticker, stickerIndex) => sticker === b.image[faceIndexValue]?.[stickerIndex]));
|
|
74
|
+
//#endregion
|
|
75
|
+
export { applySkewbMove, areSkewbStatesEqual, createSolvedSkewbState };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PuzzleDefinition } from "../puzzle-definition.mjs";
|
|
2
|
+
import { SquareOneMove } from "./square1-parser.mjs";
|
|
3
|
+
import { SquareOneState } from "./square1-state2.mjs";
|
|
4
|
+
|
|
5
|
+
//#region .build/vendor/scramble-puzzle/src/square1/square1-definition.d.ts
|
|
6
|
+
declare const createSquareOneDefinition: () => PuzzleDefinition<SquareOneState, SquareOneMove>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { createSquareOneDefinition };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { applyAlgorithm } from "../algorithm.mjs";
|
|
2
|
+
import { parseSquareOneAlgorithm } from "./square1-parser.mjs";
|
|
3
|
+
import { applySquareOneMove, areSquareOneStatesEqual, createSolvedSquareOneState } from "./square1-state.mjs";
|
|
4
|
+
//#region ../scramble-puzzle/src/square1/square1-definition.ts
|
|
5
|
+
const createSquareOneDefinition = () => {
|
|
6
|
+
const definition = {
|
|
7
|
+
id: "square1",
|
|
8
|
+
eventIds: ["sq1"],
|
|
9
|
+
createSolvedState: createSolvedSquareOneState,
|
|
10
|
+
parseAlgorithm: parseSquareOneAlgorithm,
|
|
11
|
+
applyMove: applySquareOneMove,
|
|
12
|
+
applyAlgorithm: (state, algorithm) => applyAlgorithm(definition, state, algorithm),
|
|
13
|
+
isSolved: (state) => areSquareOneStatesEqual(state, createSolvedSquareOneState())
|
|
14
|
+
};
|
|
15
|
+
return definition;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createSquareOneDefinition };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { applyAlgorithm } from "../algorithm2.mjs";
|
|
2
|
+
import { parseSquareOneAlgorithm } from "./square1-parser2.mjs";
|
|
3
|
+
import { applySquareOneMove, areSquareOneStatesEqual, createSolvedSquareOneState } from "./square1-state2.mjs";
|
|
4
|
+
//#region .build/vendor/scramble-puzzle/src/square1/square1-definition.ts
|
|
5
|
+
const createSquareOneDefinition = () => {
|
|
6
|
+
const definition = {
|
|
7
|
+
id: "square1",
|
|
8
|
+
eventIds: ["sq1"],
|
|
9
|
+
createSolvedState: createSolvedSquareOneState,
|
|
10
|
+
parseAlgorithm: parseSquareOneAlgorithm,
|
|
11
|
+
applyMove: applySquareOneMove,
|
|
12
|
+
applyAlgorithm: (state, algorithm) => applyAlgorithm(definition, state, algorithm),
|
|
13
|
+
isSolved: (state) => areSquareOneStatesEqual(state, createSolvedSquareOneState())
|
|
14
|
+
};
|
|
15
|
+
return definition;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createSquareOneDefinition };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region .build/vendor/scramble-puzzle/src/square1/square1-parser.d.ts
|
|
2
|
+
type SquareOneTurn = -5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
3
|
+
interface SquareOneTupleMove {
|
|
4
|
+
readonly type: 'tuple';
|
|
5
|
+
readonly top: SquareOneTurn;
|
|
6
|
+
readonly bottom: SquareOneTurn;
|
|
7
|
+
}
|
|
8
|
+
interface SquareOneSlashMove {
|
|
9
|
+
readonly type: 'slash';
|
|
10
|
+
}
|
|
11
|
+
type SquareOneMove = SquareOneTupleMove | SquareOneSlashMove;
|
|
12
|
+
declare const parseSquareOneMove: (token: string) => SquareOneMove;
|
|
13
|
+
declare const parseSquareOneAlgorithm: (algorithm: string) => readonly SquareOneMove[];
|
|
14
|
+
declare const getSquareOneMoveCost: (move: SquareOneMove) => number;
|
|
15
|
+
declare const getSquareOneSlashabilityMoveCost: (move: SquareOneMove) => number | undefined;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { SquareOneMove, SquareOneSlashMove, SquareOneTupleMove, SquareOneTurn, getSquareOneMoveCost, getSquareOneSlashabilityMoveCost, parseSquareOneAlgorithm, parseSquareOneMove };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors.mjs";
|
|
2
|
+
import { splitAlgorithm } from "../algorithm.mjs";
|
|
3
|
+
//#region ../scramble-puzzle/src/square1/square1-parser.ts
|
|
4
|
+
const SQUARE_ONE_MOVE_PATTERN = /^\((-?\d+),(-?\d+)\)$/;
|
|
5
|
+
const MIN_TURN = -5;
|
|
6
|
+
const MAX_TURN = 6;
|
|
7
|
+
const MALFORMED_MOVE = "<malformed>";
|
|
8
|
+
const isSquareOneRecord = (move) => typeof move === "object" && move !== null;
|
|
9
|
+
const isSquareOneTurn = (turn) => typeof turn === "number" && Number.isSafeInteger(turn) && turn >= MIN_TURN && turn <= MAX_TURN;
|
|
10
|
+
const hasOnlyKeys = (move, expectedKeys) => Object.keys(move).length === expectedKeys.length && expectedKeys.every((key) => Object.hasOwn(move, key));
|
|
11
|
+
const isSquareOneTupleMove = (move) => isSquareOneRecord(move) && move.type === "tuple";
|
|
12
|
+
const isSquareOneSlashMove = (move) => isSquareOneRecord(move) && move.type === "slash" && hasOnlyKeys(move, ["type"]);
|
|
13
|
+
const validateSquareOneMove = (move) => {
|
|
14
|
+
if (isSquareOneSlashMove(move)) return move;
|
|
15
|
+
if (isSquareOneTupleMove(move) && hasOnlyKeys(move, [
|
|
16
|
+
"type",
|
|
17
|
+
"top",
|
|
18
|
+
"bottom"
|
|
19
|
+
]) && isSquareOneTurn(move.top) && isSquareOneTurn(move.bottom) && (move.top !== 0 || move.bottom !== 0)) return move;
|
|
20
|
+
throw new InvalidMoveError(MALFORMED_MOVE, "square1");
|
|
21
|
+
};
|
|
22
|
+
const parseSquareOneMove = (token) => {
|
|
23
|
+
if (token === "/") return { type: "slash" };
|
|
24
|
+
const match = token.match(SQUARE_ONE_MOVE_PATTERN);
|
|
25
|
+
if (!match) throw new InvalidMoveError(token, "square1");
|
|
26
|
+
const [, topText, bottomText] = match;
|
|
27
|
+
const top = Number(topText);
|
|
28
|
+
const bottom = Number(bottomText);
|
|
29
|
+
if (!isSquareOneTurn(top) || !isSquareOneTurn(bottom) || top === 0 && bottom === 0) throw new InvalidMoveError(token, "square1");
|
|
30
|
+
return {
|
|
31
|
+
type: "tuple",
|
|
32
|
+
top,
|
|
33
|
+
bottom
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const parseSquareOneAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parseSquareOneMove);
|
|
37
|
+
const getSquareOneSlashabilityMoveCost = (move) => {
|
|
38
|
+
const validMove = validateSquareOneMove(move);
|
|
39
|
+
if (validMove.type === "slash") return void 0;
|
|
40
|
+
return Math.abs(validMove.top) + Math.abs(validMove.bottom);
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { getSquareOneSlashabilityMoveCost, parseSquareOneAlgorithm, parseSquareOneMove, validateSquareOneMove };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { InvalidMoveError } from "../errors2.mjs";
|
|
2
|
+
import { splitAlgorithm } from "../algorithm2.mjs";
|
|
3
|
+
//#region .build/vendor/scramble-puzzle/src/square1/square1-parser.ts
|
|
4
|
+
const SQUARE_ONE_MOVE_PATTERN = /^\((-?\d+),(-?\d+)\)$/;
|
|
5
|
+
const MIN_TURN = -5;
|
|
6
|
+
const MAX_TURN = 6;
|
|
7
|
+
const MALFORMED_MOVE = "<malformed>";
|
|
8
|
+
const isSquareOneRecord = (move) => typeof move === "object" && move !== null;
|
|
9
|
+
const isSquareOneTurn = (turn) => typeof turn === "number" && Number.isSafeInteger(turn) && turn >= MIN_TURN && turn <= MAX_TURN;
|
|
10
|
+
const hasOnlyKeys = (move, expectedKeys) => Object.keys(move).length === expectedKeys.length && expectedKeys.every((key) => Object.hasOwn(move, key));
|
|
11
|
+
const isSquareOneTupleMove = (move) => isSquareOneRecord(move) && move.type === "tuple";
|
|
12
|
+
const isSquareOneSlashMove = (move) => isSquareOneRecord(move) && move.type === "slash" && hasOnlyKeys(move, ["type"]);
|
|
13
|
+
const validateSquareOneMove = (move) => {
|
|
14
|
+
if (isSquareOneSlashMove(move)) return move;
|
|
15
|
+
if (isSquareOneTupleMove(move) && hasOnlyKeys(move, [
|
|
16
|
+
"type",
|
|
17
|
+
"top",
|
|
18
|
+
"bottom"
|
|
19
|
+
]) && isSquareOneTurn(move.top) && isSquareOneTurn(move.bottom) && (move.top !== 0 || move.bottom !== 0)) return move;
|
|
20
|
+
throw new InvalidMoveError(MALFORMED_MOVE, "square1");
|
|
21
|
+
};
|
|
22
|
+
const parseSquareOneMove = (token) => {
|
|
23
|
+
if (token === "/") return { type: "slash" };
|
|
24
|
+
const match = token.match(SQUARE_ONE_MOVE_PATTERN);
|
|
25
|
+
if (!match) throw new InvalidMoveError(token, "square1");
|
|
26
|
+
const [, topText, bottomText] = match;
|
|
27
|
+
const top = Number(topText);
|
|
28
|
+
const bottom = Number(bottomText);
|
|
29
|
+
if (!isSquareOneTurn(top) || !isSquareOneTurn(bottom) || top === 0 && bottom === 0) throw new InvalidMoveError(token, "square1");
|
|
30
|
+
return {
|
|
31
|
+
type: "tuple",
|
|
32
|
+
top,
|
|
33
|
+
bottom
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const parseSquareOneAlgorithm = (algorithm) => splitAlgorithm(algorithm).map(parseSquareOneMove);
|
|
37
|
+
const getSquareOneMoveCost = (move) => {
|
|
38
|
+
validateSquareOneMove(move);
|
|
39
|
+
return 1;
|
|
40
|
+
};
|
|
41
|
+
const getSquareOneSlashabilityMoveCost = (move) => {
|
|
42
|
+
const validMove = validateSquareOneMove(move);
|
|
43
|
+
if (validMove.type === "slash") return void 0;
|
|
44
|
+
return Math.abs(validMove.top) + Math.abs(validMove.bottom);
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { getSquareOneMoveCost, getSquareOneSlashabilityMoveCost, parseSquareOneAlgorithm, parseSquareOneMove, validateSquareOneMove };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region ../scramble-puzzle/src/square1/square1-state.d.ts
|
|
2
|
+
type SquareOnePiece = number;
|
|
3
|
+
type SquareOnePieces = readonly SquareOnePiece[];
|
|
4
|
+
interface SquareOneState {
|
|
5
|
+
readonly sliceSolved: boolean;
|
|
6
|
+
readonly pieces: SquareOnePieces;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { SquareOneState };
|