@wodzik/cubecore 0.1.6 → 0.1.8
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/bluetooth/rotations.d.ts +14 -2
- package/bluetooth/rotations.js +14 -17
- package/package.json +1 -1
package/bluetooth/rotations.d.ts
CHANGED
|
@@ -60,9 +60,21 @@ export declare function heldMove(move: string, grip: Grip): string;
|
|
|
60
60
|
* y2, y y' = nothing), and slices / wide moves read from face moves with
|
|
61
61
|
* the core's rotation.
|
|
62
62
|
*/
|
|
63
|
-
export
|
|
63
|
+
export interface HeldOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Wide moves to read from one face turn and the core's rotation — the rest
|
|
66
|
+
* stay a face turn and a rotation. Default r, l, f, b: a u or d is almost
|
|
67
|
+
* always a U / D turn and a y regrip.
|
|
68
|
+
*/
|
|
69
|
+
wide?: readonly string[];
|
|
70
|
+
/** Slices to read from both faces of an axis and the core's rotation (default M, E, S); the rest stay two face turns and a rotation. */
|
|
71
|
+
slices?: readonly string[];
|
|
72
|
+
}
|
|
73
|
+
export declare const DEFAULT_WIDE: readonly string[];
|
|
74
|
+
export declare const DEFAULT_SLICES: readonly string[];
|
|
75
|
+
export declare function heldTokens(moves: readonly TimedMove[], startRotation: string, rotations: readonly RotationRecord[], options?: HeldOptions): HeldToken[];
|
|
64
76
|
/** A rotation and the face moves around it that make a slice / wide move → that move. */
|
|
65
|
-
export declare function mergeSlicesAndWides(tokens: readonly HeldToken[]): HeldToken[];
|
|
77
|
+
export declare function mergeSlicesAndWides(tokens: readonly HeldToken[], allowed?: ReadonlySet<string>): HeldToken[];
|
|
66
78
|
export interface GripEvent {
|
|
67
79
|
/** Moves the session had reported before it (its stream position). */
|
|
68
80
|
after: number;
|
package/bluetooth/rotations.js
CHANGED
|
@@ -28,16 +28,12 @@ export function heldMove(move, grip) {
|
|
|
28
28
|
const canonical = Object.keys(grip.face).find((c) => grip.face[c] === face);
|
|
29
29
|
return canonical ? canonical + move.slice(1) : move;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* y2, y y' = nothing), and slices / wide moves read from face moves with
|
|
36
|
-
* the core's rotation.
|
|
37
|
-
*/
|
|
38
|
-
export function heldTokens(moves, startRotation, rotations) {
|
|
31
|
+
export const DEFAULT_WIDE = ["r", "l", "f", "b"];
|
|
32
|
+
export const DEFAULT_SLICES = ["M", "E", "S"];
|
|
33
|
+
export function heldTokens(moves, startRotation, rotations, options = {}) {
|
|
34
|
+
const allowed = new Set([...(options.wide ?? DEFAULT_WIDE), ...(options.slices ?? DEFAULT_SLICES)]);
|
|
39
35
|
let grip = rotateGrip(IDENTITY_GRIP, startRotation);
|
|
40
|
-
const rots = snapToSlices(moves, grip, [...rotations].sort((a, b) => a.after - b.after || a.t - b.t));
|
|
36
|
+
const rots = snapToSlices(moves, grip, [...rotations].sort((a, b) => a.after - b.after || a.t - b.t), allowed);
|
|
41
37
|
const tokens = [];
|
|
42
38
|
let r = 0;
|
|
43
39
|
for (let i = 0; i <= moves.length; i++) {
|
|
@@ -58,7 +54,7 @@ export function heldTokens(moves, startRotation, rotations) {
|
|
|
58
54
|
if (i < moves.length)
|
|
59
55
|
tokens.push({ kind: "move", move: heldMove(moves[i].move, grip), t: moves[i].t, index: i });
|
|
60
56
|
}
|
|
61
|
-
return mergeSlicesAndWides(tokens);
|
|
57
|
+
return mergeSlicesAndWides(tokens, allowed);
|
|
62
58
|
}
|
|
63
59
|
// ─── slices and wide moves ──────────────────────────────────────────────
|
|
64
60
|
/** A slice / wide move's face moves and its rotation, reported this far apart (ms), are one move. */
|
|
@@ -74,12 +70,13 @@ const AXIS_FACES = { x: ["R", "L"], y: ["U", "D"], z: ["F", "B"] };
|
|
|
74
70
|
const SLICE_WIDE = ["M", "E", "S", "r", "l", "u", "d", "f", "b"].flatMap((f) => [f, `${f}'`, `${f}2`]);
|
|
75
71
|
const effect = (alg) => applyMoves(solvedState(), alg).join();
|
|
76
72
|
const SLICE_WIDE_EFFECT = new Map();
|
|
77
|
-
/** The slice / wide move the group (held letters and a rotation) amounts to, or null. */
|
|
78
|
-
function sliceOrWide(group) {
|
|
73
|
+
/** The slice / wide move the group (held letters and a rotation) amounts to, if `allowed` (by its letter), or null. */
|
|
74
|
+
function sliceOrWide(group, allowed) {
|
|
79
75
|
if (SLICE_WIDE_EFFECT.size === 0)
|
|
80
76
|
for (const m of SLICE_WIDE)
|
|
81
77
|
SLICE_WIDE_EFFECT.set(effect(m), m);
|
|
82
|
-
|
|
78
|
+
const m = SLICE_WIDE_EFFECT.get(effect(group.join(" ")));
|
|
79
|
+
return m && allowed.has(m[0]) ? m : null;
|
|
83
80
|
}
|
|
84
81
|
/**
|
|
85
82
|
* The consecutive run (up to MAX_GROUP) of moves on the axis nearest to
|
|
@@ -111,7 +108,7 @@ function axisRun(moves, from, dir, onAxis, t) {
|
|
|
111
108
|
* slice's signature (both faces of the axis) is trusted: one face and a
|
|
112
109
|
* rotation could as well be a face turn and a real regrip.
|
|
113
110
|
*/
|
|
114
|
-
function snapToSlices(moves, startGrip, rotations) {
|
|
111
|
+
function snapToSlices(moves, startGrip, rotations, allowed) {
|
|
115
112
|
let grip = startGrip;
|
|
116
113
|
const out = rotations.map((r) => ({ ...r }));
|
|
117
114
|
for (const r of out) {
|
|
@@ -133,7 +130,7 @@ function snapToSlices(moves, startGrip, rotations) {
|
|
|
133
130
|
const far = idx.some((j) => Math.abs(moves[j].t - r.t) > SNAP_MS);
|
|
134
131
|
if (far && new Set(idx.map((j) => moves[j].move[0])).size < 2)
|
|
135
132
|
continue;
|
|
136
|
-
if (sliceOrWide([...letters(idx), r.move])) {
|
|
133
|
+
if (sliceOrWide([...letters(idx), r.move], allowed)) {
|
|
137
134
|
r.after = after;
|
|
138
135
|
// It happened with those moves: its time is theirs.
|
|
139
136
|
r.t = moves[after > idx[0] ? idx.at(-1) : idx[0]].t;
|
|
@@ -146,7 +143,7 @@ function snapToSlices(moves, startGrip, rotations) {
|
|
|
146
143
|
return out.sort((a, b) => a.after - b.after || a.t - b.t);
|
|
147
144
|
}
|
|
148
145
|
/** A rotation and the face moves around it that make a slice / wide move → that move. */
|
|
149
|
-
export function mergeSlicesAndWides(tokens) {
|
|
146
|
+
export function mergeSlicesAndWides(tokens, allowed = new Set([...DEFAULT_WIDE, ...DEFAULT_SLICES])) {
|
|
150
147
|
const out = [...tokens];
|
|
151
148
|
for (let k = 0; k < out.length; k++) {
|
|
152
149
|
const rot = out[k];
|
|
@@ -165,7 +162,7 @@ export function mergeSlicesAndWides(tokens) {
|
|
|
165
162
|
const groupMoves = group.filter((t) => t.kind === "move");
|
|
166
163
|
if (groupMoves.length !== group.length - 1 || groupMoves.some((m) => Math.abs(m.t - rot.t) > SAME_MOMENT_MS))
|
|
167
164
|
continue;
|
|
168
|
-
const merged = sliceOrWide(group.map((t) => t.move));
|
|
165
|
+
const merged = sliceOrWide(group.map((t) => t.move), allowed);
|
|
169
166
|
if (!merged)
|
|
170
167
|
continue;
|
|
171
168
|
const first = groupMoves[0];
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.8",
|
|
7
7
|
"description": "A 3×3×3 cube library for the web, built around smart (Bluetooth) cubes: state, notation, methods, solvers and scrambles, a three.js renderer with skins, pictures, web components, React bindings.",
|
|
8
8
|
"license": "MPL-2.0",
|
|
9
9
|
"author": "Tomasz Wodzikowski <wodziszczakow@gmail.com>",
|