@wodzik/cubecore 0.1.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/LICENSE +373 -0
- package/README.md +118 -0
- package/analyze/client.d.ts +18 -0
- package/analyze/client.js +42 -0
- package/analyze/index.d.ts +114 -0
- package/analyze/index.js +151 -0
- package/analyze/rotations.d.ts +3 -0
- package/analyze/rotations.js +15 -0
- package/analyze/roux.d.ts +67 -0
- package/analyze/roux.js +95 -0
- package/analyze/worker.d.ts +6 -0
- package/analyze/worker.js +31 -0
- package/analyze/zz.d.ts +47 -0
- package/analyze/zz.js +102 -0
- package/bld/index.d.ts +14 -0
- package/bld/index.js +14 -0
- package/bld/memo.d.ts +66 -0
- package/bld/memo.js +139 -0
- package/bld/scheme.d.ts +30 -0
- package/bld/scheme.js +35 -0
- package/bld/skin.d.ts +26 -0
- package/bld/skin.js +46 -0
- package/bld/tracker.d.ts +68 -0
- package/bld/tracker.js +145 -0
- package/bluetooth/clock.d.ts +22 -0
- package/bluetooth/clock.js +37 -0
- package/bluetooth/cubeSkins.d.ts +31 -0
- package/bluetooth/cubeSkins.js +32 -0
- package/bluetooth/gyro.d.ts +31 -0
- package/bluetooth/gyro.js +46 -0
- package/bluetooth/index.d.ts +5 -0
- package/bluetooth/index.js +5 -0
- package/bluetooth/session.d.ts +140 -0
- package/bluetooth/session.js +201 -0
- package/bluetooth/simulated.d.ts +52 -0
- package/bluetooth/simulated.js +80 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-cube-definitions.d.ts +38 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-cube-definitions.js +51 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-cube-encrypter.d.ts +35 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-cube-encrypter.js +70 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-cube-protocol.d.ts +273 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-cube-protocol.js +846 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-gen1.d.ts +38 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-gen1.js +340 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-gen234-packet-validate.d.ts +11 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-gen234-packet-validate.js +118 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-mac-salt.d.ts +2 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-mac-salt.js +15 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-smart-cube.d.ts +18 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-smart-cube.js +152 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-smart-timer.d.ts +74 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-smart-timer.js +161 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-write-queue.d.ts +7 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gan-write-queue.js +11 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gatt-characteristic-write.d.ts +2 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/gatt-characteristic-write.js +36 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/index.d.ts +4 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/index.js +4 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/address-hints.d.ts +12 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/address-hints.js +122 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/build-picker-options.d.ts +11 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/build-picker-options.js +55 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/default-optional-services.d.ts +21 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/default-optional-services.js +47 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/device-name-scan-filters.d.ts +6 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/device-name-scan-filters.js +24 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/gatt-snapshot.d.ts +6 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/gatt-snapshot.js +57 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/mac-candidates.d.ts +11 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/mac-candidates.js +67 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/mac-probe-moyu32.d.ts +8 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/mac-probe-moyu32.js +98 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/mac-probe-qiyi.d.ts +8 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/mac-probe-qiyi.js +128 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/moyu32-session-crypto.d.ts +5 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/moyu32-session-crypto.js +60 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/normalize-uuid.d.ts +2 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/normalize-uuid.js +8 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/packet-sanity.d.ts +7 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/packet-sanity.js +142 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/profile-rank.d.ts +6 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/profile-rank.js +21 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/types.d.ts +32 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/attachment/types.js +1 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/ble-utils.d.ts +6 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/ble-utils.js +68 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/connect.d.ts +3 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/connect.js +178 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/cubie-cube.d.ts +16 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/cubie-cube.js +141 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/index.d.ts +11 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/index.js +10 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocol.d.ts +26 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocol.js +8 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/gan.d.ts +3 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/gan.js +265 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/giiker.d.ts +3 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/giiker.js +345 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/gocube.d.ts +15 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/gocube.js +382 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/moyu-mhc.d.ts +3 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/moyu-mhc.js +352 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/moyu-v1.d.ts +57 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/moyu-v1.js +243 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/moyu32.d.ts +3 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/moyu32.js +454 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/qiyi.d.ts +3 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/protocols/qiyi.js +424 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/types.d.ts +78 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/smartcube/types.js +1 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/utils.d.ts +45 -0
- package/bluetooth/vendor/smartcube-web-bluetooth/utils.js +150 -0
- package/cfop/caseData.d.ts +16 -0
- package/cfop/caseData.js +88 -0
- package/cfop/cases.d.ts +42 -0
- package/cfop/cases.js +116 -0
- package/cfop/f2l.d.ts +28 -0
- package/cfop/f2l.js +88 -0
- package/cfop/f2lData.d.ts +15 -0
- package/cfop/f2lData.js +49 -0
- package/cfop/index.d.ts +41 -0
- package/cfop/index.js +110 -0
- package/cfop/slots.d.ts +2 -0
- package/cfop/slots.js +1 -0
- package/core/arrows.d.ts +24 -0
- package/core/arrows.js +22 -0
- package/core/bytes.d.ts +27 -0
- package/core/bytes.js +145 -0
- package/core/centers.d.ts +32 -0
- package/core/centers.js +83 -0
- package/core/checks.d.ts +53 -0
- package/core/checks.js +85 -0
- package/core/cubies.d.ts +45 -0
- package/core/cubies.js +169 -0
- package/core/frames.d.ts +61 -0
- package/core/frames.js +126 -0
- package/core/geometry.d.ts +58 -0
- package/core/geometry.js +132 -0
- package/core/index.d.ts +19 -0
- package/core/index.js +19 -0
- package/core/masks.d.ts +32 -0
- package/core/masks.js +39 -0
- package/core/method.d.ts +35 -0
- package/core/method.js +30 -0
- package/core/moves.d.ts +48 -0
- package/core/moves.js +88 -0
- package/core/notation.d.ts +48 -0
- package/core/notation.js +226 -0
- package/core/physical.d.ts +53 -0
- package/core/physical.js +99 -0
- package/core/practice.d.ts +62 -0
- package/core/practice.js +87 -0
- package/core/sequence.d.ts +90 -0
- package/core/sequence.js +157 -0
- package/core/stages.d.ts +90 -0
- package/core/stages.js +21 -0
- package/core/state.d.ts +55 -0
- package/core/state.js +140 -0
- package/core/stateCodec.d.ts +12 -0
- package/core/stateCodec.js +51 -0
- package/core/stream.d.ts +45 -0
- package/core/stream.js +75 -0
- package/core/tracker.d.ts +62 -0
- package/core/tracker.js +121 -0
- package/element/alg.d.ts +45 -0
- package/element/alg.js +150 -0
- package/element/base.d.ts +2 -0
- package/element/base.js +3 -0
- package/element/bld.d.ts +82 -0
- package/element/bld.js +222 -0
- package/element/index.d.ts +8 -0
- package/element/index.js +21 -0
- package/element/model.d.ts +36 -0
- package/element/model.js +64 -0
- package/element/player.d.ts +196 -0
- package/element/player.js +680 -0
- package/element/practice.d.ts +75 -0
- package/element/practice.js +150 -0
- package/element/scramble.d.ts +50 -0
- package/element/scramble.js +107 -0
- package/element/sequence.d.ts +126 -0
- package/element/sequence.js +254 -0
- package/element/styles.d.ts +32 -0
- package/element/styles.js +196 -0
- package/image/cache.d.ts +21 -0
- package/image/cache.js +66 -0
- package/image/index.d.ts +2 -0
- package/image/index.js +2 -0
- package/image/png-node.d.ts +6 -0
- package/image/png-node.js +10 -0
- package/image/svg.d.ts +36 -0
- package/image/svg.js +215 -0
- package/lbl/index.d.ts +10 -0
- package/lbl/index.js +31 -0
- package/methods/index.d.ts +20 -0
- package/methods/index.js +33 -0
- package/package.json +133 -0
- package/petrus/index.d.ts +11 -0
- package/petrus/index.js +27 -0
- package/react/index.d.ts +176 -0
- package/react/index.js +228 -0
- package/render/arrows.d.ts +68 -0
- package/render/arrows.js +190 -0
- package/render/build/attachments.d.ts +35 -0
- package/render/build/attachments.js +94 -0
- package/render/build/models.d.ts +9 -0
- package/render/build/models.js +27 -0
- package/render/build/tiles.d.ts +48 -0
- package/render/build/tiles.js +194 -0
- package/render/gltf.d.ts +10 -0
- package/render/gltf.js +106 -0
- package/render/index.d.ts +12 -0
- package/render/index.js +12 -0
- package/render/layers.d.ts +21 -0
- package/render/layers.js +24 -0
- package/render/pictures.d.ts +46 -0
- package/render/pictures.js +80 -0
- package/render/pieceModels.d.ts +38 -0
- package/render/pieceModels.js +43 -0
- package/render/renderer.d.ts +165 -0
- package/render/renderer.js +647 -0
- package/render/tile.d.ts +114 -0
- package/render/tile.js +390 -0
- package/render/viewports.d.ts +25 -0
- package/render/viewports.js +26 -0
- package/roux/cmll.d.ts +35 -0
- package/roux/cmll.js +121 -0
- package/roux/cmllData.d.ts +12 -0
- package/roux/cmllData.js +49 -0
- package/roux/index.d.ts +52 -0
- package/roux/index.js +175 -0
- package/skin/attachments.d.ts +82 -0
- package/skin/attachments.js +110 -0
- package/skin/index.d.ts +3 -0
- package/skin/index.js +3 -0
- package/skin/shapes.d.ts +112 -0
- package/skin/shapes.js +147 -0
- package/skin/skin.d.ts +911 -0
- package/skin/skin.js +412 -0
- package/solve/client.d.ts +58 -0
- package/solve/client.js +56 -0
- package/solve/handle.d.ts +6 -0
- package/solve/handle.js +38 -0
- package/solve/index.d.ts +8 -0
- package/solve/index.js +7 -0
- package/solve/lse.d.ts +42 -0
- package/solve/lse.js +151 -0
- package/solve/pieces.d.ts +18 -0
- package/solve/pieces.js +24 -0
- package/solve/protocol.d.ts +70 -0
- package/solve/protocol.js +16 -0
- package/solve/scramble.d.ts +76 -0
- package/solve/scramble.js +187 -0
- package/solve/stage.d.ts +108 -0
- package/solve/stage.js +532 -0
- package/solve/twophase.d.ts +36 -0
- package/solve/twophase.js +229 -0
- package/solve/worker.d.ts +6 -0
- package/solve/worker.js +15 -0
- package/timeline/codec.d.ts +23 -0
- package/timeline/codec.js +84 -0
- package/timeline/index.d.ts +7 -0
- package/timeline/index.js +7 -0
- package/timeline/recording.d.ts +19 -0
- package/timeline/recording.js +20 -0
- package/timeline/replay.d.ts +68 -0
- package/timeline/replay.js +145 -0
- package/timeline/segments.d.ts +31 -0
- package/timeline/segments.js +39 -0
- package/timeline/share.d.ts +30 -0
- package/timeline/share.js +62 -0
- package/timeline/stats.d.ts +34 -0
- package/timeline/stats.js +56 -0
- package/timeline/timings.d.ts +30 -0
- package/timeline/timings.js +54 -0
- package/zz/index.d.ts +29 -0
- package/zz/index.js +68 -0
- package/zz/seeds.d.ts +9 -0
- package/zz/seeds.js +29 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Practising an algorithm on a smart cube — SequenceTracker plus what a
|
|
3
|
+
* practice session needs: moves hidden until done (memory check), hints,
|
|
4
|
+
* mistakes, time and TPS, and noticing a different algorithm that solves
|
|
5
|
+
* the case all the same.
|
|
6
|
+
*
|
|
7
|
+
* reveal: "all" — every move shown (learning)
|
|
8
|
+
* "done" — dots, each move shown once it's done (default)
|
|
9
|
+
* "none" — dots to the end (test)
|
|
10
|
+
* `hint()` shows the next move; a slip shows it too unless hintOnMistake is off.
|
|
11
|
+
*/
|
|
12
|
+
import type { Move } from "./moves.js";
|
|
13
|
+
import { type NextTurn, type SequenceOptions, type SequenceProgress, type TokenStatus } from "./sequence.js";
|
|
14
|
+
import type { State } from "./state.js";
|
|
15
|
+
export type Reveal = "all" | "done" | "none";
|
|
16
|
+
export interface PracticeOptions extends SequenceOptions {
|
|
17
|
+
reveal?: Reveal;
|
|
18
|
+
/** Show the next move after a slip. Default true. */
|
|
19
|
+
hintOnMistake?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface PracticeToken {
|
|
22
|
+
/** The move as written. */
|
|
23
|
+
move: Move;
|
|
24
|
+
status: TokenStatus;
|
|
25
|
+
/** Show it (else a dot). */
|
|
26
|
+
visible: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface PracticeProgress extends SequenceProgress {
|
|
29
|
+
practice: {
|
|
30
|
+
tokens: PracticeToken[];
|
|
31
|
+
mistakes: number;
|
|
32
|
+
/** Face turns made so far. */
|
|
33
|
+
turns: number;
|
|
34
|
+
/** ms from the first turn to the last one (or to completion). */
|
|
35
|
+
elapsedMs: number;
|
|
36
|
+
/** Turns per second over the attempt. */
|
|
37
|
+
tps: number;
|
|
38
|
+
/** Solved, but not with the written algorithm (the same end state another way). */
|
|
39
|
+
differentAlg: boolean;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export declare class PracticeTracker {
|
|
43
|
+
private readonly tracker;
|
|
44
|
+
private readonly revealed;
|
|
45
|
+
private reveal;
|
|
46
|
+
private readonly hintOnMistake;
|
|
47
|
+
private mistakes;
|
|
48
|
+
private turns;
|
|
49
|
+
private firstTime;
|
|
50
|
+
private lastTime;
|
|
51
|
+
private wasOff;
|
|
52
|
+
private solvedDifferently;
|
|
53
|
+
constructor(alg: string | readonly Move[], start: State, options?: PracticeOptions);
|
|
54
|
+
get written(): readonly Move[];
|
|
55
|
+
setReveal(reveal: Reveal): PracticeProgress;
|
|
56
|
+
/** Show the next move (the current one). */
|
|
57
|
+
hint(): PracticeProgress;
|
|
58
|
+
push(move: Move, time?: number): PracticeProgress;
|
|
59
|
+
/** What to turn now (see SequenceTracker.nextTurn); null for a hidden next move — Hint or a slip shows it. */
|
|
60
|
+
get nextTurn(): NextTurn | null;
|
|
61
|
+
get progress(): PracticeProgress;
|
|
62
|
+
}
|
package/core/practice.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Practising an algorithm on a smart cube — SequenceTracker plus what a
|
|
3
|
+
* practice session needs: moves hidden until done (memory check), hints,
|
|
4
|
+
* mistakes, time and TPS, and noticing a different algorithm that solves
|
|
5
|
+
* the case all the same.
|
|
6
|
+
*
|
|
7
|
+
* reveal: "all" — every move shown (learning)
|
|
8
|
+
* "done" — dots, each move shown once it's done (default)
|
|
9
|
+
* "none" — dots to the end (test)
|
|
10
|
+
* `hint()` shows the next move; a slip shows it too unless hintOnMistake is off.
|
|
11
|
+
*/
|
|
12
|
+
import { SequenceTracker } from "./sequence.js";
|
|
13
|
+
export class PracticeTracker {
|
|
14
|
+
tracker;
|
|
15
|
+
revealed = new Set();
|
|
16
|
+
reveal;
|
|
17
|
+
hintOnMistake;
|
|
18
|
+
mistakes = 0;
|
|
19
|
+
turns = [];
|
|
20
|
+
firstTime = null;
|
|
21
|
+
lastTime = 0;
|
|
22
|
+
wasOff = false;
|
|
23
|
+
solvedDifferently = false;
|
|
24
|
+
constructor(alg, start, options = {}) {
|
|
25
|
+
this.tracker = new SequenceTracker(alg, start, options);
|
|
26
|
+
this.reveal = options.reveal ?? "done";
|
|
27
|
+
this.hintOnMistake = options.hintOnMistake ?? true;
|
|
28
|
+
}
|
|
29
|
+
get written() {
|
|
30
|
+
return this.tracker.written;
|
|
31
|
+
}
|
|
32
|
+
setReveal(reveal) {
|
|
33
|
+
this.reveal = reveal;
|
|
34
|
+
return this.progress;
|
|
35
|
+
}
|
|
36
|
+
/** Show the next move (the current one). */
|
|
37
|
+
hint() {
|
|
38
|
+
const next = this.progress.tokens.findIndex((s) => s === "current" || s === "partial" || s === "wrong-way");
|
|
39
|
+
if (next >= 0)
|
|
40
|
+
this.revealed.add(next);
|
|
41
|
+
return this.progress;
|
|
42
|
+
}
|
|
43
|
+
push(move, time = Date.now()) {
|
|
44
|
+
this.firstTime ??= time;
|
|
45
|
+
this.lastTime = time;
|
|
46
|
+
this.turns.push(move);
|
|
47
|
+
const p = this.tracker.push(move);
|
|
48
|
+
// Reaching the end straight from off the path = the case solved another way.
|
|
49
|
+
if (p.complete && this.wasOff)
|
|
50
|
+
this.solvedDifferently = true;
|
|
51
|
+
const off = p.undo.length > 0;
|
|
52
|
+
if (off && !this.wasOff) {
|
|
53
|
+
this.mistakes++;
|
|
54
|
+
if (this.hintOnMistake)
|
|
55
|
+
this.hint();
|
|
56
|
+
}
|
|
57
|
+
this.wasOff = off;
|
|
58
|
+
return this.progress;
|
|
59
|
+
}
|
|
60
|
+
/** What to turn now (see SequenceTracker.nextTurn); null for a hidden next move — Hint or a slip shows it. */
|
|
61
|
+
get nextTurn() {
|
|
62
|
+
const t = this.tracker.nextTurn;
|
|
63
|
+
if (!t || t.token === null)
|
|
64
|
+
return t;
|
|
65
|
+
return this.progress.practice.tokens[t.token]?.visible ? t : null;
|
|
66
|
+
}
|
|
67
|
+
get progress() {
|
|
68
|
+
const p = this.tracker.progress;
|
|
69
|
+
const tokens = this.tracker.written.map((move, i) => {
|
|
70
|
+
const status = p.tokens[i];
|
|
71
|
+
const visible = this.reveal === "all" || this.revealed.has(i) || (this.reveal === "done" && (status === "done" || status === "partial"));
|
|
72
|
+
return { move, status, visible };
|
|
73
|
+
});
|
|
74
|
+
const elapsedMs = this.firstTime === null ? 0 : this.lastTime - this.firstTime;
|
|
75
|
+
return {
|
|
76
|
+
...p,
|
|
77
|
+
practice: {
|
|
78
|
+
tokens,
|
|
79
|
+
mistakes: this.mistakes,
|
|
80
|
+
turns: this.turns.length,
|
|
81
|
+
elapsedMs,
|
|
82
|
+
tps: elapsedMs > 0 ? this.turns.length / (elapsedMs / 1000) : 0,
|
|
83
|
+
differentAlg: p.complete && this.solvedDifferently,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Following a scramble (or an algorithm) on a smart cube: which moves are
|
|
3
|
+
* done, which one is under way, and — after a slip — what to undo.
|
|
4
|
+
*
|
|
5
|
+
* It matches CUBE STATES, not move strings, so everything that reaches the
|
|
6
|
+
* same state counts:
|
|
7
|
+
* - a half turn done as two quarter turns, either way (half done = `partial`);
|
|
8
|
+
* - opposite faces in the other order (R L done as L R);
|
|
9
|
+
* - an algorithm written with rotations, slices and wide moves (converted
|
|
10
|
+
* with toFaceTurns: what the smart cube will actually report).
|
|
11
|
+
* Off the path, `undo` is the way back to the last matching point (the
|
|
12
|
+
* slip, simplified: R R' cancels) and `needsReset` says it's too long.
|
|
13
|
+
*/
|
|
14
|
+
import { type TurnArrow } from "./arrows.js";
|
|
15
|
+
import type { Frame } from "./frames.js";
|
|
16
|
+
import type { Move } from "./moves.js";
|
|
17
|
+
import { type State } from "./state.js";
|
|
18
|
+
export interface SequenceStep {
|
|
19
|
+
/** The face turn the cube will report. */
|
|
20
|
+
move: Move;
|
|
21
|
+
/** Index of the written move (token) it belongs to — several steps for M, none for a rotation. */
|
|
22
|
+
token: number;
|
|
23
|
+
}
|
|
24
|
+
/** "wrong-way": the move due, its face turned the wrong way (or too far) — turn it back / on, no real slip. */
|
|
25
|
+
export type TokenStatus = "done" | "partial" | "current" | "wrong-way" | "todo";
|
|
26
|
+
export interface SequenceProgress {
|
|
27
|
+
/** Face-turn steps fully done. */
|
|
28
|
+
done: number;
|
|
29
|
+
total: number;
|
|
30
|
+
/** The next step is a half turn and half of it is done. */
|
|
31
|
+
partial: boolean;
|
|
32
|
+
/** Status of each written move (for display). */
|
|
33
|
+
tokens: TokenStatus[];
|
|
34
|
+
/** Moves that bring the cube back to the last matching point (empty when on track). */
|
|
35
|
+
undo: Move[];
|
|
36
|
+
/** The slip is longer than `maxCorrection`: better to reset / solve and start over. */
|
|
37
|
+
needsReset: boolean;
|
|
38
|
+
/** The only slip is the move due turned the wrong way (or too far) — the right face, fix it with that face. */
|
|
39
|
+
wrongWay: boolean;
|
|
40
|
+
complete: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** What to turn now — for arrows on a 3D cube (see arrows.ts). */
|
|
43
|
+
export interface NextTurn {
|
|
44
|
+
/**
|
|
45
|
+
* "next": the next move of the sequence; "undo": the first move back after
|
|
46
|
+
* a slip; "wrong-way": the same, when the slip was the right face turned
|
|
47
|
+
* the wrong way (or too far) — worth a colour of its own.
|
|
48
|
+
*/
|
|
49
|
+
kind: "next" | "undo" | "wrong-way";
|
|
50
|
+
/** In the cube's own coordinates. Usually one; the rest of an M done half-way can be two. */
|
|
51
|
+
arrows: TurnArrow[];
|
|
52
|
+
/** The written move it belongs to (null for undo). */
|
|
53
|
+
token: number | null;
|
|
54
|
+
}
|
|
55
|
+
export interface SequenceOptions {
|
|
56
|
+
/** Longest undo worth showing (act's rule: 25). */
|
|
57
|
+
maxCorrection?: number;
|
|
58
|
+
/**
|
|
59
|
+
* How the cube is held at the start (default: its own U on top, F in
|
|
60
|
+
* front) — e.g. after an algorithm with a net rotation (M, wide moves) the
|
|
61
|
+
* next one is written for the cube as now held.
|
|
62
|
+
*/
|
|
63
|
+
frame?: Frame;
|
|
64
|
+
}
|
|
65
|
+
export declare class SequenceTracker {
|
|
66
|
+
readonly written: Move[];
|
|
67
|
+
readonly steps: SequenceStep[];
|
|
68
|
+
/** How the cube is held before each written move (rotations and slices change it). */
|
|
69
|
+
readonly frames: Frame[];
|
|
70
|
+
private readonly path;
|
|
71
|
+
private cur;
|
|
72
|
+
private anchor;
|
|
73
|
+
private anchorPartial;
|
|
74
|
+
private offPath;
|
|
75
|
+
private readonly maxCorrection;
|
|
76
|
+
constructor(target: string | readonly Move[], start: State, options?: SequenceOptions);
|
|
77
|
+
get state(): State;
|
|
78
|
+
/** A face turn reported by the cube. */
|
|
79
|
+
push(move: Move): SequenceProgress;
|
|
80
|
+
get progress(): SequenceProgress;
|
|
81
|
+
/**
|
|
82
|
+
* What to turn now, for an arrow: after a slip the first undo move; half way
|
|
83
|
+
* through a half turn the remaining quarter (the way it was started); else
|
|
84
|
+
* the next written move as written — a wide r stays two layers, an M the
|
|
85
|
+
* middle one — placed where it is on the cube as now held. Null when complete.
|
|
86
|
+
*/
|
|
87
|
+
get nextTurn(): NextTurn | null;
|
|
88
|
+
/** Where the current state is on the path, if anywhere: after `done` steps (+ half of the next one). */
|
|
89
|
+
private locate;
|
|
90
|
+
}
|
package/core/sequence.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Following a scramble (or an algorithm) on a smart cube: which moves are
|
|
3
|
+
* done, which one is under way, and — after a slip — what to undo.
|
|
4
|
+
*
|
|
5
|
+
* It matches CUBE STATES, not move strings, so everything that reaches the
|
|
6
|
+
* same state counts:
|
|
7
|
+
* - a half turn done as two quarter turns, either way (half done = `partial`);
|
|
8
|
+
* - opposite faces in the other order (R L done as L R);
|
|
9
|
+
* - an algorithm written with rotations, slices and wide moves (converted
|
|
10
|
+
* with toFaceTurns: what the smart cube will actually report).
|
|
11
|
+
* Off the path, `undo` is the way back to the last matching point (the
|
|
12
|
+
* slip, simplified: R R' cancels) and `needsReset` says it's too long.
|
|
13
|
+
*/
|
|
14
|
+
import { turnArrow } from "./arrows.js";
|
|
15
|
+
import { invert, parseAlg, simplify } from "./notation.js";
|
|
16
|
+
import { OrientationTracker } from "./physical.js";
|
|
17
|
+
import { applyMove, statesEqual } from "./state.js";
|
|
18
|
+
export class SequenceTracker {
|
|
19
|
+
written;
|
|
20
|
+
steps;
|
|
21
|
+
/** How the cube is held before each written move (rotations and slices change it). */
|
|
22
|
+
frames;
|
|
23
|
+
path; // state after k steps
|
|
24
|
+
cur;
|
|
25
|
+
anchor = 0; // last matching step index
|
|
26
|
+
anchorPartial = false;
|
|
27
|
+
offPath = []; // moves since the last matching point
|
|
28
|
+
maxCorrection;
|
|
29
|
+
constructor(target, start, options = {}) {
|
|
30
|
+
this.written = typeof target === "string" ? parseAlg(target) : [...target];
|
|
31
|
+
this.maxCorrection = options.maxCorrection ?? 25;
|
|
32
|
+
const grip = new OrientationTracker(options.frame);
|
|
33
|
+
this.frames = [];
|
|
34
|
+
this.steps = this.written.flatMap((m, token) => {
|
|
35
|
+
this.frames.push(grip.frame);
|
|
36
|
+
return grip.push(m).map((move) => ({ move, token }));
|
|
37
|
+
});
|
|
38
|
+
this.path = [new Uint8Array(start)];
|
|
39
|
+
for (const s of this.steps)
|
|
40
|
+
this.path.push(applyMove(this.path[this.path.length - 1], s.move));
|
|
41
|
+
this.cur = new Uint8Array(start);
|
|
42
|
+
}
|
|
43
|
+
get state() {
|
|
44
|
+
return this.cur;
|
|
45
|
+
}
|
|
46
|
+
/** A face turn reported by the cube. */
|
|
47
|
+
push(move) {
|
|
48
|
+
this.cur = applyMove(this.cur, move);
|
|
49
|
+
const on = this.locate();
|
|
50
|
+
if (on) {
|
|
51
|
+
this.anchor = on.done;
|
|
52
|
+
this.anchorPartial = on.partial;
|
|
53
|
+
this.offPath = [];
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.offPath.push(move);
|
|
57
|
+
}
|
|
58
|
+
return this.progress;
|
|
59
|
+
}
|
|
60
|
+
get progress() {
|
|
61
|
+
const total = this.steps.length;
|
|
62
|
+
const undo = this.offPath.length ? invert(simplify(this.offPath)) : [];
|
|
63
|
+
const done = this.anchor;
|
|
64
|
+
const partial = this.anchorPartial && !this.offPath.length;
|
|
65
|
+
const next = done < total ? this.steps[done].token : this.written.length;
|
|
66
|
+
const expected = this.steps[done]?.move;
|
|
67
|
+
const wrongWay = undo.length === 1 && expected !== undefined && undo[0].family === expected.family;
|
|
68
|
+
const tokens = this.written.map((_, t) => {
|
|
69
|
+
const idx = this.steps.map((s, i) => (s.token === t ? i : -1)).filter((i) => i >= 0);
|
|
70
|
+
if (!idx.length)
|
|
71
|
+
return t < next ? "done" : "todo"; // a rotation: done once the cube gets past it
|
|
72
|
+
const first = idx[0], last = idx[idx.length - 1];
|
|
73
|
+
if (last < done)
|
|
74
|
+
return "done";
|
|
75
|
+
if (first < done || (first === done && partial))
|
|
76
|
+
return "partial"; // M half done, or half of an R2
|
|
77
|
+
if (first === done && wrongWay)
|
|
78
|
+
return "wrong-way";
|
|
79
|
+
return first === done ? "current" : "todo";
|
|
80
|
+
});
|
|
81
|
+
return { done, total, partial, tokens, undo, needsReset: undo.length > this.maxCorrection, wrongWay, complete: done === total && !this.offPath.length };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* What to turn now, for an arrow: after a slip the first undo move; half way
|
|
85
|
+
* through a half turn the remaining quarter (the way it was started); else
|
|
86
|
+
* the next written move as written — a wide r stays two layers, an M the
|
|
87
|
+
* middle one — placed where it is on the cube as now held. Null when complete.
|
|
88
|
+
*/
|
|
89
|
+
get nextTurn() {
|
|
90
|
+
const p = this.progress;
|
|
91
|
+
if (p.complete)
|
|
92
|
+
return null;
|
|
93
|
+
if (p.wrongWay) {
|
|
94
|
+
// The face due went the wrong way (or too far): the turn to where it should be —
|
|
95
|
+
// back and on in one go (U instead of U': a U2 the way U' goes).
|
|
96
|
+
const expected = this.steps[p.done].move;
|
|
97
|
+
const back = p.undo[0];
|
|
98
|
+
const signed = (m) => (m.amount === 2 ? 2 * Math.sign(m.written ?? 2) : m.amount);
|
|
99
|
+
let q = signed(back) + (expected.amount === 2 ? 2 * (Math.sign(signed(back)) || 1) : expected.amount);
|
|
100
|
+
q = ((q % 4) + 4) % 4;
|
|
101
|
+
const amount = (q === 3 ? -1 : q);
|
|
102
|
+
const fix = amount === 2 ? { family: expected.family, amount: 2, written: 2 * (Math.sign(signed(expected)) || 1) } : { family: expected.family, amount };
|
|
103
|
+
return { kind: "wrong-way", arrows: [turnArrow(fix)], token: this.steps[p.done].token };
|
|
104
|
+
}
|
|
105
|
+
if (p.undo.length) {
|
|
106
|
+
return { kind: "undo", arrows: [turnArrow(p.undo[0])], token: null };
|
|
107
|
+
}
|
|
108
|
+
const k = p.done;
|
|
109
|
+
const step = this.steps[k];
|
|
110
|
+
if (!step)
|
|
111
|
+
return null;
|
|
112
|
+
const next = (moves) => ({ kind: "next", arrows: moves.map((m) => turnArrow(m)), token: step.token });
|
|
113
|
+
if (p.partial) {
|
|
114
|
+
if (step.move.amount === 2) {
|
|
115
|
+
for (const amount of [1, -1]) {
|
|
116
|
+
const half = { family: step.move.family, amount };
|
|
117
|
+
if (statesEqual(applyMove(this.path[k], half), this.cur))
|
|
118
|
+
return next([half]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return next([step.move]); // the opposite face went first: this one is left
|
|
122
|
+
}
|
|
123
|
+
const first = this.steps.findIndex((s) => s.token === step.token);
|
|
124
|
+
if (first < k) {
|
|
125
|
+
// A slice / wide move partly done (its face turns arrive one by one): what's left of it.
|
|
126
|
+
return next(this.steps.slice(k).filter((s) => s.token === step.token).map((s) => s.move));
|
|
127
|
+
}
|
|
128
|
+
return { kind: "next", arrows: [turnArrow(this.written[step.token], this.frames[step.token])], token: step.token };
|
|
129
|
+
}
|
|
130
|
+
/** Where the current state is on the path, if anywhere: after `done` steps (+ half of the next one). */
|
|
131
|
+
locate() {
|
|
132
|
+
for (let k = this.path.length - 1; k >= 0; k--)
|
|
133
|
+
if (statesEqual(this.path[k], this.cur))
|
|
134
|
+
return { done: k, partial: false };
|
|
135
|
+
for (let k = 0; k < this.steps.length; k++) {
|
|
136
|
+
const s = this.steps[k].move;
|
|
137
|
+
// Half of a half turn, either way.
|
|
138
|
+
if (s.amount === 2) {
|
|
139
|
+
for (const amount of [1, -1]) {
|
|
140
|
+
if (statesEqual(applyMove(this.path[k], { family: s.family, amount }), this.cur))
|
|
141
|
+
return { done: k, partial: true };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// The next step on the opposite face done first (R L done as L R): count as progress on k.
|
|
145
|
+
const n = this.steps[k + 1];
|
|
146
|
+
if (n && opposite(s, n.move)) {
|
|
147
|
+
if (statesEqual(applyMove(this.path[k], n.move), this.cur))
|
|
148
|
+
return { done: k, partial: true };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const AXIS = { U: 1, D: 1, R: 0, L: 0, F: 2, B: 2 };
|
|
155
|
+
function opposite(a, b) {
|
|
156
|
+
return a.family !== b.family && AXIS[a.family] !== undefined && AXIS[a.family] === AXIS[b.family];
|
|
157
|
+
}
|
package/core/stages.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solving stages as plain data — which pieces a stage puts where — so
|
|
3
|
+
* method packages can describe their trainer stages (cross, XCross, Roux
|
|
4
|
+
* first square…) without depending on a solver; @cubecore/solve runs them.
|
|
5
|
+
*
|
|
6
|
+
* Canonical frame: cross / first layer on D, F2L slots FR FL BL BR, Roux
|
|
7
|
+
* first block on L-bottom. Pieces use the Kociemba ids of core cubies.ts
|
|
8
|
+
* (edges UR UF UL UB DR DF DL DB FR FL BL BR, corners URF UFL ULB UBR DFR
|
|
9
|
+
* DLF DBL DRB).
|
|
10
|
+
*/
|
|
11
|
+
export interface Piece {
|
|
12
|
+
kind: "edge" | "corner";
|
|
13
|
+
/** Kociemba piece id. */
|
|
14
|
+
id: number;
|
|
15
|
+
}
|
|
16
|
+
export interface StageDef {
|
|
17
|
+
name: string;
|
|
18
|
+
pieces: readonly Piece[];
|
|
19
|
+
/** Also orient every edge (EOCross). */
|
|
20
|
+
eo?: boolean;
|
|
21
|
+
/** Groups (indices into `pieces`) with exact distance tables; the heuristic is their max. At most 5 pieces each. */
|
|
22
|
+
groups: readonly (readonly number[])[];
|
|
23
|
+
/**
|
|
24
|
+
* The stage is done in any of these states — algorithms applied to a
|
|
25
|
+
* solved cube (canonical frame), e.g. a pair "one insert away". Default:
|
|
26
|
+
* the pieces at home.
|
|
27
|
+
*/
|
|
28
|
+
goals?: readonly string[];
|
|
29
|
+
/** Indices into `pieces` kept solved in trainer cases (e.g. the first block while practising the second square). */
|
|
30
|
+
keep?: readonly number[];
|
|
31
|
+
/**
|
|
32
|
+
* The block may be built with any of the four x rotations (Roux first
|
|
33
|
+
* block / square: any bottom colour on the L side) — the distance is the
|
|
34
|
+
* best of them. Trainer cases are then drawn from whole random states.
|
|
35
|
+
*/
|
|
36
|
+
neutral?: "x";
|
|
37
|
+
/**
|
|
38
|
+
* Known cases for levels too rare to draw at run time (EOCross at 10: a
|
|
39
|
+
* few in a million): depth → placements "v.v.v…:flip" (each piece's
|
|
40
|
+
* value in `pieces` order, position × orientations + orientation; flip
|
|
41
|
+
* for EO stages). Found once offline; the rest of the cube stays random.
|
|
42
|
+
*/
|
|
43
|
+
seeds?: Readonly<Record<number, readonly string[]>>;
|
|
44
|
+
/**
|
|
45
|
+
* Faces the solution may turn (default all six) — e.g. ["R", "U", "L"]
|
|
46
|
+
* for ZZ's F2L, which keeps every edge oriented.
|
|
47
|
+
*/
|
|
48
|
+
moves?: readonly ("U" | "R" | "F" | "D" | "L" | "B")[];
|
|
49
|
+
}
|
|
50
|
+
export declare const edgePiece: (id: number) => Piece;
|
|
51
|
+
export declare const cornerPiece: (id: number) => Piece;
|
|
52
|
+
/** Named pieces (canonical positions). */
|
|
53
|
+
export declare const PIECE: {
|
|
54
|
+
readonly UR: Piece;
|
|
55
|
+
readonly UF: Piece;
|
|
56
|
+
readonly UL: Piece;
|
|
57
|
+
readonly UB: Piece;
|
|
58
|
+
readonly DR: Piece;
|
|
59
|
+
readonly DF: Piece;
|
|
60
|
+
readonly DL: Piece;
|
|
61
|
+
readonly DB: Piece;
|
|
62
|
+
readonly FR: Piece;
|
|
63
|
+
readonly FL: Piece;
|
|
64
|
+
readonly BL: Piece;
|
|
65
|
+
readonly BR: Piece;
|
|
66
|
+
readonly URF: Piece;
|
|
67
|
+
readonly UFL: Piece;
|
|
68
|
+
readonly ULB: Piece;
|
|
69
|
+
readonly UBR: Piece;
|
|
70
|
+
readonly DFR: Piece;
|
|
71
|
+
readonly DLF: Piece;
|
|
72
|
+
readonly DBL: Piece;
|
|
73
|
+
readonly DRB: Piece;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* A last-six-edges stage (Roux): moves are M and U only, the blocks and
|
|
77
|
+
* CMLL stay solved; done in any of `goals` (algorithms from a solved cube),
|
|
78
|
+
* compared on what the stage is about:
|
|
79
|
+
* `features: "eolr"` — edge orientation of the six edges, where UL and UR
|
|
80
|
+
* are, centres and corner AUF (the other four edges' order is the next
|
|
81
|
+
* step's business); `"lse"` — everything (the whole of LSE).
|
|
82
|
+
*/
|
|
83
|
+
export interface LseStageDef {
|
|
84
|
+
name: string;
|
|
85
|
+
kind: "lse";
|
|
86
|
+
features: "eolr" | "lse";
|
|
87
|
+
goals: readonly string[];
|
|
88
|
+
}
|
|
89
|
+
export type AnyStageDef = StageDef | LseStageDef;
|
|
90
|
+
export declare const isLseStage: (def: AnyStageDef) => def is LseStageDef;
|
package/core/stages.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solving stages as plain data — which pieces a stage puts where — so
|
|
3
|
+
* method packages can describe their trainer stages (cross, XCross, Roux
|
|
4
|
+
* first square…) without depending on a solver; @cubecore/solve runs them.
|
|
5
|
+
*
|
|
6
|
+
* Canonical frame: cross / first layer on D, F2L slots FR FL BL BR, Roux
|
|
7
|
+
* first block on L-bottom. Pieces use the Kociemba ids of core cubies.ts
|
|
8
|
+
* (edges UR UF UL UB DR DF DL DB FR FL BL BR, corners URF UFL ULB UBR DFR
|
|
9
|
+
* DLF DBL DRB).
|
|
10
|
+
*/
|
|
11
|
+
export const edgePiece = (id) => ({ kind: "edge", id });
|
|
12
|
+
export const cornerPiece = (id) => ({ kind: "corner", id });
|
|
13
|
+
/** Named pieces (canonical positions). */
|
|
14
|
+
export const PIECE = {
|
|
15
|
+
UR: edgePiece(0), UF: edgePiece(1), UL: edgePiece(2), UB: edgePiece(3),
|
|
16
|
+
DR: edgePiece(4), DF: edgePiece(5), DL: edgePiece(6), DB: edgePiece(7),
|
|
17
|
+
FR: edgePiece(8), FL: edgePiece(9), BL: edgePiece(10), BR: edgePiece(11),
|
|
18
|
+
URF: cornerPiece(0), UFL: cornerPiece(1), ULB: cornerPiece(2), UBR: cornerPiece(3),
|
|
19
|
+
DFR: cornerPiece(4), DLF: cornerPiece(5), DBL: cornerPiece(6), DRB: cornerPiece(7),
|
|
20
|
+
};
|
|
21
|
+
export const isLseStage = (def) => def.kind === "lse";
|
package/core/state.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cube state: 54 stickers, each carrying the index of its HOME facelet in the
|
|
3
|
+
* solved cube (so pieces keep their identity — masks and rendering follow
|
|
4
|
+
* them). A sticker's colour class is its home face: `colorOf(id) = id / 9`.
|
|
5
|
+
*
|
|
6
|
+
* Nothing here assumes a colour scheme or an orientation: "solved" means
|
|
7
|
+
* every face shows a single colour class, whichever it is. Real colours are
|
|
8
|
+
* the renderer's business (colour class → colour of a scheme).
|
|
9
|
+
*/
|
|
10
|
+
import { CUBIE_OF_FACELET, FACELETS, type Face } from "./geometry.js";
|
|
11
|
+
import { type Move, type Permutation } from "./moves.js";
|
|
12
|
+
export type State = Uint8Array;
|
|
13
|
+
/** Colour class 0..5 = the home face (U R F D L B order) of a sticker. */
|
|
14
|
+
export type ColorClass = number;
|
|
15
|
+
export declare function solvedState(): State;
|
|
16
|
+
export declare const colorOf: (sticker: number) => ColorClass;
|
|
17
|
+
/** Colour class shown at facelet position `i`. */
|
|
18
|
+
export declare const colorAt: (state: State, i: number) => ColorClass;
|
|
19
|
+
/** Colour class of the centre currently on `face`. */
|
|
20
|
+
export declare const centerColor: (state: State, face: Face) => ColorClass;
|
|
21
|
+
export declare function applyPermutation(state: State, perm: Permutation): State;
|
|
22
|
+
export declare function applyMove(state: State, move: Move): State;
|
|
23
|
+
export declare function applyMoves(state: State, moves: readonly Move[] | string): State;
|
|
24
|
+
export declare function statesEqual(a: State, b: State): boolean;
|
|
25
|
+
/** Every face shows one colour (any orientation, any scheme). */
|
|
26
|
+
export declare function isSolved(state: State): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 54 letters in U R F D L B facelet order, each naming the face whose home
|
|
29
|
+
* colour the sticker has — e.g. the solved cube is "UUUUUUUUURRR…BBB".
|
|
30
|
+
* This is what smart cubes and most solvers exchange.
|
|
31
|
+
*/
|
|
32
|
+
export declare function toFaceletString(state: State): string;
|
|
33
|
+
/**
|
|
34
|
+
* Build a state from a facelet string. Stickers get their identity by matching
|
|
35
|
+
* each piece's colour set to its home piece; throws if the colours don't form a
|
|
36
|
+
* real cube (wrong counts or a piece that doesn't exist).
|
|
37
|
+
*/
|
|
38
|
+
export declare function fromFaceletString(text: string): State;
|
|
39
|
+
export declare class CubeState {
|
|
40
|
+
private s;
|
|
41
|
+
constructor(initial?: State);
|
|
42
|
+
get state(): State;
|
|
43
|
+
apply(moves: Move | readonly Move[] | string): this;
|
|
44
|
+
reset(state?: State): this;
|
|
45
|
+
isSolved(): boolean;
|
|
46
|
+
clone(): CubeState;
|
|
47
|
+
}
|
|
48
|
+
export { CUBIE_OF_FACELET, FACELETS };
|
|
49
|
+
/**
|
|
50
|
+
* The state whose solution is the way from `from` to `to`: solving it gives
|
|
51
|
+
* moves M with applyMoves(from, M) = to. Lets any solver (and so any
|
|
52
|
+
* scramble generator) work from wherever the physical cube is now — a smart
|
|
53
|
+
* cube between attempts doesn't have to be solved first.
|
|
54
|
+
*/
|
|
55
|
+
export declare function relativeState(from: State, to: State): State;
|