cubing 0.26.3 → 0.26.6
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/dist/esm/alg/index.js +1 -1
- package/dist/esm/bluetooth/index.js +11 -7
- package/dist/esm/bluetooth/index.js.map +2 -2
- package/dist/esm/{chunk-4OCHKVLJ.js → chunk-7K6HJKEG.js} +5 -5
- package/dist/esm/chunk-7K6HJKEG.js.map +7 -0
- package/dist/esm/{chunk-DO7GZAW4.js → chunk-FCB447RN.js} +4 -4
- package/dist/esm/chunk-FCB447RN.js.map +7 -0
- package/dist/esm/{chunk-HD2CMNE4.js → chunk-GNKVWDWW.js} +7 -627
- package/dist/esm/chunk-GNKVWDWW.js.map +7 -0
- package/dist/esm/{chunk-ESSOEWR6.js → chunk-GOBAXDTU.js} +61 -341
- package/dist/esm/chunk-GOBAXDTU.js.map +7 -0
- package/dist/esm/{chunk-FB7SFELN.js → chunk-ITRA3DUQ.js} +2 -2
- package/dist/esm/{chunk-FB7SFELN.js.map → chunk-ITRA3DUQ.js.map} +0 -0
- package/dist/esm/{chunk-RGEST6KF.js → chunk-K62P6E3H.js} +7 -7
- package/dist/esm/{chunk-RGEST6KF.js.map → chunk-K62P6E3H.js.map} +0 -0
- package/dist/esm/{chunk-3NFDCQI2.js → chunk-LJBHUHEP.js} +2 -56
- package/dist/esm/{chunk-3NFDCQI2.js.map → chunk-LJBHUHEP.js.map} +3 -3
- package/dist/esm/{chunk-NSLR2SC4.js → chunk-NHCGS73I.js} +2 -2
- package/dist/esm/{chunk-NSLR2SC4.js.map → chunk-NHCGS73I.js.map} +0 -0
- package/dist/esm/{chunk-3ADPLDWG.js → chunk-TB6NTLZY.js} +370 -81
- package/dist/esm/chunk-TB6NTLZY.js.map +7 -0
- package/dist/esm/chunk-VCOUFQGJ.js +240 -0
- package/dist/esm/chunk-VCOUFQGJ.js.map +7 -0
- package/dist/esm/chunk-VFDAQ42O.js +684 -0
- package/dist/esm/chunk-VFDAQ42O.js.map +7 -0
- package/dist/esm/{chunk-ZPAGJE7S.js → chunk-WQK6XWML.js} +2 -2
- package/dist/esm/{chunk-ZPAGJE7S.js.map → chunk-WQK6XWML.js.map} +1 -1
- package/dist/esm/kpuzzle/index.js +4 -6
- package/dist/esm/notation/index.js +2 -2
- package/dist/esm/protocol/index.js +4 -4
- package/dist/esm/puzzle-geometry/index.js +2 -2
- package/dist/esm/puzzles/index.js +4 -12
- package/dist/esm/{puzzles-dynamic-side-events-CXNWDLKD.js → puzzles-dynamic-side-events-HOXBZYWI.js} +21 -21
- package/dist/esm/{puzzles-dynamic-side-events-CXNWDLKD.js.map → puzzles-dynamic-side-events-HOXBZYWI.js.map} +1 -1
- package/dist/esm/{puzzles-dynamic-unofficial-CKTRIKMY.js → puzzles-dynamic-unofficial-MGVOFUDR.js} +79 -79
- package/dist/esm/{puzzles-dynamic-unofficial-CKTRIKMY.js.map → puzzles-dynamic-unofficial-MGVOFUDR.js.map} +1 -1
- package/dist/esm/scramble/index.js +2 -6
- package/dist/esm/search/index.js +9 -10
- package/dist/esm/{search-dynamic-sgs-side-events-ZDPMZ4Y7.js → search-dynamic-sgs-side-events-KK62JAWA.js} +7 -6
- package/dist/esm/{search-dynamic-sgs-side-events-ZDPMZ4Y7.js.map → search-dynamic-sgs-side-events-KK62JAWA.js.map} +1 -1
- package/dist/esm/{search-dynamic-sgs-unofficial-RAGEBTDP.js → search-dynamic-sgs-unofficial-VLNIEUW3.js} +8 -7
- package/dist/esm/{search-dynamic-sgs-unofficial-RAGEBTDP.js.map → search-dynamic-sgs-unofficial-VLNIEUW3.js.map} +1 -1
- package/dist/esm/{search-dynamic-solve-4x4x4-W455FUFG.js → search-dynamic-solve-4x4x4-S5JPXMNU.js} +7 -6
- package/dist/esm/{search-dynamic-solve-4x4x4-W455FUFG.js.map → search-dynamic-solve-4x4x4-S5JPXMNU.js.map} +1 -1
- package/dist/esm/{search-dynamic-solve-fto-ZM45FTCO.js → search-dynamic-solve-fto-WROONLZS.js} +6 -6
- package/dist/esm/search-dynamic-solve-fto-WROONLZS.js.map +7 -0
- package/dist/esm/{search-dynamic-solve-kilominx-PAW6HKT5.js → search-dynamic-solve-kilominx-UEFJENHO.js} +2 -2
- package/dist/esm/{search-dynamic-solve-kilominx-PAW6HKT5.js.map → search-dynamic-solve-kilominx-UEFJENHO.js.map} +0 -0
- package/dist/esm/search-worker-inside-generated-string-AVMDARJP.js +3768 -0
- package/dist/esm/search-worker-inside-generated-string-AVMDARJP.js.map +7 -0
- package/dist/esm/{search-worker-js-entry-5IIKIMTU.js → search-worker-js-entry-KJRZ3CJQ.js} +22 -21
- package/dist/esm/{search-worker-js-entry-5IIKIMTU.js.map → search-worker-js-entry-KJRZ3CJQ.js.map} +1 -1
- package/dist/esm/{search-worker-ts-entry-BV3J54MW.js → search-worker-ts-entry-AFMPRPSV.js} +3 -3
- package/dist/esm/{search-worker-ts-entry-BV3J54MW.js.map → search-worker-ts-entry-AFMPRPSV.js.map} +0 -0
- package/dist/esm/stream/index.js +1 -1
- package/dist/esm/twisty/index.js +78 -38
- package/dist/esm/twisty/index.js.map +3 -3
- package/dist/esm/{twisty-dynamic-3d-KFFJZNMZ.js → twisty-dynamic-3d-AVZOMIIW.js} +25 -8
- package/dist/esm/twisty-dynamic-3d-AVZOMIIW.js.map +7 -0
- package/dist/types/{Alg-6f3dc52c.d.ts → Alg-5cf4b166.d.ts} +2 -2
- package/dist/types/{KPuzzleDefinition-121e85a8.d.ts → KState-84892e94.d.ts} +77 -5
- package/dist/types/{PuzzleLoader-9243f44d.d.ts → TwizzleLink-02cfe1b1.d.ts} +42 -145
- package/dist/types/alg/index.d.ts +3 -3
- package/dist/types/bluetooth/index.d.ts +4 -5
- package/dist/types/{bluetooth-puzzle-679d8ca3.d.ts → bluetooth-puzzle-0f2e5f07.d.ts} +2 -2
- package/dist/types/kpuzzle/index.d.ts +2 -8
- package/dist/types/notation/index.d.ts +1 -1
- package/dist/types/{outside-f7ba9c00.d.ts → outside-d0ced6cc.d.ts} +2 -2
- package/dist/types/{parse-6d363160.d.ts → parse-9db7ee51.d.ts} +1 -1
- package/dist/types/protocol/index.d.ts +3 -6
- package/dist/types/puzzle-geometry/index.d.ts +3 -3
- package/dist/types/puzzles/index.d.ts +6 -16
- package/dist/types/scramble/index.d.ts +3 -4
- package/dist/types/search/index.d.ts +3 -4
- package/dist/types/stream/index.d.ts +3 -4
- package/dist/types/twisty/index.d.ts +5 -6
- package/package.json +6 -2
- package/dist/esm/chunk-3ADPLDWG.js.map +0 -7
- package/dist/esm/chunk-4OCHKVLJ.js.map +0 -7
- package/dist/esm/chunk-DO7GZAW4.js.map +0 -7
- package/dist/esm/chunk-ESSOEWR6.js.map +0 -7
- package/dist/esm/chunk-HD2CMNE4.js.map +0 -7
- package/dist/esm/search-dynamic-solve-fto-ZM45FTCO.js.map +0 -7
- package/dist/esm/search-worker-inside-generated-string-VBEHCGJ6.js +0 -3768
- package/dist/esm/search-worker-inside-generated-string-VBEHCGJ6.js.map +0 -7
- package/dist/esm/twisty-dynamic-3d-KFFJZNMZ.js.map +0 -7
- package/dist/types/KState-73482114.d.ts +0 -70
package/dist/esm/alg/index.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
puzzles
|
|
3
|
-
} from "../chunk-ESSOEWR6.js";
|
|
4
|
-
import {
|
|
5
|
-
KState,
|
|
6
2
|
binaryComponentsToReid3x3x3,
|
|
7
|
-
experimental3x3x3KPuzzle,
|
|
8
3
|
twizzleBinaryToBinaryComponents
|
|
9
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-VCOUFQGJ.js";
|
|
5
|
+
import {
|
|
6
|
+
puzzles
|
|
7
|
+
} from "../chunk-GOBAXDTU.js";
|
|
8
|
+
import {
|
|
9
|
+
experimental3x3x3KPuzzle
|
|
10
|
+
} from "../chunk-VFDAQ42O.js";
|
|
11
|
+
import {
|
|
12
|
+
KState
|
|
13
|
+
} from "../chunk-GNKVWDWW.js";
|
|
10
14
|
import {
|
|
11
15
|
Alg,
|
|
12
16
|
Move,
|
|
13
17
|
experimentalAppendMove,
|
|
14
18
|
keyToMove
|
|
15
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-FCB447RN.js";
|
|
16
20
|
import "../chunk-MGJA5U5O.js";
|
|
17
21
|
|
|
18
22
|
// src/cubing/bluetooth/debug.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cubing/bluetooth/debug.ts", "../../../src/cubing/bluetooth/transformer.ts", "../../../src/cubing/bluetooth/smart-puzzle/bluetooth-puzzle.ts", "../../../src/cubing/bluetooth/keyboard.ts", "../../../src/cubing/bluetooth/connect/index.ts", "../../../src/cubing/bluetooth/smart-puzzle/gan.ts", "../../../src/cubing/vendor/unsafe-raw-aes/unsafe-raw-aes.ts", "../../../src/cubing/bluetooth/smart-puzzle/giiker.ts", "../../../src/cubing/bluetooth/smart-puzzle/gocube.ts", "../../../src/cubing/bluetooth/smart-puzzle/endianness.ts", "../../../src/cubing/bluetooth/smart-puzzle/Heykube.ts", "../../../src/cubing/bluetooth/smart-puzzle/connect.ts", "../../../src/cubing/bluetooth/smart-robot/GanRobot.ts", "../../../src/cubing/bluetooth/smart-robot/index.ts", "../../../src/cubing/bluetooth/smart-timer/GanTimer.ts", "../../../src/cubing/bluetooth/smart-timer/index.ts"],
|
|
4
|
-
"sourcesContent": ["let DEBUG_LOGGING_ENABLED = false;\n\nexport function enableDebugLogging(enable: boolean): void {\n DEBUG_LOGGING_ENABLED = enable;\n}\n\n// TODO: Remove this.\nexport function debugLog(...args: any[]): void {\n if (!DEBUG_LOGGING_ENABLED) {\n return;\n }\n\n if (console.info) {\n console.info(...args);\n } else {\n console.log(...args);\n }\n}\n", "import { Quaternion, Vector3 } from \"three\";\nimport type {\n MoveEvent,\n OrientationEvent,\n} from \"./smart-puzzle/bluetooth-puzzle\";\n\n// TODO: Combine orientation and moves into a single event to handle quaternion remapping.\nexport interface StreamTransformer {\n // Modifies the input.\n transformMove(moveEvent: MoveEvent): void;\n\n // Modifies the input.\n transformOrientation(orientationEvent: OrientationEvent): void;\n}\n\nfunction maxAxis(v: Vector3): string {\n const maxVal = Math.max(Math.abs(v.x), Math.abs(v.y), Math.abs(v.z));\n switch (maxVal) {\n case v.x:\n return \"x\";\n case -v.x:\n return \"-x\";\n case v.y:\n return \"y\";\n case -v.y:\n return \"-y\";\n case v.z:\n return \"z\";\n case -v.z:\n return \"-z\";\n default:\n throw new Error(\"Uh-oh.\");\n }\n}\n\nconst s2 = Math.sqrt(0.5);\n\nconst m: { [s: string]: Quaternion } = {\n \"y z\": new Quaternion(0, 0, 0, 1),\n \"-z y\": new Quaternion(s2, 0, 0, s2),\n \"x z\": new Quaternion(0, 0, -s2, s2),\n \"-x z\": new Quaternion(0, 0, s2, s2),\n};\n\nexport class BasicRotationTransformer implements StreamTransformer {\n // private reorientQuat = new Quaternion();\n\n public transformMove(_moveEvent: MoveEvent): void {\n // Nothing to do.\n }\n\n public transformOrientation(orientationEvent: OrientationEvent): void {\n const { x, y, z, w } = orientationEvent.quaternion;\n const quat = new Quaternion(x, y, z, w);\n\n const U = new Vector3(0, 1, 0);\n const F = new Vector3(0, 0, 1);\n const maxU = maxAxis(U.applyQuaternion(quat));\n const maxF = maxAxis(F.applyQuaternion(quat));\n\n const oriQuat = m[`${maxU} ${maxF}`] || m[\"y z\"];\n\n console.log(quat);\n console.log(oriQuat);\n const q2 = quat.premultiply(oriQuat);\n\n // console.log(maxAxis(U.applyQuaternion(quat)), maxAxis(F.applyQuaternion(quat)));\n console.log(q2);\n\n orientationEvent.quaternion = quat;\n\n console.log(orientationEvent.quaternion);\n }\n}\n", "import type { Move } from \"../../alg\";\nimport type { KState } from \"../../kpuzzle/KState\";\nimport { BasicRotationTransformer, StreamTransformer } from \"../transformer\";\n\n/******** BluetoothPuzzle ********/\n\n// TODO: Use actual `CustomEvent`s?\n// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent\nexport interface MoveEvent {\n latestMove: Move;\n timeStamp: number;\n debug?: Record<string, unknown>;\n state?: KState;\n quaternion?: any; // TODO: Unused\n}\n\n// TODO: Only use the `quaternion` field in the `MoveEvent`?\nexport interface OrientationEvent {\n quaternion: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n timeStamp: number;\n debug?: Record<string, unknown>;\n}\n\nexport interface BluetoothConfig<T> {\n connect: (\n server: BluetoothRemoteGATTServer,\n device?: BluetoothDevice,\n ) => Promise<T>;\n // TODO: Can we reuse `filters`?\n prefixes: string[]; // `[\"\"]` for GiiKER\n filters: BluetoothLEScanFilter[];\n optionalServices: BluetoothServiceUUID[];\n}\n\n// TODO: Expose device name (and/or globally unique identifier)?\nexport abstract class BluetoothPuzzle extends EventTarget {\n public transformers: StreamTransformer[] = [];\n protected listeners: Array<(e: MoveEvent) => void> = []; // TODO: type\n protected orientationListeners: Array<(e: OrientationEvent) => void> = []; // TODO: type\n\n public abstract name(): string | undefined;\n public abstract disconnect(): void; // TODO: Can we make this reutrn (async) on success?\n\n // TODO: require subclasses to implement this?\n public async getState(): Promise<KState> {\n throw new Error(\"cannot get state\");\n }\n\n public addMoveListener(listener: (e: MoveEvent) => void): void {\n this.listeners.push(listener);\n }\n\n public addOrientationListener(listener: (e: OrientationEvent) => void): void {\n this.orientationListeners.push(listener);\n }\n\n public experimentalAddBasicRotationTransformer(): void {\n this.transformers.push(new BasicRotationTransformer());\n }\n\n protected dispatchMove(moveEvent: MoveEvent): void {\n for (const transformer of this.transformers) {\n transformer.transformMove(moveEvent);\n }\n for (const l of this.listeners) {\n l(moveEvent);\n }\n }\n\n protected dispatchOrientation(orientationEvent: OrientationEvent): void {\n for (const transformer of this.transformers) {\n transformer.transformOrientation(orientationEvent);\n }\n const { x, y, z, w } = orientationEvent.quaternion;\n // TODO: can we avoid mutating the source event?\n orientationEvent.quaternion = {\n x,\n y,\n z,\n w,\n };\n for (const l of this.orientationListeners) {\n // TODO: Convert quaternion.\n l(orientationEvent);\n }\n }\n}\n", "import { keyToMove } from \"../alg\";\nimport type { KPuzzle } from \"../kpuzzle\";\nimport type { KState } from \"../kpuzzle/KState\";\nimport { puzzles } from \"../puzzles\";\nimport { BluetoothPuzzle } from \"./smart-puzzle/bluetooth-puzzle\";\n\nexport class KeyboardPuzzle extends BluetoothPuzzle {\n private puzzle: Promise<KPuzzle> = puzzles[\"3x3x3\"].kpuzzle();\n private state: Promise<KState> = (async () =>\n (await this.puzzle).startState())();\n\n listener: (e: KeyboardEvent) => Promise<void>;\n\n // TODO: Decide on the right arguments.\n constructor(private target: Element) {\n super();\n // TODO: Filter out repeated keydown?\n this.listener = this.onKeyDown.bind(this);\n target.addEventListener(\"keydown\", this.listener);\n }\n\n public name(): string | undefined {\n return \"Keyboard Input\";\n }\n\n disconnect() {\n this.target.removeEventListener(\"keydown\", this.listener);\n }\n\n public async getState(): Promise<KState> {\n return this.state;\n }\n\n private async onKeyDown(e: KeyboardEvent): Promise<void> {\n if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {\n return;\n }\n\n const move = keyToMove(e);\n if (move) {\n const newState = (await this.state).applyMove(move);\n this.state = Promise.resolve(newState);\n this.dispatchMove({\n latestMove: move,\n timeStamp: e.timeStamp,\n state: newState,\n });\n e.preventDefault();\n }\n }\n}\n\n// TODO: Type\nexport async function debugKeyboardConnect(\n target: any = window,\n): Promise<KeyboardPuzzle> {\n return new KeyboardPuzzle(target);\n}\n", "import { debugLog } from \"../debug\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\n\n/******** requestOptions ********/\n\nfunction requestOptions<T>(\n configs: BluetoothConfig<T>[],\n acceptAllDevices: boolean = false,\n): RequestDeviceOptions {\n const options = acceptAllDevices\n ? {\n acceptAllDevices: true,\n optionalServices: [] as BluetoothServiceUUID[],\n }\n : {\n filters: [] as BluetoothLEScanFilter[],\n optionalServices: [] as BluetoothServiceUUID[],\n };\n for (const config of configs) {\n if (!acceptAllDevices) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n options.filters = options.filters!.concat(config.filters);\n }\n options.optionalServices = options.optionalServices.concat(\n config.optionalServices,\n );\n }\n debugLog({ requestOptions: options });\n return options;\n}\n\n/******** connect() ********/\n\nexport interface BluetoothConnectOptions {\n acceptAllDevices?: boolean;\n}\n\n// We globally track the number of connection failures,\n// in order to offer the user recourse (accept all devices) if they're having issues.\n// This allows us to future-proof situations where a device might not show up in\n// the chooser, but works if we connect.\nlet consecutiveFailures = 0;\nconst MAX_FAILURES_BEFORE_ACCEPT_ALL_FALLBACK = 2;\n\n// TODO: Debug options to allow connecting to any device?\nexport async function bluetoothConnect<T>(\n configs: BluetoothConfig<T>[],\n options: BluetoothConnectOptions = {},\n): Promise<T> {\n debugLog(\"Attempting to pair.\");\n let device;\n try {\n let acceptAllDevices = options.acceptAllDevices;\n if (\n !acceptAllDevices &&\n consecutiveFailures >= MAX_FAILURES_BEFORE_ACCEPT_ALL_FALLBACK\n ) {\n console.info(\n `The last ${MAX_FAILURES_BEFORE_ACCEPT_ALL_FALLBACK} Bluetooth puzzle connection attempts failed. This time, the Bluetooth prompt will show all possible devices.`,\n );\n acceptAllDevices = true;\n }\n device = await navigator.bluetooth.requestDevice(\n requestOptions<T>(configs, acceptAllDevices),\n );\n consecutiveFailures = 0;\n } catch (e) {\n consecutiveFailures++;\n throw new Error(e);\n }\n debugLog(\"Device:\", device);\n\n if (typeof device.gatt === \"undefined\") {\n return Promise.reject(\"Device did not have a GATT server.\");\n }\n\n const server = await device.gatt.connect();\n debugLog(\"Server:\", server);\n\n const name = server.device?.name || \"\";\n\n // TODO by reading supported matched filters or provided services.\n\n for (const config of configs) {\n for (const prefix of config.prefixes) {\n if (name?.startsWith(prefix)) {\n return config.connect(server, device);\n }\n }\n }\n\n throw Error(\"Unknown Bluetooth devive.\");\n}\n", "/* tslint:disable no-bitwise */\n\nimport { Quaternion } from \"three\";\nimport { Move } from \"../../alg\";\nimport type { KPuzzle, KStateData } from \"../../kpuzzle\";\nimport { KState } from \"../../kpuzzle\";\nimport { puzzles } from \"../../puzzles\";\nimport {\n importKey,\n unsafeDecryptBlock,\n} from \"../../vendor/unsafe-raw-aes/unsafe-raw-aes\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\n\n// This needs to be short enough to capture 6 moves (OBQTM).\nconst DEFAULT_INTERVAL_MS = 150;\n// Number of latest moves provided by the Gan 356i.\nconst MAX_LATEST_MOVES = 6;\n\nconst ganMoveToBlockMove: { [i: number]: Move } = {\n 0x00: new Move(\"U\"),\n 0x02: new Move(\"U\", -1),\n 0x03: new Move(\"R\"),\n 0x05: new Move(\"R\", -1),\n 0x06: new Move(\"F\"),\n 0x08: new Move(\"F\", -1),\n 0x09: new Move(\"D\"),\n 0x0b: new Move(\"D\", -1),\n 0x0c: new Move(\"L\"),\n 0x0e: new Move(\"L\", -1),\n 0x0f: new Move(\"B\"),\n 0x11: new Move(\"B\", -1),\n};\n\nlet homeQuatInverse: Quaternion | null = null;\n\nfunction probablyDecodedCorrectly(data: Uint8Array): boolean {\n return (\n data[13] < 0x12 &&\n data[14] < 0x12 &&\n data[15] < 0x12 &&\n data[16] < 0x12 &&\n data[17] < 0x12 &&\n data[18] < 0x12\n );\n}\n\nconst key10 = new Uint8Array([\n 198, 202, 21, 223, 79, 110, 19, 182, 119, 13, 230, 89, 58, 175, 186, 162,\n]);\nconst key11 = new Uint8Array([\n 67, 226, 91, 214, 125, 220, 120, 216, 7, 96, 163, 218, 130, 60, 1, 241,\n]);\n\n// Clean-room reverse-engineered\nasync function decryptState(\n data: Uint8Array,\n aesKey: CryptoKey | null,\n): Promise<Uint8Array> {\n if (aesKey === null) {\n return data;\n }\n\n const copy = new Uint8Array(data);\n copy.set(new Uint8Array(await unsafeDecryptBlock(aesKey, copy.slice(3))), 3);\n copy.set(\n new Uint8Array(await unsafeDecryptBlock(aesKey, copy.slice(0, 16))),\n 0,\n );\n\n if (probablyDecodedCorrectly(copy)) {\n return copy;\n }\n\n throw new Error(\"Invalid Gan cube state\");\n}\n\nclass PhysicalState {\n public static async read(\n characteristic: BluetoothRemoteGATTCharacteristic,\n aesKey: CryptoKey | null,\n ): Promise<PhysicalState> {\n const value = await decryptState(\n new Uint8Array((await characteristic.readValue()).buffer),\n aesKey,\n );\n const timeStamp = Date.now();\n // console.log(value);\n return new PhysicalState(new DataView(value.buffer), timeStamp);\n }\n\n private arr: Uint8Array;\n private arrLen = 19;\n private constructor(private dataView: DataView, public timeStamp: number) {\n this.arr = new Uint8Array(dataView.buffer);\n if (this.arr.length !== this.arrLen) {\n throw new Error(\"Unexpected array length\");\n }\n }\n\n public rotQuat(): Quaternion {\n let x = this.dataView.getInt16(0, true) / 16384;\n let y = this.dataView.getInt16(2, true) / 16384;\n let z = this.dataView.getInt16(4, true) / 16384;\n [x, y, z] = [-y, z, -x];\n const wSquared = 1 - (x * x + y * y + z * z);\n const w = wSquared > 0 ? Math.sqrt(wSquared) : 0;\n const quat = new Quaternion(x, y, z, w);\n\n if (!homeQuatInverse) {\n homeQuatInverse = quat.clone().inverse();\n }\n\n return quat.clone().multiply(homeQuatInverse.clone());\n }\n\n // Loops from 255 to 0.\n public moveCounter(): number {\n return this.arr[12];\n }\n\n public numMovesSince(previousMoveCounter: number): number {\n return (this.moveCounter() - previousMoveCounter) & 0xff;\n }\n\n // Due to the design of the Gan356i protocol, it's common to query for the\n // latest physical state and find 0 moves have been performed since the last\n // query. Therefore, it's useful to allow 0 as an argument.\n public latestMoves(n: number): Move[] {\n if (n < 0 || n > MAX_LATEST_MOVES) {\n throw new Error(`Must ask for 0 to 6 latest moves. (Asked for ${n})`);\n }\n return Array.from(this.arr.slice(19 - n, 19)).map(\n (i) => ganMoveToBlockMove[i],\n );\n }\n\n public debugInfo(): { arr: Uint8Array } {\n return {\n arr: this.arr,\n };\n }\n}\n\n// TODO: Short IDs\nconst UUIDs = {\n ganCubeService: \"0000fff0-0000-1000-8000-00805f9b34fb\",\n physicalStateCharacteristic: \"0000fff5-0000-1000-8000-00805f9b34fb\",\n actualAngleAndBatteryCharacteristic: \"0000fff7-0000-1000-8000-00805f9b34fb\",\n faceletStatus1Characteristic: \"0000fff2-0000-1000-8000-00805f9b34fb\",\n faceletStatus2Characteristic: \"0000fff3-0000-1000-8000-00805f9b34fb\",\n infoService: \"0000180a-0000-1000-8000-00805f9b34fb\",\n systemIDCharacteristic: \"00002a23-0000-1000-8000-00805f9b34fb\",\n versionCharacteristic: \"00002a28-0000-1000-8000-00805f9b34fb\",\n};\n\nconst commands: { [cmd: string]: BufferSource } = {\n reset: new Uint8Array([\n 0x00, 0x00, 0x24, 0x00, 0x49, 0x92, 0x24, 0x49, 0x6d, 0x92, 0xdb, 0xb6,\n 0x49, 0x92, 0xb6, 0x24, 0x6d, 0xdb,\n ]),\n};\n\nfunction buf2hex(buffer: ArrayBuffer): string {\n // buffer is an ArrayBuffer\n return (\n Array.prototype.map.call(new Uint8Array(buffer), (x: number) =>\n (\"00\" + x.toString(16)).slice(-2),\n ) as string[]\n ).join(\" \");\n}\n\nconst reidEdgeOrder = \"UF UR UB UL DF DR DB DL FR FL BR BL\".split(\" \");\nconst reidCornerOrder = \"UFR URB UBL ULF DRF DFL DLB DBR\".split(\" \");\n\ninterface PieceInfo {\n piece: number;\n orientation: number;\n}\n\nfunction rotateLeft(s: string, i: number): string {\n return s.slice(i) + s.slice(0, i);\n}\n\nconst pieceMap: { [s: string]: PieceInfo } = {};\n// TODO: Condense the for loops.\nreidEdgeOrder.forEach((edge, idx) => {\n for (let i = 0; i < 2; i++) {\n pieceMap[rotateLeft(edge, i)] = { piece: idx, orientation: i };\n }\n});\nreidCornerOrder.forEach((corner, idx) => {\n for (let i = 0; i < 3; i++) {\n pieceMap[rotateLeft(corner, i)] = { piece: idx, orientation: i };\n }\n});\n\nconst gan356iCornerMappings = [\n [0, 21, 15],\n [5, 13, 47],\n [7, 45, 39],\n [2, 37, 23],\n [29, 10, 16],\n [31, 18, 32],\n [26, 34, 40],\n [24, 42, 8],\n];\n\nconst gan356iEdgeMappings = [\n [1, 22],\n [3, 14],\n [6, 46],\n [4, 38],\n [30, 17],\n [27, 9],\n [25, 41],\n [28, 33],\n [19, 12],\n [20, 35],\n [44, 11],\n [43, 36],\n];\nconst faceOrder = \"URFDLB\";\n\nasync function getKey(\n server: BluetoothRemoteGATTServer,\n): Promise<CryptoKey | null> {\n const infoService = await server.getPrimaryService(UUIDs.infoService);\n\n const versionCharacteristic = await infoService.getCharacteristic(\n UUIDs.versionCharacteristic,\n );\n const versionBuffer = new Uint8Array(\n (await versionCharacteristic.readValue()).buffer,\n );\n\n const versionValue =\n (((versionBuffer[0] << 8) + versionBuffer[1]) << 8) + versionBuffer[2];\n if (versionValue < 0x01_00_08) {\n return null;\n }\n\n const keyXor = versionValue < 0x01_01_00 ? key10 : key11;\n\n const systemIDCharacteristic = await infoService.getCharacteristic(\n UUIDs.systemIDCharacteristic,\n );\n const systemID = new Uint8Array(\n (await systemIDCharacteristic.readValue()).buffer,\n ).reverse();\n\n const key = new Uint8Array(keyXor);\n for (let i = 0; i < systemID.length; i++) {\n key[i] = (key[i] + systemID[i]) % 256;\n }\n\n return importKey(key);\n}\n\nexport class GanCube extends BluetoothPuzzle {\n // We have to perform async operations before we call the constructor.\n public static async connect(\n server: BluetoothRemoteGATTServer,\n ): Promise<GanCube> {\n const ganCubeService = await server.getPrimaryService(UUIDs.ganCubeService);\n debugLog(\"Service:\", ganCubeService);\n\n const physicalStateCharacteristic = await ganCubeService.getCharacteristic(\n UUIDs.physicalStateCharacteristic,\n );\n debugLog(\"Characteristic:\", physicalStateCharacteristic);\n\n const aesKey = await getKey(server);\n\n const initialMoveCounter = (\n await PhysicalState.read(physicalStateCharacteristic, aesKey)\n ).moveCounter();\n debugLog(\"Initial Move Counter:\", initialMoveCounter);\n const cube = new GanCube(\n await puzzles[\"3x3x3\"].kpuzzle(),\n ganCubeService,\n server,\n physicalStateCharacteristic,\n initialMoveCounter,\n aesKey,\n );\n return cube;\n }\n\n public INTERVAL_MS: number = DEFAULT_INTERVAL_MS;\n private intervalHandle: number | null = null;\n private state: KState;\n private cachedFaceletStatus1Characteristic: Promise<BluetoothRemoteGATTCharacteristic>;\n\n private cachedFaceletStatus2Characteristic: Promise<BluetoothRemoteGATTCharacteristic>;\n\n private cachedActualAngleAndBatteryCharacteristic: Promise<BluetoothRemoteGATTCharacteristic>;\n\n private constructor(\n private kpuzzle: KPuzzle,\n private service: BluetoothRemoteGATTService,\n private server: BluetoothRemoteGATTServer,\n private physicalStateCharacteristic: BluetoothRemoteGATTCharacteristic,\n private lastMoveCounter: number,\n private aesKey: CryptoKey | null,\n ) {\n super();\n this.state = kpuzzle.startState();\n this.startTrackingMoves();\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n public startTrackingMoves(): void {\n // `window.setInterval` instead of `setInterval`:\n // https://github.com/Microsoft/TypeScript/issues/842#issuecomment-252445883\n this.intervalHandle = window.setInterval(\n this.intervalHandler.bind(this),\n this.INTERVAL_MS,\n );\n }\n\n public stopTrackingMoves(): void {\n if (!this.intervalHandle) {\n throw new Error(\"Not tracking moves!\");\n }\n clearInterval(this.intervalHandle);\n this.intervalHandle = null;\n }\n\n // TODO: Can we ever receive async responses out of order?\n public async intervalHandler(): Promise<void> {\n const physicalState = await PhysicalState.read(\n this.physicalStateCharacteristic,\n this.aesKey,\n );\n let numInterveningMoves = physicalState.numMovesSince(this.lastMoveCounter);\n // console.log(numInterveningMoves);\n if (numInterveningMoves > MAX_LATEST_MOVES) {\n debugLog(\n `Too many moves! Dropping ${\n numInterveningMoves - MAX_LATEST_MOVES\n } moves`,\n );\n numInterveningMoves = MAX_LATEST_MOVES;\n }\n for (const move of physicalState.latestMoves(numInterveningMoves)) {\n // console.log(move);\n this.state = this.state.applyMove(move);\n this.dispatchMove({\n latestMove: move,\n timeStamp: physicalState.timeStamp,\n debug: physicalState.debugInfo(),\n state: this.state,\n // quaternion: physicalState.rotQuat(),\n });\n }\n this.dispatchOrientation({\n timeStamp: physicalState.timeStamp,\n quaternion: physicalState.rotQuat(),\n });\n this.lastMoveCounter = physicalState.moveCounter();\n }\n\n public async getBattery(): Promise<number> {\n return new Uint8Array(\n await this.readActualAngleAndBatteryCharacteristic(),\n )[7];\n }\n\n public async getState(): Promise<KState> {\n const arr: Uint8Array = await decryptState(\n new Uint8Array(await this.readFaceletStatus1Characteristic()),\n this.aesKey,\n );\n const stickers: number[] = [];\n for (let i = 0; i < 18; i += 3) {\n let v = (((arr[i ^ 1] << 8) + arr[(i + 1) ^ 1]) << 8) + arr[(i + 2) ^ 1];\n for (let j = 0; j < 8; j++) {\n stickers.push(v & 7);\n v >>= 3;\n }\n }\n\n const stateData: KStateData = {\n CORNERS: {\n pieces: [],\n orientation: [],\n },\n EDGES: {\n pieces: [],\n orientation: [],\n },\n CENTERS: {\n pieces: [0, 1, 2, 3, 4, 5],\n orientation: [0, 0, 0, 0, 0, 0],\n },\n };\n\n for (const cornerMapping of gan356iCornerMappings) {\n const pieceInfo: PieceInfo =\n pieceMap[cornerMapping.map((i) => faceOrder[stickers[i]]).join(\"\")];\n stateData.CORNERS.pieces.push(pieceInfo.piece);\n stateData.CORNERS.orientation.push(pieceInfo.orientation);\n }\n\n for (const edgeMapping of gan356iEdgeMappings) {\n const pieceInfo: PieceInfo =\n pieceMap[edgeMapping.map((i) => faceOrder[stickers[i]]).join(\"\")];\n stateData.EDGES.pieces.push(pieceInfo.piece);\n stateData.EDGES.orientation.push(pieceInfo.orientation);\n }\n\n return new KState(this.kpuzzle, stateData);\n }\n\n public async faceletStatus1Characteristic(): Promise<BluetoothRemoteGATTCharacteristic> {\n this.cachedFaceletStatus1Characteristic =\n this.cachedFaceletStatus1Characteristic ||\n this.service.getCharacteristic(UUIDs.faceletStatus1Characteristic);\n return this.cachedFaceletStatus1Characteristic;\n }\n\n public async faceletStatus2Characteristic(): Promise<BluetoothRemoteGATTCharacteristic> {\n this.cachedFaceletStatus2Characteristic =\n this.cachedFaceletStatus2Characteristic ||\n this.service.getCharacteristic(UUIDs.faceletStatus2Characteristic);\n return this.cachedFaceletStatus2Characteristic;\n }\n\n public async actualAngleAndBatteryCharacteristic(): Promise<BluetoothRemoteGATTCharacteristic> {\n this.cachedActualAngleAndBatteryCharacteristic =\n this.cachedActualAngleAndBatteryCharacteristic ||\n this.service.getCharacteristic(UUIDs.actualAngleAndBatteryCharacteristic);\n return this.cachedActualAngleAndBatteryCharacteristic;\n }\n\n public async reset(): Promise<void> {\n const faceletStatus1Characteristic =\n await this.faceletStatus1Characteristic();\n await faceletStatus1Characteristic.writeValue(commands.reset);\n }\n\n public async readFaceletStatus1Characteristic(): Promise<ArrayBuffer> {\n const faceletStatus1Characteristic =\n await this.faceletStatus1Characteristic();\n return (await faceletStatus1Characteristic.readValue()).buffer;\n }\n\n public async readFaceletStatus2Characteristic(): Promise<string> {\n const faceletStatus2Characteristic =\n await this.faceletStatus2Characteristic();\n return buf2hex((await faceletStatus2Characteristic.readValue()).buffer);\n }\n\n public async readActualAngleAndBatteryCharacteristic(): Promise<ArrayBuffer> {\n const actualAngleAndBatteryCharacteristic =\n await this.actualAngleAndBatteryCharacteristic();\n return (await actualAngleAndBatteryCharacteristic.readValue()).buffer;\n }\n\n // TODO\n // private onphysicalStateCharacteristicChanged(event: any): void {\n // var val = event.target.value;\n // debugLog(val);\n // }\n}\n\n// // TODO: Move this into a factory?\nexport const ganConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: GanCube.connect.bind(GanCube),\n prefixes: [\"GAN\"],\n filters: [{ namePrefix: \"GAN\" }],\n optionalServices: [UUIDs.ganCubeService, UUIDs.infoService],\n};\n", "const blockSize = 16;\nconst zeros = new Uint8Array(blockSize);\nconst paddingBlockPlaintext = new Uint8Array(\n new Array(blockSize).fill(blockSize),\n);\nconst AES_CBC = \"AES-CBC\";\n\nexport async function importKey(keyBytes: ArrayBuffer): Promise<CryptoKey> {\n return await crypto.subtle.importKey(\"raw\", keyBytes, AES_CBC, true, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\nasync function unsafeEncryptBlockWithIV(\n key: CryptoKey,\n plaintextBlock: ArrayBuffer,\n iv: ArrayBuffer,\n): Promise<ArrayBuffer> {\n const cryptoResult: ArrayBuffer = await window.crypto.subtle.encrypt(\n {\n name: AES_CBC,\n iv,\n },\n key,\n plaintextBlock,\n );\n return cryptoResult.slice(0, blockSize);\n}\n\nexport async function unsafeEncryptBlock(\n key: CryptoKey,\n plaintextBlock: ArrayBuffer,\n): Promise<ArrayBuffer> {\n return (await unsafeEncryptBlockWithIV(key, plaintextBlock, zeros)).slice(\n 0,\n blockSize,\n );\n}\n\nexport async function unsafeDecryptBlock(\n key: CryptoKey,\n ciphertextBlock: ArrayBuffer,\n): Promise<ArrayBuffer> {\n const paddingBlock = await unsafeEncryptBlockWithIV(\n key,\n paddingBlockPlaintext,\n ciphertextBlock,\n );\n\n const cbcCiphertext = new Uint8Array(2 * blockSize);\n cbcCiphertext.set(new Uint8Array(ciphertextBlock), 0);\n cbcCiphertext.set(new Uint8Array(paddingBlock), blockSize);\n\n const cryptoResult: ArrayBuffer = await window.crypto.subtle.decrypt(\n {\n name: AES_CBC,\n iv: zeros,\n },\n key,\n cbcCiphertext,\n );\n return cryptoResult.slice(0, blockSize);\n}\n", "/* tslint:disable no-bitwise */\n\nimport { Move } from \"../../alg\";\nimport { experimental3x3x3KPuzzle, KState, KStateData } from \"../../kpuzzle\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\n\nconst MESSAGE_LENGTH = 20;\n\nconst UUIDs = {\n cubeService: \"0000aadb-0000-1000-8000-00805f9b34fb\",\n cubeCharacteristic: \"0000aadc-0000-1000-8000-00805f9b34fb\",\n};\n\n// TODO: Expose for testing.\nfunction giikerMoveToAlgMove(face: number, amount: number): Move {\n switch (amount) {\n case 3:\n amount = -1;\n break;\n case 9:\n debugLog(\"Encountered 9\", face, amount);\n amount = -2;\n break;\n }\n\n const family = [\"?\", \"B\", \"D\", \"L\", \"U\", \"R\", \"F\"][face];\n return new Move(family, amount);\n}\n\nexport { giikerMoveToAlgMove as giikerMoveToAlgMoveForTesting };\n\nfunction giikerStateStr(giikerState: number[]): string {\n let str = \"\";\n str += giikerState.slice(0, 8).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(8, 16).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(16, 28).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(28, 32).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(32, 40).join(\".\");\n return str;\n}\n\n// TODO\n// const Reid333Orbits = {\n// \"EDGES\": {\"numPieces\": 12, \"orientations\": 2},\n// \"CORNERS\": {\"numPieces\": 8, \"orientations\": 3},\n// \"CENTERS\": {\"numPieces\": 6, \"orientations\": 4}\n// };\n\nconst Reid333SolvedCenters = {\n pieces: [0, 1, 2, 3, 4, 5],\n orientation: [0, 0, 0, 0, 0, 0],\n};\n\nconst epGiiKERtoReid333: number[] = [4, 8, 0, 9, 5, 1, 3, 7, 6, 10, 2, 11];\nconst epReid333toGiiKER: number[] = [2, 5, 10, 6, 0, 4, 8, 7, 1, 3, 9, 11];\n\nconst preEO: number[] = [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0];\nconst postEO: number[] = [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0];\n\nconst cpGiiKERtoReid333: number[] = [4, 0, 3, 5, 7, 1, 2, 6];\nconst cpReid333toGiiKER: number[] = [1, 5, 6, 2, 0, 3, 7, 4];\n\nconst preCO: number[] = [1, 2, 1, 2, 2, 1, 2, 1];\nconst postCO: number[] = [2, 1, 2, 1, 1, 2, 1, 2];\n\nconst coFlip: number[] = [-1, 1, -1, 1, 1, -1, 1, -1];\n\nfunction getNibble(val: Uint8Array, i: number): number {\n if (i % 2 === 1) {\n return val[(i / 2) | 0] % 16;\n }\n return 0 | (val[(i / 2) | 0] / 16);\n}\n\nfunction probablyEncrypted(data: Uint8Array): boolean {\n return data[18] === 0xa7;\n}\n\nconst lookup = [\n 176, 81, 104, 224, 86, 137, 237, 119, 38, 26, 193, 161, 210, 126, 150, 81, 93,\n 13, 236, 249, 89, 235, 88, 24, 113, 81, 214, 131, 130, 199, 2, 169, 39, 165,\n 171, 41,\n];\n\nfunction decryptState(data: Uint8Array): Uint8Array {\n const offset1 = getNibble(data, 38);\n const offset2 = getNibble(data, 39);\n const output = new Uint8Array(MESSAGE_LENGTH);\n for (let i = 0; i < MESSAGE_LENGTH; i++) {\n output[i] = data[i] + lookup[offset1 + i] + lookup[offset2 + i];\n }\n return output;\n}\n\n// TODO: Support caching which decoding strategy worked last time.\nasync function decodeState(data: Uint8Array): Promise<Uint8Array> {\n if (!probablyEncrypted(data)) {\n return data;\n }\n return decryptState(data);\n // TODO: Check that the decrypted state is a valid staet.\n}\n\nexport class GiiKERCube extends BluetoothPuzzle {\n public static async connect(\n server: BluetoothRemoteGATTServer,\n ): Promise<GiiKERCube> {\n const cubeService = await server.getPrimaryService(UUIDs.cubeService);\n debugLog(\"Service:\", cubeService);\n\n const cubeCharacteristic = await cubeService.getCharacteristic(\n UUIDs.cubeCharacteristic,\n );\n debugLog(\"Characteristic:\", cubeCharacteristic);\n\n // TODO: Can we safely save the async promise instead of waiting for the response?\n\n const originalValue = await decodeState(\n new Uint8Array((await cubeCharacteristic.readValue()).buffer),\n );\n debugLog(\"Original value:\", originalValue);\n const cube = new GiiKERCube(server, cubeCharacteristic, originalValue);\n\n await cubeCharacteristic.startNotifications();\n cubeCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n cube.onCubeCharacteristicChanged.bind(cube),\n );\n\n return cube;\n }\n\n private constructor(\n private server: BluetoothRemoteGATTServer,\n private cubeCharacteristic: BluetoothRemoteGATTCharacteristic,\n private originalValue?: Uint8Array | null,\n ) {\n super();\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n public async getState(): Promise<KState> {\n return this.toReid333(\n new Uint8Array((await this.cubeCharacteristic.readValue()).buffer),\n );\n }\n\n private getBit(val: Uint8Array, i: number): number {\n const n = (i / 8) | 0;\n const shift = 7 - (i % 8);\n return (val[n] >> shift) & 1;\n }\n\n private toReid333(val: Uint8Array): KState {\n const state: KStateData = {\n EDGES: {\n pieces: new Array(12),\n orientation: new Array(12),\n },\n CORNERS: {\n pieces: new Array(8),\n orientation: new Array(8),\n },\n CENTERS: Reid333SolvedCenters,\n };\n\n for (let i = 0; i < 12; i++) {\n const gi = epReid333toGiiKER[i];\n state.EDGES.pieces[i] = epGiiKERtoReid333[getNibble(val, gi + 16) - 1];\n state.EDGES.orientation[i] =\n this.getBit(val, gi + 112) ^ preEO[state.EDGES.pieces[i]] ^ postEO[i];\n }\n for (let i = 0; i < 8; i++) {\n const gi = cpReid333toGiiKER[i];\n state.CORNERS.pieces[i] = cpGiiKERtoReid333[getNibble(val, gi) - 1];\n state.CORNERS.orientation[i] =\n (getNibble(val, gi + 8) * coFlip[gi] +\n preCO[state.CORNERS.pieces[i]] +\n postCO[i]) %\n 3;\n }\n return new KState(experimental3x3x3KPuzzle, state);\n }\n\n private async onCubeCharacteristicChanged(event: any): Promise<void> {\n const val = await decodeState(new Uint8Array(event.target.value.buffer));\n debugLog(val);\n debugLog(val);\n\n if (this.isRepeatedInitialValue(val)) {\n debugLog(\"Skipping repeated initial value.\");\n return;\n }\n\n const giikerState = [];\n for (let i = 0; i < MESSAGE_LENGTH; i++) {\n giikerState.push(Math.floor(val[i] / 16));\n giikerState.push(val[i] % 16);\n }\n debugLog(giikerState);\n const str = giikerStateStr(giikerState);\n debugLog(str);\n\n this.dispatchMove({\n latestMove: giikerMoveToAlgMove(giikerState[32], giikerState[33]),\n timeStamp: event.timeStamp,\n debug: {\n stateStr: str,\n },\n state: this.toReid333(val),\n });\n }\n\n private isRepeatedInitialValue(val: Uint8Array): boolean {\n if (typeof this.originalValue === \"undefined\") {\n // TODO: Test this branch.\n throw new Error(\"GiiKERCube has uninitialized original value.\");\n }\n\n if (this.originalValue === null) {\n return false;\n }\n\n const originalValue = this.originalValue;\n // Reset the value here, so we can return early below.\n this.originalValue = null;\n\n debugLog(\"Comparing against original value.\");\n for (let i = 0; i < MESSAGE_LENGTH - 2; i++) {\n if (originalValue[i] !== val[i]) {\n debugLog(\"Different at index \", i);\n return false;\n }\n }\n return true;\n }\n}\n\n// TODO: Move this into a factory?\nexport const giiKERConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: GiiKERCube.connect.bind(GiiKERCube),\n prefixes: [\"Gi\", \"\"], // Hack\n filters: [\n // Known prefixes: GiC, GiS (3x3x3), Gi2 (2x2x2)\n // Suspected prefixes GiY, Gi3\n { namePrefix: \"Gi\" },\n { services: [\"0000aadb-0000-1000-8000-00805f9b34fb\"] },\n { services: [\"0000aaaa-0000-1000-8000-00805f9b34fb\"] },\n { services: [\"0000fe95-0000-1000-8000-00805f9b34fb\"] },\n ],\n optionalServices: [\n // \"00001530-1212-efde-1523-785feabcd123\",\n // \"0000aaaa-0000-1000-8000-00805f9b34fb\",\n UUIDs.cubeService,\n // \"0000180f-0000-1000-8000-00805f9b34fb\",\n // \"0000180a-0000-1000-8000-00805f9b34fb\"\n ],\n};\n", "import { Quaternion } from \"three\";\nimport { Alg, experimentalAppendMove, Move } from \"../../alg\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\n\nconst UUIDs = {\n goCubeService: \"6e400001-b5a3-f393-e0a9-e50e24dcca9e\",\n goCubeStateCharacteristic: \"6e400003-b5a3-f393-e0a9-e50e24dcca9e\",\n};\n\n// https://stackoverflow.com/a/40031979\nfunction buf2hex(buffer: ArrayBuffer): string {\n // buffer is an ArrayBuffer\n return (\n Array.prototype.map.call(new Uint8Array(buffer), (x: number) =>\n (\"00\" + x.toString(16)).slice(-2),\n ) as string[]\n ).join(\" \");\n}\n\nfunction bufferToString(buffer: ArrayBuffer): string {\n const byteView = new Uint8Array(buffer);\n let str = \"\";\n for (const charCode of byteView) {\n str += String.fromCharCode(charCode);\n }\n return str;\n}\n\nconst moveMap: Move[] = [\n new Move(\"B\", 1),\n new Move(\"B\", -1),\n new Move(\"F\", 1),\n new Move(\"F\", -1),\n new Move(\"U\", 1),\n new Move(\"U\", -1),\n new Move(\"D\", 1),\n new Move(\"D\", -1),\n new Move(\"R\", 1),\n new Move(\"R\", -1),\n new Move(\"L\", 1),\n new Move(\"L\", -1),\n];\n\nexport class GoCube extends BluetoothPuzzle {\n // We have to perform async operations before we call the constructor.\n public static async connect(\n server: BluetoothRemoteGATTServer,\n ): Promise<GoCube> {\n const service = await server.getPrimaryService(UUIDs.goCubeService);\n debugLog({ service });\n const goCubeStateCharacteristic = await service.getCharacteristic(\n UUIDs.goCubeStateCharacteristic,\n );\n debugLog({ goCubeStateCharacteristic });\n\n const cube = new GoCube(server, goCubeStateCharacteristic);\n\n await goCubeStateCharacteristic.startNotifications();\n goCubeStateCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n cube.onCubeCharacteristicChanged.bind(cube),\n );\n\n return cube;\n }\n\n // public async getState(): Promise<PuzzleState> {\n // return new Promise((resolve, reject) => {\n // this.resolve = (value: any) => {\n // resolve(buf2hex(value.buffer) as any);\n // };\n // this.goCubeStateCharacteristic.startNotifications();\n // });\n // }\n\n private recorded: any[][] = [];\n\n private homeQuatInverse: Quaternion | null = null;\n private lastRawQuat: Quaternion = new Quaternion(0, 0, 0, 1);\n private currentQuat: Quaternion = new Quaternion(0, 0, 0, 1);\n private lastTarget: Quaternion = new Quaternion(0, 0, 0, 1);\n private alg: Alg = new Alg();\n\n private constructor(\n private server: BluetoothRemoteGATTServer,\n public goCubeStateCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n public reset(): void {\n this.resetAlg();\n this.resetOrientation();\n }\n\n public resetAlg(alg?: Alg): void {\n this.alg = alg || new Alg();\n }\n\n public resetOrientation(): void {\n this.homeQuatInverse = this.lastRawQuat.clone().inverse();\n this.currentQuat = new Quaternion(0, 0, 0, 1);\n this.lastTarget = new Quaternion(0, 0, 0, 1);\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n private onCubeCharacteristicChanged(event: any): void {\n const buffer: DataView = event.target.value;\n this.recorded.push([event.timeStamp, buf2hex(buffer.buffer)]);\n // TODO: read bytes from buffer instead of guessing meaning based on length.\n if (buffer.byteLength < 16) {\n for (let i = 3; i < buffer.byteLength - 4; i += 2) {\n const move = moveMap[buffer.getUint8(i)];\n this.alg = experimentalAppendMove(this.alg, move);\n this.dispatchMove({\n latestMove: moveMap[buffer.getUint8(i)],\n timeStamp: event.timeStamp,\n debug: {\n stateStr: buf2hex(buffer.buffer),\n },\n });\n }\n } else {\n const coords = bufferToString(\n buffer.buffer.slice(3, buffer.byteLength - 3),\n )\n .split(\"#\")\n .map((s) => parseInt(s, 10) / 16384);\n const quat = new Quaternion(coords[0], coords[1], coords[2], coords[3]);\n\n this.lastRawQuat = quat.clone();\n\n if (!this.homeQuatInverse) {\n this.homeQuatInverse = quat.clone().inverse();\n }\n\n const targetQuat = quat.clone().multiply(this.homeQuatInverse.clone());\n targetQuat.y = -targetQuat.y; // GoCube axis fix.\n\n this.lastTarget.slerp(targetQuat, 0.5);\n this.currentQuat.rotateTowards(this.lastTarget, rotateTowardsRate);\n\n this.dispatchOrientation({\n quaternion: this.currentQuat,\n timeStamp: event.timeStamp,\n });\n }\n }\n}\n\nconst rotateTowardsRate = 0.5;\n\n// TODO: Move this into a factory?\nexport const goCubeConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: GoCube.connect.bind(GoCube),\n prefixes: [\"GoCube\", \"Rubik\"],\n filters: [{ namePrefix: \"GoCube\" }, { namePrefix: \"Rubik\" }],\n optionalServices: [UUIDs.goCubeService],\n};\n", "export function flipBitOrder(v: number, numBits: number): number {\n let result = 0;\n for (let i = 0; i < numBits; i++) {\n const shiftLeft = numBits - 1 - 2 * i;\n const unShiftedBit = v & (0b1 << i);\n // console.log(\n // unShiftedBit,\n // shiftLeft,\n // shiftLeft < 0 ? unShiftedBit >> -shiftLeft : unShiftedBit << shiftLeft,\n // );\n result +=\n shiftLeft < 0 ? unShiftedBit >> -shiftLeft : unShiftedBit << shiftLeft;\n }\n return result;\n}\n", "/* tslint:disable no-bitwise */\n\nimport { Move } from \"../../alg\";\nimport type { KPuzzle } from \"../../kpuzzle\";\nimport type { KState } from \"../../kpuzzle/KState\";\nimport {\n experimentalBinaryComponentsToReid3x3x3,\n experimentalTwizzleBinaryToBinaryComponents,\n} from \"../../protocol\";\nimport { puzzles } from \"../../puzzles\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\nimport { flipBitOrder } from \"./endianness\";\n\n// TODO: Short IDs\nconst UUIDs = {\n heykubeService: \"b46a791a-8273-4fc1-9e67-94d3dc2aac1c\",\n stateCharacteristic: \"a2f41a4e-0e31-4bbc-9389-4253475481fb\",\n batteryCharacteristic: \"fd51b3ba-99c7-49c6-9f85-5644ff56a378\",\n};\n\nexport class HeykubeCube extends BluetoothPuzzle {\n // We have to perform async operations before we call the constructor.\n public static async connect(\n server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n ): Promise<HeykubeCube> {\n const service = await server.getPrimaryService(UUIDs.heykubeService);\n debugLog(\"Service:\", service);\n\n const stateCharacteristic = await service.getCharacteristic(\n UUIDs.stateCharacteristic,\n );\n debugLog(\"Characteristic:\", stateCharacteristic);\n\n const cube = new HeykubeCube(\n await puzzles[\"3x3x3\"].kpuzzle(),\n service,\n device,\n server,\n stateCharacteristic,\n );\n return cube;\n }\n\n private constructor(\n _kpuzzle: KPuzzle,\n _service: BluetoothRemoteGATTService,\n device: BluetoothDevice,\n private server: BluetoothRemoteGATTServer,\n private stateCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n\n device.addEventListener(\n \"gattserverdisconnected\",\n this.onDisconnect.bind(this),\n );\n\n this.stateCharacteristic.startNotifications();\n this.startTrackingMoves();\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n onDisconnect(): void {\n this.dispatchEvent(new CustomEvent(\"disconnect\"));\n }\n\n public startTrackingMoves(): void {\n this.stateCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n (e: any) => this.onStateCharacteristic(e),\n ); // TODO\n }\n\n // public stopTrackingMoves(): void {}\n\n // public async getBattery(): Promise<number> {\n // return new Uint8Array(\n // await this.readActualAngleAndBatteryCharacteristic(),\n // )[7];\n // }srcElement: BluetoothRemoteGATTCharacteristic\n\n private onStateCharacteristic(event: {\n target: BluetoothRemoteGATTCharacteristic;\n timeStamp: number;\n }): void {\n const state = this.decodeState(event.target.value!);\n // console.log(event, state.latestMove.toString(), state);\n this.dispatchMove({\n latestMove: state.latestMove,\n timeStamp: event.timeStamp,\n state: state.state,\n });\n }\n\n private decodeState(dv: DataView): { state: KState; latestMove: Move } {\n const moves = [\n new Move(\"U\"),\n new Move(\"U'\"),\n new Move(\"B\"),\n new Move(\"B'\"),\n new Move(\"F\"),\n new Move(\"F'\"),\n null,\n null,\n new Move(\"L\"),\n new Move(\"L'\"),\n new Move(\"D\"),\n new Move(\"D'\"),\n new Move(\"R\"),\n new Move(\"R'\"),\n // null,\n // null,\n ];\n\n const b2 = new Uint8Array(dv.byteLength);\n for (let i = 0; i < dv.byteLength; i++) {\n b2[i] = flipBitOrder(dv.getUint8(i), 8);\n }\n const components1 = experimentalTwizzleBinaryToBinaryComponents(\n b2.slice(0, 11),\n );\n // console.log(\"sliced\", dv.byteLength, bufferToSpacedHex(b2.slice(11)));\n const components2 = {\n epLex: flipBitOrder(components1.epLex, 29),\n eoMask: flipBitOrder(components1.eoMask, 12),\n cpLex: flipBitOrder(components1.cpLex, 16),\n coMask: flipBitOrder(components1.coMask, 13),\n poIdxL: 0,\n poIdxU: 0b111,\n moSupport: 0b1, // TODO\n moMask: 0,\n };\n // console.log(components2, binaryComponentsToReid3x3x3(components2));\n\n return {\n state: experimentalBinaryComponentsToReid3x3x3(components2),\n latestMove: moves[b2[20] & 0b00001111]!,\n };\n }\n\n public async getState(): Promise<KState> {\n const b1 = await this.stateCharacteristic.readValue();\n return this.decodeState(b1).state;\n }\n}\n\n// // TODO: Move this into a factory?\nexport const heykubeConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: HeykubeCube.connect.bind(HeykubeCube),\n prefixes: [\"HEYKUBE\"],\n filters: [{ namePrefix: \"HEYKUBE\" }],\n optionalServices: [UUIDs.heykubeService],\n};\n", "import { bluetoothConnect, BluetoothConnectOptions } from \"../connect\";\nimport type { BluetoothPuzzle } from \"./bluetooth-puzzle\";\nimport { ganConfig } from \"./gan\";\nimport { giiKERConfig } from \"./giiker\";\nimport { goCubeConfig } from \"./gocube\";\nimport { heykubeConfig } from \"./Heykube\";\n\nconst smartPuzzleConfigs = [\n ganConfig,\n goCubeConfig,\n heykubeConfig,\n giiKERConfig, // GiiKER must be last, due to Xiaomi naming. TODO: enforce this using tests.\n];\n\nexport async function connectSmartPuzzle(\n options?: BluetoothConnectOptions,\n): Promise<BluetoothPuzzle> {\n return bluetoothConnect<BluetoothPuzzle>(smartPuzzleConfigs, options);\n}\n", "import { Alg, Move } from \"../../alg\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\n\n// TODO: Remove this. It's only used for debugging.\nfunction buf2hex(buffer: ArrayBuffer): string {\n // buffer is an ArrayBuffer\n return (\n Array.prototype.map.call(new Uint8Array(buffer), (x: number) =>\n (\"00\" + x.toString(16)).slice(-2),\n ) as string[]\n ).join(\" \");\n}\n\nconst MAX_NIBBLES_PER_WRITE = 18 * 2;\nconst QUANTUM_TURN_DURATION_MS = 150;\nconst DOUBLE_TURN_DURATION_MS = 250;\n\nconst U_D_SWAP = new Alg(\"F B R2 L2 B' F'\");\nconst U_D_UNSWAP = U_D_SWAP.invert(); // TODO: make `cubing.js` clever enough to be able to reuse the regular swap.\nconst F_B_SWAP = new Alg(\"U D R2 L2 D' U'\");\nconst F_B_UNSWAP = F_B_SWAP.invert();\n\n// TODO: Short IDs\nconst UUIDs = {\n ganRobotService: \"0000fff0-0000-1000-8000-00805f9b34fb\",\n statusCharacteristic: \"0000fff2-0000-1000-8000-00805f9b34fb\",\n moveCharacteristic: \"0000fff3-0000-1000-8000-00805f9b34fb\",\n};\n\nconst moveMap: Record<string, number> = {\n \"R\": 0,\n \"R2\": 1,\n \"R2'\": 1,\n \"R'\": 2,\n \"F\": 3,\n \"F2\": 4,\n \"F2'\": 4,\n \"F'\": 5,\n \"D\": 6,\n \"D2\": 7,\n \"D2'\": 7,\n \"D'\": 8,\n \"L\": 9,\n \"L2\": 10,\n \"L2'\": 10,\n \"L'\": 11,\n \"B\": 12,\n \"B2\": 13,\n \"B2'\": 13,\n \"B'\": 14,\n};\n\nconst moveMapX: Record<string, number> = {\n \"R\": 0,\n \"R2\": 1,\n \"R2'\": 1,\n \"R'\": 2,\n \"U\": 3,\n \"U2\": 4,\n \"U2'\": 4,\n \"U'\": 5,\n \"F\": 6,\n \"F2\": 7,\n \"F2'\": 7,\n \"F'\": 8,\n \"L\": 9,\n \"L2\": 10,\n \"L2'\": 10,\n \"L'\": 11,\n \"D\": 12,\n \"D2\": 13,\n \"D2'\": 13,\n \"D'\": 14,\n};\n\nfunction isDoubleTurnNibble(nibble: number): boolean {\n return nibble % 3 === 1;\n}\n\nfunction nibbleDuration(nibble: number): number {\n return isDoubleTurnNibble(nibble)\n ? DOUBLE_TURN_DURATION_MS\n : QUANTUM_TURN_DURATION_MS;\n}\n\nfunction throwInvalidMove(move: Move) {\n console.error(\"invalid move\", move, move.toString());\n throw new Error(\"invalid move!\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface GanRobotStatus {\n movesRemaining: number;\n}\n\ninterface GanRobotOptions {\n xAngle: boolean;\n singleMoveFixHack: boolean;\n bufferQueue: number;\n postSleep: number;\n}\n\nexport class GanRobot extends EventTarget {\n experimentalDebugOnSend: ((alg: Alg) => void) | null = null;\n experimentalDebugLog: typeof console.log = () => {};\n\n // Because our Bluetooth connection code is set up not to know what kind of device is connecting, we put these options directly on the class.\n experimentalOptions: GanRobotOptions = {\n xAngle: false,\n singleMoveFixHack: false,\n bufferQueue: 0,\n postSleep: 0,\n };\n\n constructor(\n _service: BluetoothRemoteGATTService,\n private server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n private statusCharacteristic: BluetoothRemoteGATTCharacteristic,\n private moveCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n device.addEventListener(\n \"gattserverdisconnected\",\n this.onDisconnect.bind(this),\n );\n }\n\n // We have to perform async operations before we call the constructor.\n static async connect(\n server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n ) {\n const ganTimerService = await server.getPrimaryService(\n UUIDs.ganRobotService,\n );\n const statusCharacteristic = await ganTimerService.getCharacteristic(\n UUIDs.statusCharacteristic,\n );\n const moveCharacteristic = await ganTimerService.getCharacteristic(\n UUIDs.moveCharacteristic,\n );\n const timer = new GanRobot(\n ganTimerService,\n server,\n device,\n statusCharacteristic,\n moveCharacteristic,\n );\n return timer;\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n onDisconnect(): void {\n this.dispatchEvent(new CustomEvent(\"disconnect\"));\n }\n\n private moveToNibble(move: Move): number {\n const nibble =\n (this.experimentalOptions.xAngle ? moveMapX : moveMap)[move.toString()] ??\n null;\n if (nibble === null) {\n throwInvalidMove(move);\n }\n return nibble;\n }\n\n private async writeNibbles(nibbles: number[]): Promise<void> {\n if (nibbles.length > MAX_NIBBLES_PER_WRITE) {\n throw new Error(\n `Can only write ${MAX_NIBBLES_PER_WRITE} nibbles at a time!`,\n );\n }\n // const byteLength = Math.ceil(nibbles.length / 2);\n const bytes = new Uint8Array(18);\n let i: number;\n for (i = 0; i < nibbles.length; i++) {\n const byteIdx = Math.floor(i / 2);\n bytes[byteIdx] += nibbles[i];\n if (i % 2 === 0) {\n bytes[byteIdx] *= 0x10;\n }\n }\n if (nibbles.length % 2 === 1) {\n bytes[Math.ceil(nibbles.length / 2) - 1] += 0xf;\n }\n for (let i = Math.ceil(nibbles.length / 2); i < 18; i++) {\n bytes[i] = 0xff;\n }\n let sleepDuration = 0;\n for (const nibble of nibbles) {\n sleepDuration += nibbleDuration(nibble);\n }\n this.experimentalDebugLog(\"WRITING:\", buf2hex(bytes));\n await this.moveCharacteristic.writeValue(bytes);\n await sleep(sleepDuration * 0.75);\n while ((await this.getStatus()).movesRemaining > 0) {\n // repeat\n }\n await sleep(this.experimentalOptions.postSleep);\n }\n\n private async getStatus(): Promise<GanRobotStatus> {\n const statusBytes = new Uint8Array(\n (await this.statusCharacteristic.readValue()).buffer,\n );\n this.experimentalDebugLog(\"moves remaining:\", statusBytes[0]);\n return {\n movesRemaining: statusBytes[0],\n };\n }\n\n locked: boolean = false;\n processQueue(): void {}\n\n private moveQueue: Alg = new Alg();\n // TODO: Don't let this resolve until the move is done?\n private async queueMoves(moves: Alg): Promise<void> {\n this.moveQueue = this.moveQueue\n .concat(moves)\n .simplify({ collapseMoves: true, quantumMoveOrder: (_) => 4 });\n if (!this.locked) {\n // TODO: We're currently iterating over units instead of leaves to avoid \"zip bomps\".\n try {\n this.locked = true;\n if (this.moveQueue.experimentalNumUnits() === 1) {\n await sleep(this.experimentalOptions.bufferQueue);\n }\n // await this.writeNibbles([0xf, 0xf]);\n while (this.moveQueue.experimentalNumUnits() > 0) {\n let units = Array.from(this.moveQueue.units());\n if (\n this.experimentalOptions.singleMoveFixHack &&\n units.length === 1\n ) {\n const move = units[0] as Move;\n if (move.amount === 2) {\n units = [\n move.modified({ amount: 1 }),\n move.modified({ amount: 1 }),\n ];\n } else {\n units = [\n move.modified({ amount: -move.amount }),\n move.modified({ amount: 2 }),\n ];\n }\n }\n const moves = units.splice(0, MAX_NIBBLES_PER_WRITE);\n const nibbles: number[] = moves.map(this.moveToNibble.bind(this));\n const sending = new Alg(moves);\n this.experimentalDebugLog(\"SENDING\", sending.toString());\n if (this.experimentalDebugOnSend) {\n this.experimentalDebugOnSend(sending);\n }\n const write = this.writeNibbles(nibbles);\n this.moveQueue = new Alg(units);\n await write;\n }\n } finally {\n this.locked = false;\n }\n }\n }\n\n async applyMoves(moves: Iterable<Move>): Promise<void> {\n // const nibbles: number[] = [];\n for (const move of moves) {\n const str = move.toString();\n if (str in (this.experimentalOptions.xAngle ? moveMapX : moveMap)) {\n await this.queueMoves(new Alg([move]));\n } else if (\n move.family === (this.experimentalOptions.xAngle ? \"B\" : \"U\")\n ) {\n // We purposely send just the swap, so that U2 will get coalesced\n await Promise.all([\n this.queueMoves(\n this.experimentalOptions.xAngle ? F_B_SWAP : U_D_SWAP,\n ),\n this.queueMoves(\n new Alg([\n move.modified({\n family: this.experimentalOptions.xAngle ? \"F\" : \"D\",\n }),\n ]).concat(\n this.experimentalOptions.xAngle ? F_B_UNSWAP : U_D_UNSWAP,\n ),\n ),\n ]);\n }\n }\n }\n}\n\n// // TODO: Move this into a factory?\nexport const ganTimerConfig: BluetoothConfig<GanRobot> = {\n connect: GanRobot.connect.bind(GanRobot),\n prefixes: [\"GAN\"],\n filters: [{ namePrefix: \"GAN\" }],\n optionalServices: [UUIDs.ganRobotService],\n};\n", "import { bluetoothConnect, BluetoothConnectOptions } from \"../connect\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\nimport { GanRobot, ganTimerConfig } from \"./GanRobot\";\n\nexport type BluetoothRobot = GanRobot; // TODO\n\nconst smartRobotConfigs: BluetoothConfig<BluetoothRobot>[] = [ganTimerConfig];\n\nexport async function connectSmartRobot(\n options?: BluetoothConnectOptions,\n): Promise<BluetoothRobot> {\n return bluetoothConnect<BluetoothRobot>(smartRobotConfigs, options);\n}\n", "import type { MillisecondTimestamp } from \"../../twisty/controllers/AnimationTypes\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\n\n// TODO: Short IDs\nconst UUIDs = {\n ganTimerService: \"0000fff0-0000-1000-8000-00805f9b34fb\",\n timeCharacteristic: \"0000fff2-0000-1000-8000-00805f9b34fb\",\n};\n\ninterface GanTimerDetail {\n currentTime: MillisecondTimestamp;\n latestTimes: [\n MillisecondTimestamp,\n MillisecondTimestamp,\n MillisecondTimestamp,\n ];\n}\n\nexport class GanTimer extends EventTarget {\n private polling = false;\n private previousDetail: GanTimerDetail | null = null;\n\n constructor(\n _service: BluetoothRemoteGATTService,\n private server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n private timeCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n this.startPolling();\n console.log(server);\n device.addEventListener(\n \"gattserverdisconnected\",\n this.onDisconnect.bind(this),\n );\n }\n\n // We have to perform async operations before we call the constructor.\n static async connect(\n server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n ) {\n const ganTimerService = await server.getPrimaryService(\n UUIDs.ganTimerService,\n );\n console.log(\"Service:\", ganTimerService);\n const timeCharacteristic = await ganTimerService.getCharacteristic(\n UUIDs.timeCharacteristic,\n );\n console.log(\"Characteristic:\", timeCharacteristic);\n const timer = new GanTimer(\n ganTimerService,\n server,\n device,\n timeCharacteristic,\n );\n return timer;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n async poll() {\n if (!this.polling) {\n return;\n }\n const value = await this.getTimeCharacteristic();\n\n const detail: GanTimerDetail = {\n currentTime: this.decodeTimeMs(value.slice(0, 4)),\n latestTimes: [\n this.decodeTimeMs(value.slice(4, 8)),\n this.decodeTimeMs(value.slice(8, 12)),\n this.decodeTimeMs(value.slice(12, 16)),\n ],\n };\n\n if (detail.currentTime === 0) {\n if (this.previousDetail && this.previousDetail.currentTime !== 0) {\n this.dispatchEvent(new CustomEvent(\"reset\"));\n }\n }\n\n if (detail.currentTime !== 0 && this.previousDetail) {\n if (this.previousDetail.currentTime === 0) {\n this.dispatchEvent(new CustomEvent(\"start\"));\n }\n\n if (detail.currentTime !== this.previousDetail.currentTime) {\n this.dispatchEvent(new CustomEvent(\"update\", { detail }));\n\n if (\n detail.currentTime === detail.latestTimes[0] &&\n detail.latestTimes[1] === this.previousDetail.latestTimes[0] &&\n detail.latestTimes[2] === this.previousDetail.latestTimes[1]\n ) {\n this.dispatchEvent(new CustomEvent(\"stop\", { detail }));\n }\n }\n }\n\n this.previousDetail = detail;\n\n this.poll();\n }\n\n onDisconnect(): void {\n this.dispatchEvent(new CustomEvent(\"disconnect\"));\n }\n\n async getTimeCharacteristic() {\n return new Uint8Array((await this.timeCharacteristic.readValue()).buffer);\n }\n\n async getTime() {\n const value = await this.getTimeCharacteristic();\n return this.decodeTimeMs(value.slice(0, 4));\n }\n\n decodeTimeMs(bytes: Uint8Array) {\n return (bytes[0] * 60 + bytes[1]) * 1000 + bytes[2] + bytes[3] * 256;\n }\n\n startPolling() {\n this.polling = true;\n this.poll();\n }\n\n stopPolling() {\n this.polling = false;\n }\n}\n\n// // TODO: Move this into a factory?\nexport const ganTimerConfig: BluetoothConfig<GanTimer> = {\n connect: GanTimer.connect.bind(GanTimer),\n prefixes: [\"GAN\"],\n filters: [{ namePrefix: \"GAN\" }],\n optionalServices: [UUIDs.ganTimerService],\n};\n", "import { bluetoothConnect, BluetoothConnectOptions } from \"../connect\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\nimport { GanTimer, ganTimerConfig } from \"./GanTimer\";\n\nexport type BluetoothTimer = GanTimer; // TODO\n\nconst smartTimerConfigs: BluetoothConfig<BluetoothTimer>[] = [ganTimerConfig];\n\nexport async function connectSmartTimer(\n options?: BluetoothConnectOptions,\n): Promise<BluetoothTimer> {\n return bluetoothConnect<BluetoothTimer>(smartTimerConfigs, options);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["let DEBUG_LOGGING_ENABLED = false;\n\nexport function enableDebugLogging(enable: boolean): void {\n DEBUG_LOGGING_ENABLED = enable;\n}\n\n// TODO: Remove this.\nexport function debugLog(...args: any[]): void {\n if (!DEBUG_LOGGING_ENABLED) {\n return;\n }\n\n if (console.info) {\n console.info(...args);\n } else {\n console.log(...args);\n }\n}\n", "import { Quaternion, Vector3 } from \"three\";\nimport type {\n MoveEvent,\n OrientationEvent,\n} from \"./smart-puzzle/bluetooth-puzzle\";\n\n// TODO: Combine orientation and moves into a single event to handle quaternion remapping.\nexport interface StreamTransformer {\n // Modifies the input.\n transformMove(moveEvent: MoveEvent): void;\n\n // Modifies the input.\n transformOrientation(orientationEvent: OrientationEvent): void;\n}\n\nfunction maxAxis(v: Vector3): string {\n const maxVal = Math.max(Math.abs(v.x), Math.abs(v.y), Math.abs(v.z));\n switch (maxVal) {\n case v.x:\n return \"x\";\n case -v.x:\n return \"-x\";\n case v.y:\n return \"y\";\n case -v.y:\n return \"-y\";\n case v.z:\n return \"z\";\n case -v.z:\n return \"-z\";\n default:\n throw new Error(\"Uh-oh.\");\n }\n}\n\nconst s2 = Math.sqrt(0.5);\n\nconst m: { [s: string]: Quaternion } = {\n \"y z\": new Quaternion(0, 0, 0, 1),\n \"-z y\": new Quaternion(s2, 0, 0, s2),\n \"x z\": new Quaternion(0, 0, -s2, s2),\n \"-x z\": new Quaternion(0, 0, s2, s2),\n};\n\nexport class BasicRotationTransformer implements StreamTransformer {\n // private reorientQuat = new Quaternion();\n\n public transformMove(_moveEvent: MoveEvent): void {\n // Nothing to do.\n }\n\n public transformOrientation(orientationEvent: OrientationEvent): void {\n const { x, y, z, w } = orientationEvent.quaternion;\n const quat = new Quaternion(x, y, z, w);\n\n const U = new Vector3(0, 1, 0);\n const F = new Vector3(0, 0, 1);\n const maxU = maxAxis(U.applyQuaternion(quat));\n const maxF = maxAxis(F.applyQuaternion(quat));\n\n const oriQuat = m[`${maxU} ${maxF}`] || m[\"y z\"];\n\n console.log(quat);\n console.log(oriQuat);\n const q2 = quat.premultiply(oriQuat);\n\n // console.log(maxAxis(U.applyQuaternion(quat)), maxAxis(F.applyQuaternion(quat)));\n console.log(q2);\n\n orientationEvent.quaternion = quat;\n\n console.log(orientationEvent.quaternion);\n }\n}\n", "import type { Move } from \"../../alg\";\nimport type { KState } from \"../../kpuzzle/KState\";\nimport { BasicRotationTransformer, StreamTransformer } from \"../transformer\";\n\n/******** BluetoothPuzzle ********/\n\n// TODO: Use actual `CustomEvent`s?\n// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent\nexport interface MoveEvent {\n latestMove: Move;\n timeStamp: number;\n debug?: Record<string, unknown>;\n state?: KState;\n quaternion?: any; // TODO: Unused\n}\n\n// TODO: Only use the `quaternion` field in the `MoveEvent`?\nexport interface OrientationEvent {\n quaternion: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n timeStamp: number;\n debug?: Record<string, unknown>;\n}\n\nexport interface BluetoothConfig<T> {\n connect: (\n server: BluetoothRemoteGATTServer,\n device?: BluetoothDevice,\n ) => Promise<T>;\n // TODO: Can we reuse `filters`?\n prefixes: string[]; // `[\"\"]` for GiiKER\n filters: BluetoothLEScanFilter[];\n optionalServices: BluetoothServiceUUID[];\n}\n\n// TODO: Expose device name (and/or globally unique identifier)?\nexport abstract class BluetoothPuzzle extends EventTarget {\n public transformers: StreamTransformer[] = [];\n protected listeners: Array<(e: MoveEvent) => void> = []; // TODO: type\n protected orientationListeners: Array<(e: OrientationEvent) => void> = []; // TODO: type\n\n public abstract name(): string | undefined;\n public abstract disconnect(): void; // TODO: Can we make this reutrn (async) on success?\n\n // TODO: require subclasses to implement this?\n public async getState(): Promise<KState> {\n throw new Error(\"cannot get state\");\n }\n\n public addMoveListener(listener: (e: MoveEvent) => void): void {\n this.listeners.push(listener);\n }\n\n public addOrientationListener(listener: (e: OrientationEvent) => void): void {\n this.orientationListeners.push(listener);\n }\n\n public experimentalAddBasicRotationTransformer(): void {\n this.transformers.push(new BasicRotationTransformer());\n }\n\n protected dispatchMove(moveEvent: MoveEvent): void {\n for (const transformer of this.transformers) {\n transformer.transformMove(moveEvent);\n }\n for (const l of this.listeners) {\n l(moveEvent);\n }\n }\n\n protected dispatchOrientation(orientationEvent: OrientationEvent): void {\n for (const transformer of this.transformers) {\n transformer.transformOrientation(orientationEvent);\n }\n const { x, y, z, w } = orientationEvent.quaternion;\n // TODO: can we avoid mutating the source event?\n orientationEvent.quaternion = {\n x,\n y,\n z,\n w,\n };\n for (const l of this.orientationListeners) {\n // TODO: Convert quaternion.\n l(orientationEvent);\n }\n }\n}\n", "import { keyToMove } from \"../alg\";\nimport type { KPuzzle } from \"../kpuzzle\";\nimport type { KState } from \"../kpuzzle/KState\";\nimport { puzzles } from \"../puzzles\";\nimport { BluetoothPuzzle } from \"./smart-puzzle/bluetooth-puzzle\";\n\nexport class KeyboardPuzzle extends BluetoothPuzzle {\n private puzzle: Promise<KPuzzle> = puzzles[\"3x3x3\"].kpuzzle();\n private state: Promise<KState> = (async () =>\n (await this.puzzle).startState())();\n\n listener: (e: KeyboardEvent) => Promise<void>;\n\n // TODO: Decide on the right arguments.\n constructor(private target: Element) {\n super();\n // TODO: Filter out repeated keydown?\n this.listener = this.onKeyDown.bind(this);\n target.addEventListener(\"keydown\", this.listener);\n }\n\n public name(): string | undefined {\n return \"Keyboard Input\";\n }\n\n disconnect() {\n this.target.removeEventListener(\"keydown\", this.listener);\n }\n\n public async getState(): Promise<KState> {\n return this.state;\n }\n\n private async onKeyDown(e: KeyboardEvent): Promise<void> {\n if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {\n return;\n }\n\n const move = keyToMove(e);\n if (move) {\n const newState = (await this.state).applyMove(move);\n this.state = Promise.resolve(newState);\n this.dispatchMove({\n latestMove: move,\n timeStamp: e.timeStamp,\n state: newState,\n });\n e.preventDefault();\n }\n }\n}\n\n// TODO: Type\nexport async function debugKeyboardConnect(\n target: any = window,\n): Promise<KeyboardPuzzle> {\n return new KeyboardPuzzle(target);\n}\n", "import { debugLog } from \"../debug\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\n\n/******** requestOptions ********/\n\nfunction requestOptions<T>(\n configs: BluetoothConfig<T>[],\n acceptAllDevices: boolean = false,\n): RequestDeviceOptions {\n const options = acceptAllDevices\n ? {\n acceptAllDevices: true,\n optionalServices: [] as BluetoothServiceUUID[],\n }\n : {\n filters: [] as BluetoothLEScanFilter[],\n optionalServices: [] as BluetoothServiceUUID[],\n };\n for (const config of configs) {\n if (!acceptAllDevices) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n options.filters = options.filters!.concat(config.filters);\n }\n options.optionalServices = options.optionalServices.concat(\n config.optionalServices,\n );\n }\n debugLog({ requestOptions: options });\n return options;\n}\n\n/******** connect() ********/\n\nexport interface BluetoothConnectOptions {\n acceptAllDevices?: boolean;\n}\n\n// We globally track the number of connection failures,\n// in order to offer the user recourse (accept all devices) if they're having issues.\n// This allows us to future-proof situations where a device might not show up in\n// the chooser, but works if we connect.\nlet consecutiveFailures = 0;\nconst MAX_FAILURES_BEFORE_ACCEPT_ALL_FALLBACK = 2;\n\n// TODO: Debug options to allow connecting to any device?\nexport async function bluetoothConnect<T>(\n configs: BluetoothConfig<T>[],\n options: BluetoothConnectOptions = {},\n): Promise<T> {\n debugLog(\"Attempting to pair.\");\n let device;\n try {\n let acceptAllDevices = options.acceptAllDevices;\n if (\n !acceptAllDevices &&\n consecutiveFailures >= MAX_FAILURES_BEFORE_ACCEPT_ALL_FALLBACK\n ) {\n console.info(\n `The last ${MAX_FAILURES_BEFORE_ACCEPT_ALL_FALLBACK} Bluetooth puzzle connection attempts failed. This time, the Bluetooth prompt will show all possible devices.`,\n );\n acceptAllDevices = true;\n }\n device = await navigator.bluetooth.requestDevice(\n requestOptions<T>(configs, acceptAllDevices),\n );\n consecutiveFailures = 0;\n } catch (e) {\n consecutiveFailures++;\n throw new Error(e);\n }\n debugLog(\"Device:\", device);\n\n if (typeof device.gatt === \"undefined\") {\n return Promise.reject(\"Device did not have a GATT server.\");\n }\n\n const server = await device.gatt.connect();\n debugLog(\"Server:\", server);\n\n const name = server.device?.name || \"\";\n\n // TODO by reading supported matched filters or provided services.\n\n for (const config of configs) {\n for (const prefix of config.prefixes) {\n if (name?.startsWith(prefix)) {\n return config.connect(server, device);\n }\n }\n }\n\n throw Error(\"Unknown Bluetooth devive.\");\n}\n", "/* tslint:disable no-bitwise */\n\nimport { Quaternion } from \"three\";\nimport { Move } from \"../../alg\";\nimport type { KPuzzle, KStateData } from \"../../kpuzzle\";\nimport { KState } from \"../../kpuzzle\";\nimport { puzzles } from \"../../puzzles\";\nimport {\n importKey,\n unsafeDecryptBlock,\n} from \"../../vendor/unsafe-raw-aes/unsafe-raw-aes\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\n\n// This needs to be short enough to capture 6 moves (OBQTM).\nconst DEFAULT_INTERVAL_MS = 150;\n// Number of latest moves provided by the Gan 356i.\nconst MAX_LATEST_MOVES = 6;\n\nconst ganMoveToBlockMove: { [i: number]: Move } = {\n 0x00: new Move(\"U\"),\n 0x02: new Move(\"U\", -1),\n 0x03: new Move(\"R\"),\n 0x05: new Move(\"R\", -1),\n 0x06: new Move(\"F\"),\n 0x08: new Move(\"F\", -1),\n 0x09: new Move(\"D\"),\n 0x0b: new Move(\"D\", -1),\n 0x0c: new Move(\"L\"),\n 0x0e: new Move(\"L\", -1),\n 0x0f: new Move(\"B\"),\n 0x11: new Move(\"B\", -1),\n};\n\nlet homeQuatInverse: Quaternion | null = null;\n\nfunction probablyDecodedCorrectly(data: Uint8Array): boolean {\n return (\n data[13] < 0x12 &&\n data[14] < 0x12 &&\n data[15] < 0x12 &&\n data[16] < 0x12 &&\n data[17] < 0x12 &&\n data[18] < 0x12\n );\n}\n\nconst key10 = new Uint8Array([\n 198, 202, 21, 223, 79, 110, 19, 182, 119, 13, 230, 89, 58, 175, 186, 162,\n]);\nconst key11 = new Uint8Array([\n 67, 226, 91, 214, 125, 220, 120, 216, 7, 96, 163, 218, 130, 60, 1, 241,\n]);\n\n// Clean-room reverse-engineered\nasync function decryptState(\n data: Uint8Array,\n aesKey: CryptoKey | null,\n): Promise<Uint8Array> {\n if (aesKey === null) {\n return data;\n }\n\n const copy = new Uint8Array(data);\n copy.set(new Uint8Array(await unsafeDecryptBlock(aesKey, copy.slice(3))), 3);\n copy.set(\n new Uint8Array(await unsafeDecryptBlock(aesKey, copy.slice(0, 16))),\n 0,\n );\n\n if (probablyDecodedCorrectly(copy)) {\n return copy;\n }\n\n throw new Error(\"Invalid Gan cube state\");\n}\n\nclass PhysicalState {\n public static async read(\n characteristic: BluetoothRemoteGATTCharacteristic,\n aesKey: CryptoKey | null,\n ): Promise<PhysicalState> {\n const value = await decryptState(\n new Uint8Array((await characteristic.readValue()).buffer),\n aesKey,\n );\n const timeStamp = Date.now();\n // console.log(value);\n return new PhysicalState(new DataView(value.buffer), timeStamp);\n }\n\n private arr: Uint8Array;\n private arrLen = 19;\n private constructor(private dataView: DataView, public timeStamp: number) {\n this.arr = new Uint8Array(dataView.buffer);\n if (this.arr.length !== this.arrLen) {\n throw new Error(\"Unexpected array length\");\n }\n }\n\n public rotQuat(): Quaternion {\n let x = this.dataView.getInt16(0, true) / 16384;\n let y = this.dataView.getInt16(2, true) / 16384;\n let z = this.dataView.getInt16(4, true) / 16384;\n [x, y, z] = [-y, z, -x];\n const wSquared = 1 - (x * x + y * y + z * z);\n const w = wSquared > 0 ? Math.sqrt(wSquared) : 0;\n const quat = new Quaternion(x, y, z, w);\n\n if (!homeQuatInverse) {\n homeQuatInverse = quat.clone().inverse();\n }\n\n return quat.clone().multiply(homeQuatInverse.clone());\n }\n\n // Loops from 255 to 0.\n public moveCounter(): number {\n return this.arr[12];\n }\n\n public numMovesSince(previousMoveCounter: number): number {\n return (this.moveCounter() - previousMoveCounter) & 0xff;\n }\n\n // Due to the design of the Gan356i protocol, it's common to query for the\n // latest physical state and find 0 moves have been performed since the last\n // query. Therefore, it's useful to allow 0 as an argument.\n public latestMoves(n: number): Move[] {\n if (n < 0 || n > MAX_LATEST_MOVES) {\n throw new Error(`Must ask for 0 to 6 latest moves. (Asked for ${n})`);\n }\n return Array.from(this.arr.slice(19 - n, 19)).map(\n (i) => ganMoveToBlockMove[i],\n );\n }\n\n public debugInfo(): { arr: Uint8Array } {\n return {\n arr: this.arr,\n };\n }\n}\n\n// TODO: Short IDs\nconst UUIDs = {\n ganCubeService: \"0000fff0-0000-1000-8000-00805f9b34fb\",\n physicalStateCharacteristic: \"0000fff5-0000-1000-8000-00805f9b34fb\",\n actualAngleAndBatteryCharacteristic: \"0000fff7-0000-1000-8000-00805f9b34fb\",\n faceletStatus1Characteristic: \"0000fff2-0000-1000-8000-00805f9b34fb\",\n faceletStatus2Characteristic: \"0000fff3-0000-1000-8000-00805f9b34fb\",\n infoService: \"0000180a-0000-1000-8000-00805f9b34fb\",\n systemIDCharacteristic: \"00002a23-0000-1000-8000-00805f9b34fb\",\n versionCharacteristic: \"00002a28-0000-1000-8000-00805f9b34fb\",\n};\n\nconst commands: { [cmd: string]: BufferSource } = {\n reset: new Uint8Array([\n 0x00, 0x00, 0x24, 0x00, 0x49, 0x92, 0x24, 0x49, 0x6d, 0x92, 0xdb, 0xb6,\n 0x49, 0x92, 0xb6, 0x24, 0x6d, 0xdb,\n ]),\n};\n\nfunction buf2hex(buffer: ArrayBuffer): string {\n // buffer is an ArrayBuffer\n return (\n Array.prototype.map.call(new Uint8Array(buffer), (x: number) =>\n (\"00\" + x.toString(16)).slice(-2),\n ) as string[]\n ).join(\" \");\n}\n\nconst reidEdgeOrder = \"UF UR UB UL DF DR DB DL FR FL BR BL\".split(\" \");\nconst reidCornerOrder = \"UFR URB UBL ULF DRF DFL DLB DBR\".split(\" \");\n\ninterface PieceInfo {\n piece: number;\n orientation: number;\n}\n\nfunction rotateLeft(s: string, i: number): string {\n return s.slice(i) + s.slice(0, i);\n}\n\nconst pieceMap: { [s: string]: PieceInfo } = {};\n// TODO: Condense the for loops.\nreidEdgeOrder.forEach((edge, idx) => {\n for (let i = 0; i < 2; i++) {\n pieceMap[rotateLeft(edge, i)] = { piece: idx, orientation: i };\n }\n});\nreidCornerOrder.forEach((corner, idx) => {\n for (let i = 0; i < 3; i++) {\n pieceMap[rotateLeft(corner, i)] = { piece: idx, orientation: i };\n }\n});\n\nconst gan356iCornerMappings = [\n [0, 21, 15],\n [5, 13, 47],\n [7, 45, 39],\n [2, 37, 23],\n [29, 10, 16],\n [31, 18, 32],\n [26, 34, 40],\n [24, 42, 8],\n];\n\nconst gan356iEdgeMappings = [\n [1, 22],\n [3, 14],\n [6, 46],\n [4, 38],\n [30, 17],\n [27, 9],\n [25, 41],\n [28, 33],\n [19, 12],\n [20, 35],\n [44, 11],\n [43, 36],\n];\nconst faceOrder = \"URFDLB\";\n\nasync function getKey(\n server: BluetoothRemoteGATTServer,\n): Promise<CryptoKey | null> {\n const infoService = await server.getPrimaryService(UUIDs.infoService);\n\n const versionCharacteristic = await infoService.getCharacteristic(\n UUIDs.versionCharacteristic,\n );\n const versionBuffer = new Uint8Array(\n (await versionCharacteristic.readValue()).buffer,\n );\n\n const versionValue =\n (((versionBuffer[0] << 8) + versionBuffer[1]) << 8) + versionBuffer[2];\n if (versionValue < 0x01_00_08) {\n return null;\n }\n\n const keyXor = versionValue < 0x01_01_00 ? key10 : key11;\n\n const systemIDCharacteristic = await infoService.getCharacteristic(\n UUIDs.systemIDCharacteristic,\n );\n const systemID = new Uint8Array(\n (await systemIDCharacteristic.readValue()).buffer,\n ).reverse();\n\n const key = new Uint8Array(keyXor);\n for (let i = 0; i < systemID.length; i++) {\n key[i] = (key[i] + systemID[i]) % 256;\n }\n\n return importKey(key);\n}\n\nexport class GanCube extends BluetoothPuzzle {\n // We have to perform async operations before we call the constructor.\n public static async connect(\n server: BluetoothRemoteGATTServer,\n ): Promise<GanCube> {\n const ganCubeService = await server.getPrimaryService(UUIDs.ganCubeService);\n debugLog(\"Service:\", ganCubeService);\n\n const physicalStateCharacteristic = await ganCubeService.getCharacteristic(\n UUIDs.physicalStateCharacteristic,\n );\n debugLog(\"Characteristic:\", physicalStateCharacteristic);\n\n const aesKey = await getKey(server);\n\n const initialMoveCounter = (\n await PhysicalState.read(physicalStateCharacteristic, aesKey)\n ).moveCounter();\n debugLog(\"Initial Move Counter:\", initialMoveCounter);\n const cube = new GanCube(\n await puzzles[\"3x3x3\"].kpuzzle(),\n ganCubeService,\n server,\n physicalStateCharacteristic,\n initialMoveCounter,\n aesKey,\n );\n return cube;\n }\n\n public INTERVAL_MS: number = DEFAULT_INTERVAL_MS;\n private intervalHandle: number | null = null;\n private state: KState;\n private cachedFaceletStatus1Characteristic: Promise<BluetoothRemoteGATTCharacteristic>;\n\n private cachedFaceletStatus2Characteristic: Promise<BluetoothRemoteGATTCharacteristic>;\n\n private cachedActualAngleAndBatteryCharacteristic: Promise<BluetoothRemoteGATTCharacteristic>;\n\n private constructor(\n private kpuzzle: KPuzzle,\n private service: BluetoothRemoteGATTService,\n private server: BluetoothRemoteGATTServer,\n private physicalStateCharacteristic: BluetoothRemoteGATTCharacteristic,\n private lastMoveCounter: number,\n private aesKey: CryptoKey | null,\n ) {\n super();\n this.state = kpuzzle.startState();\n this.startTrackingMoves();\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n public startTrackingMoves(): void {\n // `window.setInterval` instead of `setInterval`:\n // https://github.com/Microsoft/TypeScript/issues/842#issuecomment-252445883\n this.intervalHandle = window.setInterval(\n this.intervalHandler.bind(this),\n this.INTERVAL_MS,\n );\n }\n\n public stopTrackingMoves(): void {\n if (!this.intervalHandle) {\n throw new Error(\"Not tracking moves!\");\n }\n clearInterval(this.intervalHandle);\n this.intervalHandle = null;\n }\n\n // TODO: Can we ever receive async responses out of order?\n public async intervalHandler(): Promise<void> {\n const physicalState = await PhysicalState.read(\n this.physicalStateCharacteristic,\n this.aesKey,\n );\n let numInterveningMoves = physicalState.numMovesSince(this.lastMoveCounter);\n // console.log(numInterveningMoves);\n if (numInterveningMoves > MAX_LATEST_MOVES) {\n debugLog(\n `Too many moves! Dropping ${\n numInterveningMoves - MAX_LATEST_MOVES\n } moves`,\n );\n numInterveningMoves = MAX_LATEST_MOVES;\n }\n for (const move of physicalState.latestMoves(numInterveningMoves)) {\n // console.log(move);\n this.state = this.state.applyMove(move);\n this.dispatchMove({\n latestMove: move,\n timeStamp: physicalState.timeStamp,\n debug: physicalState.debugInfo(),\n state: this.state,\n // quaternion: physicalState.rotQuat(),\n });\n }\n this.dispatchOrientation({\n timeStamp: physicalState.timeStamp,\n quaternion: physicalState.rotQuat(),\n });\n this.lastMoveCounter = physicalState.moveCounter();\n }\n\n public async getBattery(): Promise<number> {\n return new Uint8Array(\n await this.readActualAngleAndBatteryCharacteristic(),\n )[7];\n }\n\n public async getState(): Promise<KState> {\n const arr: Uint8Array = await decryptState(\n new Uint8Array(await this.readFaceletStatus1Characteristic()),\n this.aesKey,\n );\n const stickers: number[] = [];\n for (let i = 0; i < 18; i += 3) {\n let v = (((arr[i ^ 1] << 8) + arr[(i + 1) ^ 1]) << 8) + arr[(i + 2) ^ 1];\n for (let j = 0; j < 8; j++) {\n stickers.push(v & 7);\n v >>= 3;\n }\n }\n\n const stateData: KStateData = {\n CORNERS: {\n pieces: [],\n orientation: [],\n },\n EDGES: {\n pieces: [],\n orientation: [],\n },\n CENTERS: {\n pieces: [0, 1, 2, 3, 4, 5],\n orientation: [0, 0, 0, 0, 0, 0],\n },\n };\n\n for (const cornerMapping of gan356iCornerMappings) {\n const pieceInfo: PieceInfo =\n pieceMap[cornerMapping.map((i) => faceOrder[stickers[i]]).join(\"\")];\n stateData.CORNERS.pieces.push(pieceInfo.piece);\n stateData.CORNERS.orientation.push(pieceInfo.orientation);\n }\n\n for (const edgeMapping of gan356iEdgeMappings) {\n const pieceInfo: PieceInfo =\n pieceMap[edgeMapping.map((i) => faceOrder[stickers[i]]).join(\"\")];\n stateData.EDGES.pieces.push(pieceInfo.piece);\n stateData.EDGES.orientation.push(pieceInfo.orientation);\n }\n\n return new KState(this.kpuzzle, stateData);\n }\n\n public async faceletStatus1Characteristic(): Promise<BluetoothRemoteGATTCharacteristic> {\n this.cachedFaceletStatus1Characteristic =\n this.cachedFaceletStatus1Characteristic ||\n this.service.getCharacteristic(UUIDs.faceletStatus1Characteristic);\n return this.cachedFaceletStatus1Characteristic;\n }\n\n public async faceletStatus2Characteristic(): Promise<BluetoothRemoteGATTCharacteristic> {\n this.cachedFaceletStatus2Characteristic =\n this.cachedFaceletStatus2Characteristic ||\n this.service.getCharacteristic(UUIDs.faceletStatus2Characteristic);\n return this.cachedFaceletStatus2Characteristic;\n }\n\n public async actualAngleAndBatteryCharacteristic(): Promise<BluetoothRemoteGATTCharacteristic> {\n this.cachedActualAngleAndBatteryCharacteristic =\n this.cachedActualAngleAndBatteryCharacteristic ||\n this.service.getCharacteristic(UUIDs.actualAngleAndBatteryCharacteristic);\n return this.cachedActualAngleAndBatteryCharacteristic;\n }\n\n public async reset(): Promise<void> {\n const faceletStatus1Characteristic =\n await this.faceletStatus1Characteristic();\n await faceletStatus1Characteristic.writeValue(commands.reset);\n }\n\n public async readFaceletStatus1Characteristic(): Promise<ArrayBuffer> {\n const faceletStatus1Characteristic =\n await this.faceletStatus1Characteristic();\n return (await faceletStatus1Characteristic.readValue()).buffer;\n }\n\n public async readFaceletStatus2Characteristic(): Promise<string> {\n const faceletStatus2Characteristic =\n await this.faceletStatus2Characteristic();\n return buf2hex((await faceletStatus2Characteristic.readValue()).buffer);\n }\n\n public async readActualAngleAndBatteryCharacteristic(): Promise<ArrayBuffer> {\n const actualAngleAndBatteryCharacteristic =\n await this.actualAngleAndBatteryCharacteristic();\n return (await actualAngleAndBatteryCharacteristic.readValue()).buffer;\n }\n\n // TODO\n // private onphysicalStateCharacteristicChanged(event: any): void {\n // var val = event.target.value;\n // debugLog(val);\n // }\n}\n\n// // TODO: Move this into a factory?\nexport const ganConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: GanCube.connect.bind(GanCube),\n prefixes: [\"GAN\"],\n filters: [{ namePrefix: \"GAN\" }],\n optionalServices: [UUIDs.ganCubeService, UUIDs.infoService],\n};\n", "const blockSize = 16;\nconst zeros = new Uint8Array(blockSize);\nconst paddingBlockPlaintext = new Uint8Array(\n new Array(blockSize).fill(blockSize),\n);\nconst AES_CBC = \"AES-CBC\";\n\nexport async function importKey(keyBytes: ArrayBuffer): Promise<CryptoKey> {\n return await crypto.subtle.importKey(\"raw\", keyBytes, AES_CBC, true, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\nasync function unsafeEncryptBlockWithIV(\n key: CryptoKey,\n plaintextBlock: ArrayBuffer,\n iv: ArrayBuffer,\n): Promise<ArrayBuffer> {\n const cryptoResult: ArrayBuffer = await window.crypto.subtle.encrypt(\n {\n name: AES_CBC,\n iv,\n },\n key,\n plaintextBlock,\n );\n return cryptoResult.slice(0, blockSize);\n}\n\nexport async function unsafeEncryptBlock(\n key: CryptoKey,\n plaintextBlock: ArrayBuffer,\n): Promise<ArrayBuffer> {\n return (await unsafeEncryptBlockWithIV(key, plaintextBlock, zeros)).slice(\n 0,\n blockSize,\n );\n}\n\nexport async function unsafeDecryptBlock(\n key: CryptoKey,\n ciphertextBlock: ArrayBuffer,\n): Promise<ArrayBuffer> {\n const paddingBlock = await unsafeEncryptBlockWithIV(\n key,\n paddingBlockPlaintext,\n ciphertextBlock,\n );\n\n const cbcCiphertext = new Uint8Array(2 * blockSize);\n cbcCiphertext.set(new Uint8Array(ciphertextBlock), 0);\n cbcCiphertext.set(new Uint8Array(paddingBlock), blockSize);\n\n const cryptoResult: ArrayBuffer = await window.crypto.subtle.decrypt(\n {\n name: AES_CBC,\n iv: zeros,\n },\n key,\n cbcCiphertext,\n );\n return cryptoResult.slice(0, blockSize);\n}\n", "/* tslint:disable no-bitwise */\n\nimport { Move } from \"../../alg\";\nimport { KState, KStateData } from \"../../kpuzzle\";\nimport { experimental3x3x3KPuzzle } from \"../../puzzles/cubing-private\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\n\nconst MESSAGE_LENGTH = 20;\n\nconst UUIDs = {\n cubeService: \"0000aadb-0000-1000-8000-00805f9b34fb\",\n cubeCharacteristic: \"0000aadc-0000-1000-8000-00805f9b34fb\",\n};\n\n// TODO: Expose for testing.\nfunction giikerMoveToAlgMove(face: number, amount: number): Move {\n switch (amount) {\n case 3:\n amount = -1;\n break;\n case 9:\n debugLog(\"Encountered 9\", face, amount);\n amount = -2;\n break;\n }\n\n const family = [\"?\", \"B\", \"D\", \"L\", \"U\", \"R\", \"F\"][face];\n return new Move(family, amount);\n}\n\nexport { giikerMoveToAlgMove as giikerMoveToAlgMoveForTesting };\n\nfunction giikerStateStr(giikerState: number[]): string {\n let str = \"\";\n str += giikerState.slice(0, 8).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(8, 16).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(16, 28).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(28, 32).join(\".\");\n str += \"\\n\";\n str += giikerState.slice(32, 40).join(\".\");\n return str;\n}\n\n// TODO\n// const Reid333Orbits = {\n// \"EDGES\": {\"numPieces\": 12, \"orientations\": 2},\n// \"CORNERS\": {\"numPieces\": 8, \"orientations\": 3},\n// \"CENTERS\": {\"numPieces\": 6, \"orientations\": 4}\n// };\n\nconst Reid333SolvedCenters = {\n pieces: [0, 1, 2, 3, 4, 5],\n orientation: [0, 0, 0, 0, 0, 0],\n};\n\nconst epGiiKERtoReid333: number[] = [4, 8, 0, 9, 5, 1, 3, 7, 6, 10, 2, 11];\nconst epReid333toGiiKER: number[] = [2, 5, 10, 6, 0, 4, 8, 7, 1, 3, 9, 11];\n\nconst preEO: number[] = [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0];\nconst postEO: number[] = [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0];\n\nconst cpGiiKERtoReid333: number[] = [4, 0, 3, 5, 7, 1, 2, 6];\nconst cpReid333toGiiKER: number[] = [1, 5, 6, 2, 0, 3, 7, 4];\n\nconst preCO: number[] = [1, 2, 1, 2, 2, 1, 2, 1];\nconst postCO: number[] = [2, 1, 2, 1, 1, 2, 1, 2];\n\nconst coFlip: number[] = [-1, 1, -1, 1, 1, -1, 1, -1];\n\nfunction getNibble(val: Uint8Array, i: number): number {\n if (i % 2 === 1) {\n return val[(i / 2) | 0] % 16;\n }\n return 0 | (val[(i / 2) | 0] / 16);\n}\n\nfunction probablyEncrypted(data: Uint8Array): boolean {\n return data[18] === 0xa7;\n}\n\nconst lookup = [\n 176, 81, 104, 224, 86, 137, 237, 119, 38, 26, 193, 161, 210, 126, 150, 81, 93,\n 13, 236, 249, 89, 235, 88, 24, 113, 81, 214, 131, 130, 199, 2, 169, 39, 165,\n 171, 41,\n];\n\nfunction decryptState(data: Uint8Array): Uint8Array {\n const offset1 = getNibble(data, 38);\n const offset2 = getNibble(data, 39);\n const output = new Uint8Array(MESSAGE_LENGTH);\n for (let i = 0; i < MESSAGE_LENGTH; i++) {\n output[i] = data[i] + lookup[offset1 + i] + lookup[offset2 + i];\n }\n return output;\n}\n\n// TODO: Support caching which decoding strategy worked last time.\nasync function decodeState(data: Uint8Array): Promise<Uint8Array> {\n if (!probablyEncrypted(data)) {\n return data;\n }\n return decryptState(data);\n // TODO: Check that the decrypted state is a valid staet.\n}\n\nexport class GiiKERCube extends BluetoothPuzzle {\n public static async connect(\n server: BluetoothRemoteGATTServer,\n ): Promise<GiiKERCube> {\n const cubeService = await server.getPrimaryService(UUIDs.cubeService);\n debugLog(\"Service:\", cubeService);\n\n const cubeCharacteristic = await cubeService.getCharacteristic(\n UUIDs.cubeCharacteristic,\n );\n debugLog(\"Characteristic:\", cubeCharacteristic);\n\n // TODO: Can we safely save the async promise instead of waiting for the response?\n\n const originalValue = await decodeState(\n new Uint8Array((await cubeCharacteristic.readValue()).buffer),\n );\n debugLog(\"Original value:\", originalValue);\n const cube = new GiiKERCube(server, cubeCharacteristic, originalValue);\n\n await cubeCharacteristic.startNotifications();\n cubeCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n cube.onCubeCharacteristicChanged.bind(cube),\n );\n\n return cube;\n }\n\n private constructor(\n private server: BluetoothRemoteGATTServer,\n private cubeCharacteristic: BluetoothRemoteGATTCharacteristic,\n private originalValue?: Uint8Array | null,\n ) {\n super();\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n public async getState(): Promise<KState> {\n return this.toReid333(\n new Uint8Array((await this.cubeCharacteristic.readValue()).buffer),\n );\n }\n\n private getBit(val: Uint8Array, i: number): number {\n const n = (i / 8) | 0;\n const shift = 7 - (i % 8);\n return (val[n] >> shift) & 1;\n }\n\n private toReid333(val: Uint8Array): KState {\n const state: KStateData = {\n EDGES: {\n pieces: new Array(12),\n orientation: new Array(12),\n },\n CORNERS: {\n pieces: new Array(8),\n orientation: new Array(8),\n },\n CENTERS: Reid333SolvedCenters,\n };\n\n for (let i = 0; i < 12; i++) {\n const gi = epReid333toGiiKER[i];\n state.EDGES.pieces[i] = epGiiKERtoReid333[getNibble(val, gi + 16) - 1];\n state.EDGES.orientation[i] =\n this.getBit(val, gi + 112) ^ preEO[state.EDGES.pieces[i]] ^ postEO[i];\n }\n for (let i = 0; i < 8; i++) {\n const gi = cpReid333toGiiKER[i];\n state.CORNERS.pieces[i] = cpGiiKERtoReid333[getNibble(val, gi) - 1];\n state.CORNERS.orientation[i] =\n (getNibble(val, gi + 8) * coFlip[gi] +\n preCO[state.CORNERS.pieces[i]] +\n postCO[i]) %\n 3;\n }\n return new KState(experimental3x3x3KPuzzle, state);\n }\n\n private async onCubeCharacteristicChanged(event: any): Promise<void> {\n const val = await decodeState(new Uint8Array(event.target.value.buffer));\n debugLog(val);\n debugLog(val);\n\n if (this.isRepeatedInitialValue(val)) {\n debugLog(\"Skipping repeated initial value.\");\n return;\n }\n\n const giikerState = [];\n for (let i = 0; i < MESSAGE_LENGTH; i++) {\n giikerState.push(Math.floor(val[i] / 16));\n giikerState.push(val[i] % 16);\n }\n debugLog(giikerState);\n const str = giikerStateStr(giikerState);\n debugLog(str);\n\n this.dispatchMove({\n latestMove: giikerMoveToAlgMove(giikerState[32], giikerState[33]),\n timeStamp: event.timeStamp,\n debug: {\n stateStr: str,\n },\n state: this.toReid333(val),\n });\n }\n\n private isRepeatedInitialValue(val: Uint8Array): boolean {\n if (typeof this.originalValue === \"undefined\") {\n // TODO: Test this branch.\n throw new Error(\"GiiKERCube has uninitialized original value.\");\n }\n\n if (this.originalValue === null) {\n return false;\n }\n\n const originalValue = this.originalValue;\n // Reset the value here, so we can return early below.\n this.originalValue = null;\n\n debugLog(\"Comparing against original value.\");\n for (let i = 0; i < MESSAGE_LENGTH - 2; i++) {\n if (originalValue[i] !== val[i]) {\n debugLog(\"Different at index \", i);\n return false;\n }\n }\n return true;\n }\n}\n\n// TODO: Move this into a factory?\nexport const giiKERConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: GiiKERCube.connect.bind(GiiKERCube),\n prefixes: [\"Gi\", \"\"], // Hack\n filters: [\n // Known prefixes: GiC, GiS (3x3x3), Gi2 (2x2x2)\n // Suspected prefixes GiY, Gi3\n { namePrefix: \"Gi\" },\n { services: [\"0000aadb-0000-1000-8000-00805f9b34fb\"] },\n { services: [\"0000aaaa-0000-1000-8000-00805f9b34fb\"] },\n { services: [\"0000fe95-0000-1000-8000-00805f9b34fb\"] },\n ],\n optionalServices: [\n // \"00001530-1212-efde-1523-785feabcd123\",\n // \"0000aaaa-0000-1000-8000-00805f9b34fb\",\n UUIDs.cubeService,\n // \"0000180f-0000-1000-8000-00805f9b34fb\",\n // \"0000180a-0000-1000-8000-00805f9b34fb\"\n ],\n};\n", "import { Quaternion } from \"three\";\nimport { Alg, experimentalAppendMove, Move } from \"../../alg\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\n\nconst UUIDs = {\n goCubeService: \"6e400001-b5a3-f393-e0a9-e50e24dcca9e\",\n goCubeStateCharacteristic: \"6e400003-b5a3-f393-e0a9-e50e24dcca9e\",\n};\n\n// https://stackoverflow.com/a/40031979\nfunction buf2hex(buffer: ArrayBuffer): string {\n // buffer is an ArrayBuffer\n return (\n Array.prototype.map.call(new Uint8Array(buffer), (x: number) =>\n (\"00\" + x.toString(16)).slice(-2),\n ) as string[]\n ).join(\" \");\n}\n\nfunction bufferToString(buffer: ArrayBuffer): string {\n const byteView = new Uint8Array(buffer);\n let str = \"\";\n for (const charCode of byteView) {\n str += String.fromCharCode(charCode);\n }\n return str;\n}\n\nconst moveMap: Move[] = [\n new Move(\"B\", 1),\n new Move(\"B\", -1),\n new Move(\"F\", 1),\n new Move(\"F\", -1),\n new Move(\"U\", 1),\n new Move(\"U\", -1),\n new Move(\"D\", 1),\n new Move(\"D\", -1),\n new Move(\"R\", 1),\n new Move(\"R\", -1),\n new Move(\"L\", 1),\n new Move(\"L\", -1),\n];\n\nexport class GoCube extends BluetoothPuzzle {\n // We have to perform async operations before we call the constructor.\n public static async connect(\n server: BluetoothRemoteGATTServer,\n ): Promise<GoCube> {\n const service = await server.getPrimaryService(UUIDs.goCubeService);\n debugLog({ service });\n const goCubeStateCharacteristic = await service.getCharacteristic(\n UUIDs.goCubeStateCharacteristic,\n );\n debugLog({ goCubeStateCharacteristic });\n\n const cube = new GoCube(server, goCubeStateCharacteristic);\n\n await goCubeStateCharacteristic.startNotifications();\n goCubeStateCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n cube.onCubeCharacteristicChanged.bind(cube),\n );\n\n return cube;\n }\n\n // public async getState(): Promise<PuzzleState> {\n // return new Promise((resolve, reject) => {\n // this.resolve = (value: any) => {\n // resolve(buf2hex(value.buffer) as any);\n // };\n // this.goCubeStateCharacteristic.startNotifications();\n // });\n // }\n\n private recorded: any[][] = [];\n\n private homeQuatInverse: Quaternion | null = null;\n private lastRawQuat: Quaternion = new Quaternion(0, 0, 0, 1);\n private currentQuat: Quaternion = new Quaternion(0, 0, 0, 1);\n private lastTarget: Quaternion = new Quaternion(0, 0, 0, 1);\n private alg: Alg = new Alg();\n\n private constructor(\n private server: BluetoothRemoteGATTServer,\n public goCubeStateCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n public reset(): void {\n this.resetAlg();\n this.resetOrientation();\n }\n\n public resetAlg(alg?: Alg): void {\n this.alg = alg || new Alg();\n }\n\n public resetOrientation(): void {\n this.homeQuatInverse = this.lastRawQuat.clone().inverse();\n this.currentQuat = new Quaternion(0, 0, 0, 1);\n this.lastTarget = new Quaternion(0, 0, 0, 1);\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n private onCubeCharacteristicChanged(event: any): void {\n const buffer: DataView = event.target.value;\n this.recorded.push([event.timeStamp, buf2hex(buffer.buffer)]);\n // TODO: read bytes from buffer instead of guessing meaning based on length.\n if (buffer.byteLength < 16) {\n for (let i = 3; i < buffer.byteLength - 4; i += 2) {\n const move = moveMap[buffer.getUint8(i)];\n this.alg = experimentalAppendMove(this.alg, move);\n this.dispatchMove({\n latestMove: moveMap[buffer.getUint8(i)],\n timeStamp: event.timeStamp,\n debug: {\n stateStr: buf2hex(buffer.buffer),\n },\n });\n }\n } else {\n const coords = bufferToString(\n buffer.buffer.slice(3, buffer.byteLength - 3),\n )\n .split(\"#\")\n .map((s) => parseInt(s, 10) / 16384);\n const quat = new Quaternion(coords[0], coords[1], coords[2], coords[3]);\n\n this.lastRawQuat = quat.clone();\n\n if (!this.homeQuatInverse) {\n this.homeQuatInverse = quat.clone().inverse();\n }\n\n const targetQuat = quat.clone().multiply(this.homeQuatInverse.clone());\n targetQuat.y = -targetQuat.y; // GoCube axis fix.\n\n this.lastTarget.slerp(targetQuat, 0.5);\n this.currentQuat.rotateTowards(this.lastTarget, rotateTowardsRate);\n\n this.dispatchOrientation({\n quaternion: this.currentQuat,\n timeStamp: event.timeStamp,\n });\n }\n }\n}\n\nconst rotateTowardsRate = 0.5;\n\n// TODO: Move this into a factory?\nexport const goCubeConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: GoCube.connect.bind(GoCube),\n prefixes: [\"GoCube\", \"Rubik\"],\n filters: [{ namePrefix: \"GoCube\" }, { namePrefix: \"Rubik\" }],\n optionalServices: [UUIDs.goCubeService],\n};\n", "export function flipBitOrder(v: number, numBits: number): number {\n let result = 0;\n for (let i = 0; i < numBits; i++) {\n const shiftLeft = numBits - 1 - 2 * i;\n const unShiftedBit = v & (0b1 << i);\n // console.log(\n // unShiftedBit,\n // shiftLeft,\n // shiftLeft < 0 ? unShiftedBit >> -shiftLeft : unShiftedBit << shiftLeft,\n // );\n result +=\n shiftLeft < 0 ? unShiftedBit >> -shiftLeft : unShiftedBit << shiftLeft;\n }\n return result;\n}\n", "/* tslint:disable no-bitwise */\n\nimport { Move } from \"../../alg\";\nimport type { KPuzzle } from \"../../kpuzzle\";\nimport type { KState } from \"../../kpuzzle/KState\";\nimport {\n experimentalBinaryComponentsToReid3x3x3,\n experimentalTwizzleBinaryToBinaryComponents,\n} from \"../../protocol\";\nimport { puzzles } from \"../../puzzles\";\nimport { debugLog } from \"../debug\";\nimport { BluetoothConfig, BluetoothPuzzle } from \"./bluetooth-puzzle\";\nimport { flipBitOrder } from \"./endianness\";\n\n// TODO: Short IDs\nconst UUIDs = {\n heykubeService: \"b46a791a-8273-4fc1-9e67-94d3dc2aac1c\",\n stateCharacteristic: \"a2f41a4e-0e31-4bbc-9389-4253475481fb\",\n batteryCharacteristic: \"fd51b3ba-99c7-49c6-9f85-5644ff56a378\",\n};\n\nexport class HeykubeCube extends BluetoothPuzzle {\n // We have to perform async operations before we call the constructor.\n public static async connect(\n server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n ): Promise<HeykubeCube> {\n const service = await server.getPrimaryService(UUIDs.heykubeService);\n debugLog(\"Service:\", service);\n\n const stateCharacteristic = await service.getCharacteristic(\n UUIDs.stateCharacteristic,\n );\n debugLog(\"Characteristic:\", stateCharacteristic);\n\n const cube = new HeykubeCube(\n await puzzles[\"3x3x3\"].kpuzzle(),\n service,\n device,\n server,\n stateCharacteristic,\n );\n return cube;\n }\n\n private constructor(\n _kpuzzle: KPuzzle,\n _service: BluetoothRemoteGATTService,\n device: BluetoothDevice,\n private server: BluetoothRemoteGATTServer,\n private stateCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n\n device.addEventListener(\n \"gattserverdisconnected\",\n this.onDisconnect.bind(this),\n );\n\n this.stateCharacteristic.startNotifications();\n this.startTrackingMoves();\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n onDisconnect(): void {\n this.dispatchEvent(new CustomEvent(\"disconnect\"));\n }\n\n public startTrackingMoves(): void {\n this.stateCharacteristic.addEventListener(\n \"characteristicvaluechanged\",\n (e: any) => this.onStateCharacteristic(e),\n ); // TODO\n }\n\n // public stopTrackingMoves(): void {}\n\n // public async getBattery(): Promise<number> {\n // return new Uint8Array(\n // await this.readActualAngleAndBatteryCharacteristic(),\n // )[7];\n // }srcElement: BluetoothRemoteGATTCharacteristic\n\n private onStateCharacteristic(event: {\n target: BluetoothRemoteGATTCharacteristic;\n timeStamp: number;\n }): void {\n const state = this.decodeState(event.target.value!);\n // console.log(event, state.latestMove.toString(), state);\n this.dispatchMove({\n latestMove: state.latestMove,\n timeStamp: event.timeStamp,\n state: state.state,\n });\n }\n\n private decodeState(dv: DataView): { state: KState; latestMove: Move } {\n const moves = [\n new Move(\"U\"),\n new Move(\"U'\"),\n new Move(\"B\"),\n new Move(\"B'\"),\n new Move(\"F\"),\n new Move(\"F'\"),\n null,\n null,\n new Move(\"L\"),\n new Move(\"L'\"),\n new Move(\"D\"),\n new Move(\"D'\"),\n new Move(\"R\"),\n new Move(\"R'\"),\n // null,\n // null,\n ];\n\n const b2 = new Uint8Array(dv.byteLength);\n for (let i = 0; i < dv.byteLength; i++) {\n b2[i] = flipBitOrder(dv.getUint8(i), 8);\n }\n const components1 = experimentalTwizzleBinaryToBinaryComponents(\n b2.slice(0, 11),\n );\n // console.log(\"sliced\", dv.byteLength, bufferToSpacedHex(b2.slice(11)));\n const components2 = {\n epLex: flipBitOrder(components1.epLex, 29),\n eoMask: flipBitOrder(components1.eoMask, 12),\n cpLex: flipBitOrder(components1.cpLex, 16),\n coMask: flipBitOrder(components1.coMask, 13),\n poIdxL: 0,\n poIdxU: 0b111,\n moSupport: 0b1, // TODO\n moMask: 0,\n };\n // console.log(components2, binaryComponentsToReid3x3x3(components2));\n\n return {\n state: experimentalBinaryComponentsToReid3x3x3(components2),\n latestMove: moves[b2[20] & 0b00001111]!,\n };\n }\n\n public async getState(): Promise<KState> {\n const b1 = await this.stateCharacteristic.readValue();\n return this.decodeState(b1).state;\n }\n}\n\n// // TODO: Move this into a factory?\nexport const heykubeConfig: BluetoothConfig<BluetoothPuzzle> = {\n connect: HeykubeCube.connect.bind(HeykubeCube),\n prefixes: [\"HEYKUBE\"],\n filters: [{ namePrefix: \"HEYKUBE\" }],\n optionalServices: [UUIDs.heykubeService],\n};\n", "import { bluetoothConnect, BluetoothConnectOptions } from \"../connect\";\nimport type { BluetoothPuzzle } from \"./bluetooth-puzzle\";\nimport { ganConfig } from \"./gan\";\nimport { giiKERConfig } from \"./giiker\";\nimport { goCubeConfig } from \"./gocube\";\nimport { heykubeConfig } from \"./Heykube\";\n\nconst smartPuzzleConfigs = [\n ganConfig,\n goCubeConfig,\n heykubeConfig,\n giiKERConfig, // GiiKER must be last, due to Xiaomi naming. TODO: enforce this using tests.\n];\n\nexport async function connectSmartPuzzle(\n options?: BluetoothConnectOptions,\n): Promise<BluetoothPuzzle> {\n return bluetoothConnect<BluetoothPuzzle>(smartPuzzleConfigs, options);\n}\n", "import { Alg, Move } from \"../../alg\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\n\n// TODO: Remove this. It's only used for debugging.\nfunction buf2hex(buffer: ArrayBuffer): string {\n // buffer is an ArrayBuffer\n return (\n Array.prototype.map.call(new Uint8Array(buffer), (x: number) =>\n (\"00\" + x.toString(16)).slice(-2),\n ) as string[]\n ).join(\" \");\n}\n\nconst MAX_NIBBLES_PER_WRITE = 18 * 2;\nconst QUANTUM_TURN_DURATION_MS = 150;\nconst DOUBLE_TURN_DURATION_MS = 250;\n\nconst U_D_SWAP = new Alg(\"F B R2 L2 B' F'\");\nconst U_D_UNSWAP = U_D_SWAP.invert(); // TODO: make `cubing.js` clever enough to be able to reuse the regular swap.\nconst F_B_SWAP = new Alg(\"U D R2 L2 D' U'\");\nconst F_B_UNSWAP = F_B_SWAP.invert();\n\n// TODO: Short IDs\nconst UUIDs = {\n ganRobotService: \"0000fff0-0000-1000-8000-00805f9b34fb\",\n statusCharacteristic: \"0000fff2-0000-1000-8000-00805f9b34fb\",\n moveCharacteristic: \"0000fff3-0000-1000-8000-00805f9b34fb\",\n};\n\nconst moveMap: Record<string, number> = {\n \"R\": 0,\n \"R2\": 1,\n \"R2'\": 1,\n \"R'\": 2,\n \"F\": 3,\n \"F2\": 4,\n \"F2'\": 4,\n \"F'\": 5,\n \"D\": 6,\n \"D2\": 7,\n \"D2'\": 7,\n \"D'\": 8,\n \"L\": 9,\n \"L2\": 10,\n \"L2'\": 10,\n \"L'\": 11,\n \"B\": 12,\n \"B2\": 13,\n \"B2'\": 13,\n \"B'\": 14,\n};\n\nconst moveMapX: Record<string, number> = {\n \"R\": 0,\n \"R2\": 1,\n \"R2'\": 1,\n \"R'\": 2,\n \"U\": 3,\n \"U2\": 4,\n \"U2'\": 4,\n \"U'\": 5,\n \"F\": 6,\n \"F2\": 7,\n \"F2'\": 7,\n \"F'\": 8,\n \"L\": 9,\n \"L2\": 10,\n \"L2'\": 10,\n \"L'\": 11,\n \"D\": 12,\n \"D2\": 13,\n \"D2'\": 13,\n \"D'\": 14,\n};\n\nfunction isDoubleTurnNibble(nibble: number): boolean {\n return nibble % 3 === 1;\n}\n\nfunction nibbleDuration(nibble: number): number {\n return isDoubleTurnNibble(nibble)\n ? DOUBLE_TURN_DURATION_MS\n : QUANTUM_TURN_DURATION_MS;\n}\n\nfunction throwInvalidMove(move: Move) {\n console.error(\"invalid move\", move, move.toString());\n throw new Error(\"invalid move!\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface GanRobotStatus {\n movesRemaining: number;\n}\n\ninterface GanRobotOptions {\n xAngle: boolean;\n singleMoveFixHack: boolean;\n bufferQueue: number;\n postSleep: number;\n}\n\nexport class GanRobot extends EventTarget {\n experimentalDebugOnSend: ((alg: Alg) => void) | null = null;\n experimentalDebugLog: typeof console.log = () => {};\n\n // Because our Bluetooth connection code is set up not to know what kind of device is connecting, we put these options directly on the class.\n experimentalOptions: GanRobotOptions = {\n xAngle: false,\n singleMoveFixHack: false,\n bufferQueue: 0,\n postSleep: 0,\n };\n\n constructor(\n _service: BluetoothRemoteGATTService,\n private server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n private statusCharacteristic: BluetoothRemoteGATTCharacteristic,\n private moveCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n device.addEventListener(\n \"gattserverdisconnected\",\n this.onDisconnect.bind(this),\n );\n }\n\n // We have to perform async operations before we call the constructor.\n static async connect(\n server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n ) {\n const ganTimerService = await server.getPrimaryService(\n UUIDs.ganRobotService,\n );\n const statusCharacteristic = await ganTimerService.getCharacteristic(\n UUIDs.statusCharacteristic,\n );\n const moveCharacteristic = await ganTimerService.getCharacteristic(\n UUIDs.moveCharacteristic,\n );\n const timer = new GanRobot(\n ganTimerService,\n server,\n device,\n statusCharacteristic,\n moveCharacteristic,\n );\n return timer;\n }\n\n public name(): string | undefined {\n return this.server.device.name;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n onDisconnect(): void {\n this.dispatchEvent(new CustomEvent(\"disconnect\"));\n }\n\n private moveToNibble(move: Move): number {\n const nibble =\n (this.experimentalOptions.xAngle ? moveMapX : moveMap)[move.toString()] ??\n null;\n if (nibble === null) {\n throwInvalidMove(move);\n }\n return nibble;\n }\n\n private async writeNibbles(nibbles: number[]): Promise<void> {\n if (nibbles.length > MAX_NIBBLES_PER_WRITE) {\n throw new Error(\n `Can only write ${MAX_NIBBLES_PER_WRITE} nibbles at a time!`,\n );\n }\n // const byteLength = Math.ceil(nibbles.length / 2);\n const bytes = new Uint8Array(18);\n let i: number;\n for (i = 0; i < nibbles.length; i++) {\n const byteIdx = Math.floor(i / 2);\n bytes[byteIdx] += nibbles[i];\n if (i % 2 === 0) {\n bytes[byteIdx] *= 0x10;\n }\n }\n if (nibbles.length % 2 === 1) {\n bytes[Math.ceil(nibbles.length / 2) - 1] += 0xf;\n }\n for (let i = Math.ceil(nibbles.length / 2); i < 18; i++) {\n bytes[i] = 0xff;\n }\n let sleepDuration = 0;\n for (const nibble of nibbles) {\n sleepDuration += nibbleDuration(nibble);\n }\n this.experimentalDebugLog(\"WRITING:\", buf2hex(bytes));\n await this.moveCharacteristic.writeValue(bytes);\n await sleep(sleepDuration * 0.75);\n while ((await this.getStatus()).movesRemaining > 0) {\n // repeat\n }\n await sleep(this.experimentalOptions.postSleep);\n }\n\n private async getStatus(): Promise<GanRobotStatus> {\n const statusBytes = new Uint8Array(\n (await this.statusCharacteristic.readValue()).buffer,\n );\n this.experimentalDebugLog(\"moves remaining:\", statusBytes[0]);\n return {\n movesRemaining: statusBytes[0],\n };\n }\n\n locked: boolean = false;\n processQueue(): void {}\n\n private moveQueue: Alg = new Alg();\n // TODO: Don't let this resolve until the move is done?\n private async queueMoves(moves: Alg): Promise<void> {\n this.moveQueue = this.moveQueue\n .concat(moves)\n .simplify({ collapseMoves: true, quantumMoveOrder: (_) => 4 });\n if (!this.locked) {\n // TODO: We're currently iterating over units instead of leaves to avoid \"zip bomps\".\n try {\n this.locked = true;\n if (this.moveQueue.experimentalNumUnits() === 1) {\n await sleep(this.experimentalOptions.bufferQueue);\n }\n // await this.writeNibbles([0xf, 0xf]);\n while (this.moveQueue.experimentalNumUnits() > 0) {\n let units = Array.from(this.moveQueue.units());\n if (\n this.experimentalOptions.singleMoveFixHack &&\n units.length === 1\n ) {\n const move = units[0] as Move;\n if (move.amount === 2) {\n units = [\n move.modified({ amount: 1 }),\n move.modified({ amount: 1 }),\n ];\n } else {\n units = [\n move.modified({ amount: -move.amount }),\n move.modified({ amount: 2 }),\n ];\n }\n }\n const moves = units.splice(0, MAX_NIBBLES_PER_WRITE);\n const nibbles: number[] = moves.map(this.moveToNibble.bind(this));\n const sending = new Alg(moves);\n this.experimentalDebugLog(\"SENDING\", sending.toString());\n if (this.experimentalDebugOnSend) {\n this.experimentalDebugOnSend(sending);\n }\n const write = this.writeNibbles(nibbles);\n this.moveQueue = new Alg(units);\n await write;\n }\n } finally {\n this.locked = false;\n }\n }\n }\n\n async applyMoves(moves: Iterable<Move>): Promise<void> {\n // const nibbles: number[] = [];\n for (const move of moves) {\n const str = move.toString();\n if (str in (this.experimentalOptions.xAngle ? moveMapX : moveMap)) {\n await this.queueMoves(new Alg([move]));\n } else if (\n move.family === (this.experimentalOptions.xAngle ? \"B\" : \"U\")\n ) {\n // We purposely send just the swap, so that U2 will get coalesced\n await Promise.all([\n this.queueMoves(\n this.experimentalOptions.xAngle ? F_B_SWAP : U_D_SWAP,\n ),\n this.queueMoves(\n new Alg([\n move.modified({\n family: this.experimentalOptions.xAngle ? \"F\" : \"D\",\n }),\n ]).concat(\n this.experimentalOptions.xAngle ? F_B_UNSWAP : U_D_UNSWAP,\n ),\n ),\n ]);\n }\n }\n }\n}\n\n// // TODO: Move this into a factory?\nexport const ganTimerConfig: BluetoothConfig<GanRobot> = {\n connect: GanRobot.connect.bind(GanRobot),\n prefixes: [\"GAN\"],\n filters: [{ namePrefix: \"GAN\" }],\n optionalServices: [UUIDs.ganRobotService],\n};\n", "import { bluetoothConnect, BluetoothConnectOptions } from \"../connect\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\nimport { GanRobot, ganTimerConfig } from \"./GanRobot\";\n\nexport type BluetoothRobot = GanRobot; // TODO\n\nconst smartRobotConfigs: BluetoothConfig<BluetoothRobot>[] = [ganTimerConfig];\n\nexport async function connectSmartRobot(\n options?: BluetoothConnectOptions,\n): Promise<BluetoothRobot> {\n return bluetoothConnect<BluetoothRobot>(smartRobotConfigs, options);\n}\n", "import type { MillisecondTimestamp } from \"../../twisty/controllers/AnimationTypes\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\n\n// TODO: Short IDs\nconst UUIDs = {\n ganTimerService: \"0000fff0-0000-1000-8000-00805f9b34fb\",\n timeCharacteristic: \"0000fff2-0000-1000-8000-00805f9b34fb\",\n};\n\ninterface GanTimerDetail {\n currentTime: MillisecondTimestamp;\n latestTimes: [\n MillisecondTimestamp,\n MillisecondTimestamp,\n MillisecondTimestamp,\n ];\n}\n\nexport class GanTimer extends EventTarget {\n private polling = false;\n private previousDetail: GanTimerDetail | null = null;\n\n constructor(\n _service: BluetoothRemoteGATTService,\n private server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n private timeCharacteristic: BluetoothRemoteGATTCharacteristic,\n ) {\n super();\n this.startPolling();\n console.log(server);\n device.addEventListener(\n \"gattserverdisconnected\",\n this.onDisconnect.bind(this),\n );\n }\n\n // We have to perform async operations before we call the constructor.\n static async connect(\n server: BluetoothRemoteGATTServer,\n device: BluetoothDevice,\n ) {\n const ganTimerService = await server.getPrimaryService(\n UUIDs.ganTimerService,\n );\n console.log(\"Service:\", ganTimerService);\n const timeCharacteristic = await ganTimerService.getCharacteristic(\n UUIDs.timeCharacteristic,\n );\n console.log(\"Characteristic:\", timeCharacteristic);\n const timer = new GanTimer(\n ganTimerService,\n server,\n device,\n timeCharacteristic,\n );\n return timer;\n }\n\n disconnect(): void {\n this.server.disconnect();\n }\n\n async poll() {\n if (!this.polling) {\n return;\n }\n const value = await this.getTimeCharacteristic();\n\n const detail: GanTimerDetail = {\n currentTime: this.decodeTimeMs(value.slice(0, 4)),\n latestTimes: [\n this.decodeTimeMs(value.slice(4, 8)),\n this.decodeTimeMs(value.slice(8, 12)),\n this.decodeTimeMs(value.slice(12, 16)),\n ],\n };\n\n if (detail.currentTime === 0) {\n if (this.previousDetail && this.previousDetail.currentTime !== 0) {\n this.dispatchEvent(new CustomEvent(\"reset\"));\n }\n }\n\n if (detail.currentTime !== 0 && this.previousDetail) {\n if (this.previousDetail.currentTime === 0) {\n this.dispatchEvent(new CustomEvent(\"start\"));\n }\n\n if (detail.currentTime !== this.previousDetail.currentTime) {\n this.dispatchEvent(new CustomEvent(\"update\", { detail }));\n\n if (\n detail.currentTime === detail.latestTimes[0] &&\n detail.latestTimes[1] === this.previousDetail.latestTimes[0] &&\n detail.latestTimes[2] === this.previousDetail.latestTimes[1]\n ) {\n this.dispatchEvent(new CustomEvent(\"stop\", { detail }));\n }\n }\n }\n\n this.previousDetail = detail;\n\n this.poll();\n }\n\n onDisconnect(): void {\n this.dispatchEvent(new CustomEvent(\"disconnect\"));\n }\n\n async getTimeCharacteristic() {\n return new Uint8Array((await this.timeCharacteristic.readValue()).buffer);\n }\n\n async getTime() {\n const value = await this.getTimeCharacteristic();\n return this.decodeTimeMs(value.slice(0, 4));\n }\n\n decodeTimeMs(bytes: Uint8Array) {\n return (bytes[0] * 60 + bytes[1]) * 1000 + bytes[2] + bytes[3] * 256;\n }\n\n startPolling() {\n this.polling = true;\n this.poll();\n }\n\n stopPolling() {\n this.polling = false;\n }\n}\n\n// // TODO: Move this into a factory?\nexport const ganTimerConfig: BluetoothConfig<GanTimer> = {\n connect: GanTimer.connect.bind(GanTimer),\n prefixes: [\"GAN\"],\n filters: [{ namePrefix: \"GAN\" }],\n optionalServices: [UUIDs.ganTimerService],\n};\n", "import { bluetoothConnect, BluetoothConnectOptions } from \"../connect\";\nimport type { BluetoothConfig } from \"../smart-puzzle/bluetooth-puzzle\";\nimport { GanTimer, ganTimerConfig } from \"./GanTimer\";\n\nexport type BluetoothTimer = GanTimer; // TODO\n\nconst smartTimerConfigs: BluetoothConfig<BluetoothTimer>[] = [ganTimerConfig];\n\nexport async function connectSmartTimer(\n options?: BluetoothConnectOptions,\n): Promise<BluetoothTimer> {\n return bluetoothConnect<BluetoothTimer>(smartTimerConfigs, options);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-GBMX6FHY.js";
|
|
10
10
|
import {
|
|
11
11
|
Alg
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FCB447RN.js";
|
|
13
13
|
|
|
14
14
|
// src/cubing/search/inside/solve/puzzles/clock.ts
|
|
15
15
|
var pins = ["UR", "DR", "DL", "UL"];
|
|
@@ -78,7 +78,7 @@ async function randomMegaminxScrambleString() {
|
|
|
78
78
|
|
|
79
79
|
// src/cubing/vendor/comlink-everywhere/outside/index.ts
|
|
80
80
|
import { wrap } from "comlink";
|
|
81
|
-
var worker_threads_mangled = "w-orker-_threa-ds";
|
|
81
|
+
var worker_threads_mangled = "node:w-orker-_threa-ds";
|
|
82
82
|
var worker_threads_unmangled = () => worker_threads_mangled.replace(/-/g, "");
|
|
83
83
|
var useNodeWorkarounds = typeof globalThis.Worker === "undefined" && typeof globalThis.WorkerNavigator === "undefined";
|
|
84
84
|
async function nodeWorker(source, options) {
|
|
@@ -111,7 +111,7 @@ async function constructWorker(source, options) {
|
|
|
111
111
|
// src/cubing/search/inside/search-worker-ts-entry-path-getter.ts
|
|
112
112
|
exposeAPI.expose = false;
|
|
113
113
|
async function getWorkerEntryFileURL() {
|
|
114
|
-
return (await import("./search-worker-ts-entry-
|
|
114
|
+
return (await import("./search-worker-ts-entry-AFMPRPSV.js")).WORKER_ENTRY_FILE_URL;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// src/cubing/search/instantiator.ts
|
|
@@ -172,7 +172,7 @@ async function instantiateModuleWorker() {
|
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
174
|
async function instantiateClassicWorker() {
|
|
175
|
-
const { workerSource } = await import("./search-worker-inside-generated-string-
|
|
175
|
+
const { workerSource } = await import("./search-worker-inside-generated-string-AVMDARJP.js");
|
|
176
176
|
const worker = await constructWorker(workerSource, { eval: true });
|
|
177
177
|
return wrap(worker);
|
|
178
178
|
}
|
|
@@ -251,4 +251,4 @@ export {
|
|
|
251
251
|
solveMegaminx,
|
|
252
252
|
setDebug
|
|
253
253
|
};
|
|
254
|
-
//# sourceMappingURL=chunk-
|
|
254
|
+
//# sourceMappingURL=chunk-7K6HJKEG.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/cubing/search/inside/solve/puzzles/clock.ts", "../../src/cubing/search/inside/solve/puzzles/wca-minx.ts", "../../src/cubing/vendor/comlink-everywhere/outside/index.ts", "../../src/cubing/search/inside/search-worker-ts-entry-path-getter.ts", "../../src/cubing/search/instantiator.ts", "../../src/cubing/search/outside.ts"],
|
|
4
|
+
"sourcesContent": ["import { randomUIntBelowFactory } from \"../../../../vendor/random-uint-below\";\n\nconst pins = [\"UR\", \"DR\", \"DL\", \"UL\"];\nconst backMoves = [\"U\", \"R\", \"D\", \"L\", \"ALL\"];\nconst frontMoves = pins.concat(backMoves);\n\nconst randomUIntBelowPromise = randomUIntBelowFactory();\n\nexport async function randomClockScrambleString(): Promise<string> {\n const randomUIntBelow = await randomUIntBelowPromise;\n\n let filteringMoveCount = 0;\n\n async function randomSuffix(randomUIntBelow: (max: number) => number) {\n const amount = randomUIntBelow(12);\n if (amount !== 0) {\n filteringMoveCount++;\n }\n if (amount <= 6) {\n return `${amount}+`;\n } else {\n return `${12 - amount}-`;\n }\n }\n\n const moves = [];\n async function side(families: string[]): Promise<void> {\n for (const family of families) {\n moves.push(`${family}${await randomSuffix(randomUIntBelow)}`);\n }\n }\n\n await side(frontMoves);\n moves.push(\"y2\");\n await side(backMoves);\n\n // https://www.worldcubeassociation.org/regulations/#4b3\n if (filteringMoveCount < 2) {\n return randomClockScrambleString();\n }\n\n for (const pin of pins) {\n if (randomUIntBelow(2) === 0) {\n moves.push(pin);\n }\n }\n return moves.join(\" \");\n}\n", "import { randomUIntBelowFactory } from \"../../../../vendor/random-uint-below\";\n\nconst randomUIntBelowPromise = randomUIntBelowFactory();\n\nconst suffixes = [\"++\", \"--\"];\n\nexport async function randomMegaminxScrambleString(): Promise<string> {\n const randomUIntBelow = await randomUIntBelowPromise;\n\n function rdPair(): string {\n return `R${suffixes[randomUIntBelow(2)]} D${suffixes[randomUIntBelow(2)]}`;\n }\n\n function randomU(): string {\n return `U${[\"\", \"'\"][randomUIntBelow(2)]}`;\n }\n\n function row(): string {\n const chunks = [];\n for (let i = 0; i < 5; i++) {\n chunks.push(rdPair());\n }\n chunks.push(randomU());\n return chunks.join(\" \");\n }\n\n const chunks = [];\n for (let i = 0; i < 6; i++) {\n chunks.push(row());\n }\n return chunks.join(\"\\n\");\n}\n", "import nodeEndpoint from \"../node-adapter\";\n\nexport { wrap } from \"comlink\";\n// Mangled so that bundlers don't try to inline the source.\n\nconst worker_threads_mangled = \"node:w-orker-_threa-ds\";\nconst worker_threads_unmangled = () => worker_threads_mangled.replace(/-/g, \"\");\n\nconst useNodeWorkarounds =\n typeof globalThis.Worker === \"undefined\" &&\n typeof (globalThis as any).WorkerNavigator === \"undefined\";\n\nasync function nodeWorker(\n source: string | URL,\n options?: { eval?: boolean },\n): Promise<Worker> {\n const { Worker: NodeWorker } = await import(\n /* @vite-ignore */ worker_threads_unmangled()\n );\n const worker = new NodeWorker(source, options);\n worker.unref();\n return nodeEndpoint(worker);\n}\n\nexport async function constructWorker(\n source: string | URL,\n options?: { eval?: boolean; type?: WorkerType },\n): Promise<Worker> {\n let worker;\n if (useNodeWorkarounds) {\n return nodeWorker(source, { eval: options?.eval });\n } else {\n if (options?.eval) {\n const blob = new Blob([source as string], {\n type: \"application/javascript\",\n });\n source = URL.createObjectURL(blob);\n }\n worker = new globalThis.Worker(source, {\n type: options ? options.type : undefined, // TODO: Is it safe to use `options?.type`?\n });\n }\n return worker;\n}\n", "import { exposeAPI } from \"./worker-guard\";\n\nexposeAPI.expose = false;\nexport async function getWorkerEntryFileURL() {\n return (await import(\"./search-worker-ts-entry\")).WORKER_ENTRY_FILE_URL;\n}\n", "import { constructWorker, wrap } from \"../vendor/comlink-everywhere/outside\";\nimport type { WorkerInsideAPI } from \"./inside/api\";\nimport { getWorkerEntryFileURL } from \"./inside/search-worker-ts-entry-path-getter\";\n\nconst MODULE_WORKER_TIMEOUT_MILLISECONDS = 5000;\n\nlet forceStringWorker: boolean = false;\nexport function setForceStringWorker(force: boolean): void {\n forceStringWorker = force;\n}\n\nexport async function instantiateModuleWorker(): Promise<WorkerInsideAPI> {\n // eslint-disable-next-line no-async-promise-executor\n return new Promise<WorkerInsideAPI>(async (resolve, reject) => {\n const timeoutID = setTimeout(() => {\n reject(new Error(\"module instantiation timeout\"));\n }, MODULE_WORKER_TIMEOUT_MILLISECONDS);\n\n try {\n const workerEntryFileURL = await getWorkerEntryFileURL();\n if (!workerEntryFileURL) {\n // This happens in `bundle-global`.\n reject(new Error(\"Could not get worker entry file URL.\"));\n }\n let url: string | URL;\n if (globalThis.Blob) {\n // Standard browser-like environment.\n const importSrc = `import \"${workerEntryFileURL}\";`;\n const blob = new Blob([importSrc], {\n type: \"text/javascript\",\n });\n url = URL.createObjectURL(blob);\n } else {\n // `node` doesn't have `Blob`. We can keep the original entry file URL there, but we have to wrap it.\n // Needed for `node`\n url = new URL(workerEntryFileURL);\n }\n\n const worker = (await constructWorker(url, {\n type: \"module\",\n })) as Worker & {\n nodeWorker?: import(\"worker_threads\").Worker;\n };\n\n const onError = (e: ErrorEvent) => {\n // TODO: Remove fallback when Firefox implements module workers: https://bugzilla.mozilla.org/show_bug.cgi?id=1247687\n if (e.message?.startsWith(\"SyntaxError\")) {\n reject(e);\n }\n };\n\n const onFirstMessage = (messageData: string) => {\n if (messageData === \"comlink-exposed\") {\n // We need to clear the timeout so that we don't prevent `node` from exiting in the meantime.\n clearTimeout(timeoutID);\n resolve(wrap<WorkerInsideAPI>(worker));\n } else {\n reject(\n new Error(\"wrong module instantiation message \" + messageData),\n );\n }\n };\n\n if (worker.nodeWorker) {\n // We have to use `once` so the `unref()` from `comlink-everywhere` allows the process to quite as expected.\n worker.nodeWorker.once(\"message\", onFirstMessage);\n } else {\n worker.addEventListener(\"error\", onError, {\n once: true,\n });\n worker.addEventListener(\"message\", (e) => onFirstMessage(e.data), {\n once: true,\n });\n }\n } catch (e) {\n reject(e);\n }\n });\n}\n\nasync function instantiateClassicWorker(): Promise<WorkerInsideAPI> {\n const { workerSource } = await import(\n \"./search-worker-inside-generated-string.js\"\n );\n const worker = await constructWorker(workerSource, { eval: true });\n return wrap(worker);\n}\n\nexport async function instantiateWorker(): Promise<WorkerInsideAPI> {\n if (forceStringWorker) {\n console.warn(\n \"Using the `forceStringWorker` workaround for search worker instantiation. This will require downloading significantly more code than necessary, but the functionality will be the same.\",\n );\n return instantiateClassicWorker();\n }\n try {\n // `await` is important for `catch` to work.\n return await instantiateModuleWorker();\n } catch (e) {\n console.warn(\n \"Could not instantiate module worker (this may happen in Firefox, with `bundle-global`, or when using Parcel). Falling back to string worker.\",\n e,\n );\n return instantiateClassicWorker();\n }\n}\n", "import { Alg } from \"../alg\";\n// import { preInitialize222 } from \"../implementations/2x2x2\";\nimport { randomClockScrambleString } from \"./inside/solve/puzzles/clock\"; // TODO: don't reach into `inside` code.\nimport { randomMegaminxScrambleString } from \"./inside/solve/puzzles/wca-minx\"; // TODO: don't reach into `inside` code.\nimport { instantiateWorker, setForceStringWorker } from \"./instantiator\";\nimport type { PrefetchLevel, WorkerInsideAPI } from \"./inside/api\";\nimport type { KState } from \"../kpuzzle/KState\";\n\nlet cachedWorkerInstance: Promise<WorkerInsideAPI> | null = null;\nasync function getCachedWorkerInstance(): Promise<WorkerInsideAPI> {\n return await (cachedWorkerInstance ??= instantiateWorker());\n}\n\n// Pre-initialize the scrambler for the given event. (Otherwise, an event is\n// initialized the first time you ask for a scramble for that event.)\n//\n// Some typical numbers for a fast computer:\n// - 3x3x3 initialization: 200ms\n// - Each 3x3x3 scramble: 50ms\n// - 4x4x4 initialization: 2500ms\n// - Each 4x4x4 scramble: 300ms to 800ms\n//\n// It is safe to immediately call for a scramble\n// any time after starting pre-initialization, or to call for them without\n// pre-initializing. Pre-initializing essentially gives the scramble worker a\n// head start in case a scramble doesn't get requested immediately.\n//\n// Note that events cannot be pre-initialized in parallel. Attempting to\n// pre-initialize multiple events will initialize them consecutively. Scrambles\n// for a given event cannot be computed while another event is being initialized.\nexport function _preInitializationHintForEvent(\n eventID: string,\n // callback?: () => void\n): void {\n switch (eventID) {\n case \"clock\":\n case \"minx\":\n return;\n case \"333oh\":\n return _preInitializationHintForEvent(\"333\");\n }\n (async () => {\n await (await getCachedWorkerInstance()).initialize(eventID);\n })();\n}\n\nexport async function randomScrambleForEvent(eventID: string): Promise<Alg> {\n switch (eventID) {\n case \"clock\":\n return Alg.fromString(await randomClockScrambleString());\n case \"minx\":\n return Alg.fromString(await randomMegaminxScrambleString());\n }\n const prom = _randomScrambleStringForEvent(eventID);\n const wat = await prom;\n return Alg.fromString(wat);\n}\n\nexport async function _randomScrambleStringForEvent(\n eventID: string,\n): Promise<string> {\n const cwi = await getCachedWorkerInstance();\n return cwi.randomScrambleStringForEvent(eventID);\n}\n\nexport async function randomScrambleStringForEvent(\n eventID: string,\n): Promise<string> {\n switch (eventID) {\n case \"clock\":\n return randomClockScrambleString();\n case \"minx\":\n return randomMegaminxScrambleString();\n }\n return await _randomScrambleStringForEvent(eventID);\n}\n\nexport async function experimentalSolve3x3x3IgnoringCenters(\n state: KState,\n): Promise<Alg> {\n const cwi = await getCachedWorkerInstance();\n return Alg.fromString(await cwi.solve333ToString(state.stateData));\n}\n\nexport async function experimentalSolve2x2x2(state: KState): Promise<Alg> {\n const cwi = await getCachedWorkerInstance();\n return Alg.fromString(await cwi.solve222ToString(state.stateData));\n}\n\nexport async function solveSkewb(state: KState): Promise<Alg> {\n const cwi = await getCachedWorkerInstance();\n return Alg.fromString(await cwi.solveSkewbToString(state.stateData));\n}\n\nexport async function solvePyraminx(state: KState): Promise<Alg> {\n const cwi = await getCachedWorkerInstance();\n return Alg.fromString(await cwi.solvePyraminxToString(state.stateData));\n}\n\nexport async function solveMegaminx(state: KState): Promise<Alg> {\n const cwi = await getCachedWorkerInstance();\n return Alg.fromString(await cwi.solveMegaminxToString(state.stateData));\n}\n\nexport function setDebug(options: {\n logPerf?: boolean;\n scramblePrefetchLevel?: `${PrefetchLevel}`;\n forceStringWorker?: boolean;\n}): void {\n const { logPerf, scramblePrefetchLevel } = options;\n if (typeof logPerf !== \"undefined\") {\n getCachedWorkerInstance().then((cwi) => cwi.setDebugMeasurePerf(logPerf));\n }\n if (typeof scramblePrefetchLevel !== \"undefined\") {\n getCachedWorkerInstance().then((cwi) =>\n cwi.setScramblePrefetchLevel(scramblePrefetchLevel as PrefetchLevel),\n );\n }\n if (\"forceStringWorker\" in options) {\n setForceStringWorker(!!options.forceStringWorker);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -385,7 +385,7 @@ var AlgParser = class {
|
|
|
385
385
|
algEndIdx = __privateGet(this, _idx);
|
|
386
386
|
continue mainLoop;
|
|
387
387
|
default:
|
|
388
|
-
throw "unexpected parsing error";
|
|
388
|
+
throw new Error("unexpected parsing error");
|
|
389
389
|
}
|
|
390
390
|
} else if (this.tryConsumeNext("\n")) {
|
|
391
391
|
algBuilder.push(addCharIndices(new Newline(), savedCharIndex, __privateGet(this, _idx)));
|
|
@@ -828,7 +828,7 @@ function assertIsUnit(t) {
|
|
|
828
828
|
if (t.is(Grouping) || t.is(Move) || t.is(Commutator) || t.is(Conjugate) || t.is(Pause) || t.is(Newline) || t.is(LineComment)) {
|
|
829
829
|
return t;
|
|
830
830
|
}
|
|
831
|
-
throw "internal error: expected unit";
|
|
831
|
+
throw new Error("internal error: expected unit");
|
|
832
832
|
}
|
|
833
833
|
var TraversalDownUp = class {
|
|
834
834
|
traverseUnit(unit, dataDown) {
|
|
@@ -967,7 +967,7 @@ function toIterable(input) {
|
|
|
967
967
|
if (typeof iter[Symbol.iterator] === "function") {
|
|
968
968
|
return iter;
|
|
969
969
|
}
|
|
970
|
-
throw "Invalid unit";
|
|
970
|
+
throw new Error("Invalid unit");
|
|
971
971
|
}
|
|
972
972
|
function experimentalEnsureAlg(alg) {
|
|
973
973
|
if (experimentalIs(alg, Alg)) {
|
|
@@ -1331,4 +1331,4 @@ export {
|
|
|
1331
1331
|
algCubingNetLink,
|
|
1332
1332
|
experimentalAppendMove
|
|
1333
1333
|
};
|
|
1334
|
-
//# sourceMappingURL=chunk-
|
|
1334
|
+
//# sourceMappingURL=chunk-FCB447RN.js.map
|