@cubingcenter/scrambler 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/dist/core/api.d.ts.map +1 -1
- package/dist/core/api.js +10 -2
- package/dist/puzzles/cube2/solver/browser-loader.d.ts +4 -7
- package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/browser-loader.js +42 -14
- package/dist/puzzles/cube2/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/generated-assets.js +8 -3
- package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/search.js +3 -3
- package/dist/puzzles/cube2/solver/tables.d.ts +6 -0
- package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/tables.js +16 -2
- package/dist/puzzles/cube3/index.d.ts +1 -0
- package/dist/puzzles/cube3/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/moves.d.ts.map +1 -1
- package/dist/puzzles/cube3/moves.js +104 -18
- package/dist/puzzles/cube3/scrambler.d.ts +16 -1
- package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube3/scrambler.js +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.js +48 -22
- package/dist/puzzles/cube3/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/generated-assets.js +9 -3
- package/dist/puzzles/cube3/solver/index.d.ts +5 -3
- package/dist/puzzles/cube3/solver/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/index.js +2 -1
- package/dist/puzzles/cube3/solver/node-loader.js +9 -2
- package/dist/puzzles/cube3/solver/phase1.d.ts +37 -0
- package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase1.js +156 -15
- package/dist/puzzles/cube3/solver/phase2.d.ts +75 -0
- package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase2.js +279 -68
- package/dist/puzzles/cube3/solver/search-utils.d.ts +1 -1
- package/dist/puzzles/cube3/solver/search-utils.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/symmetry.d.ts +24 -0
- package/dist/puzzles/cube3/solver/symmetry.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/symmetry.js +74 -0
- package/dist/puzzles/cube3/solver/tables.d.ts +6 -1
- package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/tables.js +14 -12
- package/dist/puzzles/cube3/validation.d.ts.map +1 -1
- package/dist/puzzles/cube3/validation.js +15 -7
- package/dist/puzzles/cube4/browser-worker-pool.d.ts +82 -0
- package/dist/puzzles/cube4/browser-worker-pool.d.ts.map +1 -0
- package/dist/puzzles/cube4/browser-worker-pool.js +205 -0
- package/dist/puzzles/cube4/browser-worker.d.ts +2 -0
- package/dist/puzzles/cube4/browser-worker.d.ts.map +1 -0
- package/dist/puzzles/cube4/browser-worker.js +31 -0
- package/dist/puzzles/cube4/index.d.ts +10 -2
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +6 -2
- package/dist/puzzles/cube4/moves.d.ts +5 -0
- package/dist/puzzles/cube4/moves.d.ts.map +1 -1
- package/dist/puzzles/cube4/moves.js +212 -11
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts +29 -1
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/browser-loader.js +227 -32
- package/dist/puzzles/cube4/reduction/center2.d.ts +44 -3
- package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/center2.js +152 -10
- package/dist/puzzles/cube4/reduction/edge3.d.ts +4 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/edge3.js +23 -3
- package/dist/puzzles/cube4/reduction/finish3.d.ts +53 -0
- package/dist/puzzles/cube4/reduction/finish3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/finish3.js +393 -0
- package/dist/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
- package/dist/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +44 -0
- package/dist/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +52 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.js +220 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts +15 -1
- package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/node-loader.js +199 -25
- package/dist/puzzles/cube4/reduction/pair-transversal.d.ts +28 -0
- package/dist/puzzles/cube4/reduction/pair-transversal.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/pair-transversal.js +107 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts +116 -7
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/phase3-search.js +458 -32
- package/dist/puzzles/cube4/reduction/rotation-fix.d.ts +28 -0
- package/dist/puzzles/cube4/reduction/rotation-fix.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/rotation-fix.js +212 -0
- package/dist/puzzles/cube4/reduction/solve.d.ts +172 -2
- package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/solve.js +1201 -180
- package/dist/puzzles/cube4/scramble-cache.d.ts +93 -0
- package/dist/puzzles/cube4/scramble-cache.d.ts.map +1 -0
- package/dist/puzzles/cube4/scramble-cache.js +150 -0
- package/dist/puzzles/cube4/scrambler.d.ts +201 -6
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +414 -176
- package/dist/puzzles/cube4/state.d.ts.map +1 -1
- package/dist/puzzles/cube4/state.js +4 -1
- package/dist/puzzles/cube4/worker-pool.d.ts +139 -0
- package/dist/puzzles/cube4/worker-pool.d.ts.map +1 -0
- package/dist/puzzles/cube4/worker-pool.js +405 -0
- package/dist/puzzles/cube4/worker-protocol.d.ts +58 -0
- package/dist/puzzles/cube4/worker-protocol.d.ts.map +1 -0
- package/dist/puzzles/cube4/worker-protocol.js +58 -0
- package/dist/puzzles/cube4/worker.d.ts +26 -0
- package/dist/puzzles/cube4/worker.d.ts.map +1 -0
- package/dist/puzzles/cube4/worker.js +49 -0
- package/dist/puzzles/pyraminx/solver/browser-loader.d.ts +4 -8
- package/dist/puzzles/pyraminx/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/browser-loader.js +44 -15
- package/dist/puzzles/pyraminx/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/generated-assets.js +8 -3
- package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/search.js +3 -6
- package/dist/puzzles/pyraminx/solver/tables.d.ts +6 -0
- package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/tables.js +17 -0
- package/dist/puzzles/shared/compressed-fetch.d.ts +37 -1
- package/dist/puzzles/shared/compressed-fetch.d.ts.map +1 -1
- package/dist/puzzles/shared/compressed-fetch.js +226 -31
- package/dist/puzzles/shared/load-once.d.ts +16 -0
- package/dist/puzzles/shared/load-once.d.ts.map +1 -0
- package/dist/puzzles/shared/load-once.js +11 -0
- package/dist/puzzles/skewb/solver/browser-loader.d.ts +4 -11
- package/dist/puzzles/skewb/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/browser-loader.js +44 -16
- package/dist/puzzles/skewb/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/generated-assets.js +8 -3
- package/dist/puzzles/skewb/solver/search.js +3 -3
- package/dist/puzzles/skewb/solver/tables.d.ts +6 -0
- package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/tables.js +17 -0
- package/dist/puzzles/sq1/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/sq1/solver/browser-loader.js +58 -26
- package/dist-cjs/core/api.js +10 -2
- package/dist-cjs/puzzles/cube2/solver/browser-loader.js +42 -14
- package/dist-cjs/puzzles/cube2/solver/generated-assets.js +8 -3
- package/dist-cjs/puzzles/cube2/solver/search.js +2 -2
- package/dist-cjs/puzzles/cube2/solver/tables.js +17 -3
- package/dist-cjs/puzzles/cube3/moves.js +104 -18
- package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
- package/dist-cjs/puzzles/cube3/solver/browser-loader.js +48 -22
- package/dist-cjs/puzzles/cube3/solver/generated-assets.js +9 -3
- package/dist-cjs/puzzles/cube3/solver/index.js +8 -1
- package/dist-cjs/puzzles/cube3/solver/node-loader.js +9 -2
- package/dist-cjs/puzzles/cube3/solver/phase1.js +157 -15
- package/dist-cjs/puzzles/cube3/solver/phase2.js +276 -65
- package/dist-cjs/puzzles/cube3/solver/symmetry.js +80 -0
- package/dist-cjs/puzzles/cube3/solver/tables.js +14 -12
- package/dist-cjs/puzzles/cube3/validation.js +15 -7
- package/dist-cjs/puzzles/cube4/browser-worker-pool.js +211 -0
- package/dist-cjs/puzzles/cube4/index.js +23 -1
- package/dist-cjs/puzzles/cube4/moves.js +213 -11
- package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +227 -32
- package/dist-cjs/puzzles/cube4/reduction/center2.js +155 -10
- package/dist-cjs/puzzles/cube4/reduction/edge3.js +24 -3
- package/dist-cjs/puzzles/cube4/reduction/finish3.js +398 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +44 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +232 -0
- package/dist-cjs/puzzles/cube4/reduction/node-loader.js +200 -25
- package/dist-cjs/puzzles/cube4/reduction/pair-transversal.js +112 -0
- package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
- package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +460 -33
- package/dist-cjs/puzzles/cube4/reduction/rotation-fix.js +216 -0
- package/dist-cjs/puzzles/cube4/reduction/solve.js +1203 -172
- package/dist-cjs/puzzles/cube4/scramble-cache.js +156 -0
- package/dist-cjs/puzzles/cube4/scrambler.js +416 -174
- package/dist-cjs/puzzles/cube4/state.js +4 -1
- package/dist-cjs/puzzles/cube4/worker-pool.js +447 -0
- package/dist-cjs/puzzles/cube4/worker-protocol.js +62 -0
- package/dist-cjs/puzzles/pyraminx/solver/browser-loader.js +44 -15
- package/dist-cjs/puzzles/pyraminx/solver/generated-assets.js +8 -3
- package/dist-cjs/puzzles/pyraminx/solver/search.js +2 -5
- package/dist-cjs/puzzles/pyraminx/solver/tables.js +18 -1
- package/dist-cjs/puzzles/shared/compressed-fetch.js +229 -31
- package/dist-cjs/puzzles/shared/load-once.js +14 -0
- package/dist-cjs/puzzles/skewb/solver/browser-loader.js +44 -16
- package/dist-cjs/puzzles/skewb/solver/generated-assets.js +8 -3
- package/dist-cjs/puzzles/skewb/solver/search.js +2 -2
- package/dist-cjs/puzzles/skewb/solver/tables.js +18 -1
- package/dist-cjs/puzzles/sq1/solver/browser-loader.js +58 -26
- package/docs/development.md +19 -7
- package/package.json +17 -7
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message protocol shared by the 4x4 Node worker (`worker.ts`), its pool
|
|
3
|
+
* (`worker-pool.ts`), and the browser equivalents (`browser-worker.ts`,
|
|
4
|
+
* `browser-worker-pool.ts`).
|
|
5
|
+
*
|
|
6
|
+
* Design notes:
|
|
7
|
+
* - Tasks carry the FULL `generateCube4Scramble` options object. The
|
|
8
|
+
* scrambler is a pure function of (seed, complete options), so forwarding
|
|
9
|
+
* every option verbatim is what makes the pool output bit-identical to
|
|
10
|
+
* the inline path for the same inputs.
|
|
11
|
+
* - Errors cross the thread boundary as data (`Cube4SerializedError`):
|
|
12
|
+
* `name`, `message`, `code` and `stack` survive, so typed solver errors
|
|
13
|
+
* (e.g. `Cube4TargetMismatchError` with `code: "cube4-target-mismatch"`)
|
|
14
|
+
* remain discriminated on the consumer side by name/code — the same
|
|
15
|
+
* classification keys `scrambler.ts` itself uses. Classes cannot be
|
|
16
|
+
* structured-cloned, so `instanceof` does not cross the boundary
|
|
17
|
+
* (documented contract).
|
|
18
|
+
*
|
|
19
|
+
* This module is deliberately free of runtime imports (type-only imports
|
|
20
|
+
* are erased at emit) so it can be bundled for the browser worker without
|
|
21
|
+
* dragging Node-only code into the graph.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Flattens an unknown thrown value into the structured-clone-safe shape
|
|
25
|
+
* above. Non-Error values are stringified so nothing is lost silently.
|
|
26
|
+
*/
|
|
27
|
+
export function serializeCube4Error(error) {
|
|
28
|
+
if (error instanceof Error) {
|
|
29
|
+
const code = error.code;
|
|
30
|
+
const primitiveCode = typeof code === "string" || typeof code === "number" ? code : undefined;
|
|
31
|
+
const serialized = {
|
|
32
|
+
name: error.name,
|
|
33
|
+
message: error.message
|
|
34
|
+
};
|
|
35
|
+
if (primitiveCode !== undefined)
|
|
36
|
+
serialized.code = primitiveCode;
|
|
37
|
+
if (typeof error.stack === "string")
|
|
38
|
+
serialized.stack = error.stack;
|
|
39
|
+
return serialized;
|
|
40
|
+
}
|
|
41
|
+
return { name: "Error", message: String(error) };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Rebuilds an Error from the wire shape, restoring `name`, `code` and
|
|
45
|
+
* `stack` (stack kept only as a debugging aid — its file locations point
|
|
46
|
+
* into the worker thread).
|
|
47
|
+
*/
|
|
48
|
+
export function deserializeCube4Error(serialized) {
|
|
49
|
+
const error = new Error(serialized.message);
|
|
50
|
+
error.name = serialized.name;
|
|
51
|
+
if (serialized.code !== undefined) {
|
|
52
|
+
error.code = serialized.code;
|
|
53
|
+
}
|
|
54
|
+
if (serialized.stack !== undefined) {
|
|
55
|
+
error.stack = serialized.stack;
|
|
56
|
+
}
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js worker_thread entry for 4x4 scramble generation.
|
|
3
|
+
*
|
|
4
|
+
* Lifecycle / lazy init: the thread boots without doing any work; the
|
|
5
|
+
* reduction + 3x3 tables (≈37 MB) are loaded on the FIRST task and then
|
|
6
|
+
* reused for every later task, because `scrambler.ts` deduplicates table
|
|
7
|
+
* loads per thread via its promise cache. Spawning is driven lazily by
|
|
8
|
+
* `worker-pool.ts` (one thread per queued job, up to the pool size), so a
|
|
9
|
+
* small batch never pays for idle threads.
|
|
10
|
+
*
|
|
11
|
+
* Protocol: see `worker-protocol.ts`. One task in flight per thread (the
|
|
12
|
+
* pool only re-dispatches after a response), but the handler is written to
|
|
13
|
+
* cope with concurrent messages just in case.
|
|
14
|
+
*
|
|
15
|
+
* Source-vs-dist loading: this file is excluded from the CommonJS build,
|
|
16
|
+
* so `import.meta` is safe here. When running from source the thread is
|
|
17
|
+
* booted with `execArgv: ["--import", "tsx"]` by the pool, but that flag
|
|
18
|
+
* alone does NOT register tsx's resolve hooks inside a worker thread
|
|
19
|
+
* (measured: `./x.js` → `./x.ts` mapping missing). Therefore, before any
|
|
20
|
+
* value import of the repo's `.js`-suffixed specifiers, we register the
|
|
21
|
+
* tsx hooks explicitly — `tsx/esm/api` resolves because source mode only
|
|
22
|
+
* happens inside a checkout with node_modules. From `dist/` no tsx is
|
|
23
|
+
* involved: the `.js` files are real.
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube4/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js worker_thread entry for 4x4 scramble generation.
|
|
3
|
+
*
|
|
4
|
+
* Lifecycle / lazy init: the thread boots without doing any work; the
|
|
5
|
+
* reduction + 3x3 tables (≈37 MB) are loaded on the FIRST task and then
|
|
6
|
+
* reused for every later task, because `scrambler.ts` deduplicates table
|
|
7
|
+
* loads per thread via its promise cache. Spawning is driven lazily by
|
|
8
|
+
* `worker-pool.ts` (one thread per queued job, up to the pool size), so a
|
|
9
|
+
* small batch never pays for idle threads.
|
|
10
|
+
*
|
|
11
|
+
* Protocol: see `worker-protocol.ts`. One task in flight per thread (the
|
|
12
|
+
* pool only re-dispatches after a response), but the handler is written to
|
|
13
|
+
* cope with concurrent messages just in case.
|
|
14
|
+
*
|
|
15
|
+
* Source-vs-dist loading: this file is excluded from the CommonJS build,
|
|
16
|
+
* so `import.meta` is safe here. When running from source the thread is
|
|
17
|
+
* booted with `execArgv: ["--import", "tsx"]` by the pool, but that flag
|
|
18
|
+
* alone does NOT register tsx's resolve hooks inside a worker thread
|
|
19
|
+
* (measured: `./x.js` → `./x.ts` mapping missing). Therefore, before any
|
|
20
|
+
* value import of the repo's `.js`-suffixed specifiers, we register the
|
|
21
|
+
* tsx hooks explicitly — `tsx/esm/api` resolves because source mode only
|
|
22
|
+
* happens inside a checkout with node_modules. From `dist/` no tsx is
|
|
23
|
+
* involved: the `.js` files are real.
|
|
24
|
+
*/
|
|
25
|
+
import { parentPort } from "node:worker_threads";
|
|
26
|
+
if (!parentPort) {
|
|
27
|
+
throw new Error("[cube4] worker.ts must be started as a worker_thread (use Cube4WorkerPool).");
|
|
28
|
+
}
|
|
29
|
+
const port = parentPort;
|
|
30
|
+
if (import.meta.url.endsWith(".ts")) {
|
|
31
|
+
const tsxApi = await import("tsx/esm/api");
|
|
32
|
+
tsxApi.register();
|
|
33
|
+
}
|
|
34
|
+
const { generateCube4Scramble } = await import("./scrambler.js");
|
|
35
|
+
const { serializeCube4Error } = await import("./worker-protocol.js");
|
|
36
|
+
port.on("message", (task) => {
|
|
37
|
+
void (async () => {
|
|
38
|
+
const response = await (async () => {
|
|
39
|
+
try {
|
|
40
|
+
const result = await generateCube4Scramble(task.options);
|
|
41
|
+
return { id: task.id, ok: true, result };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return { id: task.id, ok: false, error: serializeCube4Error(error) };
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
port.postMessage(response);
|
|
48
|
+
})();
|
|
49
|
+
});
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface PyraminxBrowserTables {
|
|
2
2
|
centersTable: Uint8Array;
|
|
3
3
|
permutationTable: Uint16Array;
|
|
4
4
|
orientationTable: Uint8Array;
|
|
5
5
|
policyTable: Uint8Array;
|
|
6
|
-
}
|
|
6
|
+
}
|
|
7
|
+
export declare function getCachedBrowserTables(): PyraminxBrowserTables | undefined;
|
|
7
8
|
export declare function clearCachedBrowserTables(): void;
|
|
8
|
-
export declare function loadBrowserTables(baseUrl?: string): Promise<
|
|
9
|
-
centersTable: Uint8Array;
|
|
10
|
-
permutationTable: Uint16Array;
|
|
11
|
-
orientationTable: Uint8Array;
|
|
12
|
-
policyTable: Uint8Array;
|
|
13
|
-
}>;
|
|
9
|
+
export declare function loadBrowserTables(baseUrl?: string): Promise<PyraminxBrowserTables>;
|
|
14
10
|
//# sourceMappingURL=browser-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/browser-loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/browser-loader.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,UAAU,CAAC;IACzB,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,UAAU,CAAC;IAC7B,WAAW,EAAE,UAAU,CAAC;CACzB;AAKD,wBAAgB,sBAAsB,IAAI,qBAAqB,GAAG,SAAS,CAE1E;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C;AAED,wBAAsB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkBxF"}
|
|
@@ -1,22 +1,42 @@
|
|
|
1
1
|
import { PYRAMINX_SOLVER_TABLE_METADATA } from "./table-metadata.js";
|
|
2
2
|
import { fetchTableBuffer as fetchCompressedTableBuffer } from "../../shared/compressed-fetch.js";
|
|
3
|
+
const TABLES_DIR = "puzzles/pyraminx/solver/generated";
|
|
4
|
+
const CACHE_NAME = "cubingcenter-scrambler-tables-v1";
|
|
3
5
|
let cachedBrowserTables;
|
|
6
|
+
let cachedBrowserTablesPromise;
|
|
4
7
|
export function getCachedBrowserTables() {
|
|
5
8
|
return cachedBrowserTables;
|
|
6
9
|
}
|
|
7
10
|
export function clearCachedBrowserTables() {
|
|
8
11
|
cachedBrowserTables = undefined;
|
|
12
|
+
cachedBrowserTablesPromise = undefined;
|
|
9
13
|
}
|
|
10
14
|
export async function loadBrowserTables(baseUrl) {
|
|
11
15
|
if (cachedBrowserTables)
|
|
12
16
|
return cachedBrowserTables;
|
|
17
|
+
if (cachedBrowserTablesPromise) {
|
|
18
|
+
// One shared in-flight promise: concurrent calls trigger exactly one
|
|
19
|
+
// fetch pass (dedup).
|
|
20
|
+
return cachedBrowserTablesPromise;
|
|
21
|
+
}
|
|
22
|
+
const promise = fetchTables(baseUrl);
|
|
23
|
+
cachedBrowserTablesPromise = promise;
|
|
24
|
+
promise.then(() => { }, () => {
|
|
25
|
+
// A failed load must not poison the dedup slot: purge the rejected
|
|
26
|
+
// promise so a later call retries from scratch.
|
|
27
|
+
if (cachedBrowserTablesPromise === promise)
|
|
28
|
+
cachedBrowserTablesPromise = undefined;
|
|
29
|
+
});
|
|
30
|
+
return promise;
|
|
31
|
+
}
|
|
32
|
+
async function fetchTables(baseUrl) {
|
|
13
33
|
const resolved = resolveBaseUrl(baseUrl);
|
|
14
34
|
const manifest = await fetchManifest(resolved);
|
|
15
35
|
const [centersTable, permutationTable, orientationTable, policyTable] = await Promise.all([
|
|
16
|
-
fetchUint8Table(resolved, manifest.files.centersTable, PYRAMINX_SOLVER_TABLE_METADATA.centersTable
|
|
17
|
-
fetchUint16Table(resolved, manifest.files.permutationTable, PYRAMINX_SOLVER_TABLE_METADATA.permutationTable
|
|
18
|
-
fetchUint8Table(resolved, manifest.files.orientationTable, PYRAMINX_SOLVER_TABLE_METADATA.orientationTable
|
|
19
|
-
fetchUint8Table(resolved, manifest.files.policyTable, PYRAMINX_SOLVER_TABLE_METADATA.policyTable
|
|
36
|
+
fetchUint8Table(resolved, manifest.files.centersTable, PYRAMINX_SOLVER_TABLE_METADATA.centersTable),
|
|
37
|
+
fetchUint16Table(resolved, manifest.files.permutationTable, PYRAMINX_SOLVER_TABLE_METADATA.permutationTable),
|
|
38
|
+
fetchUint8Table(resolved, manifest.files.orientationTable, PYRAMINX_SOLVER_TABLE_METADATA.orientationTable),
|
|
39
|
+
fetchUint8Table(resolved, manifest.files.policyTable, PYRAMINX_SOLVER_TABLE_METADATA.policyTable)
|
|
20
40
|
]);
|
|
21
41
|
cachedBrowserTables = { centersTable, permutationTable, orientationTable, policyTable };
|
|
22
42
|
return cachedBrowserTables;
|
|
@@ -43,19 +63,28 @@ async function fetchManifest(baseUrl) {
|
|
|
43
63
|
throw new Error(`Unsupported pyraminx solver table manifest version: ${manifest.version}`);
|
|
44
64
|
return manifest;
|
|
45
65
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Fetch + verify with the SAME checks as node-loader.ts: byte length from
|
|
68
|
+
* the manifest entries, FNV-1a checksum against the table-metadata
|
|
69
|
+
* constants (the values node asserts against).
|
|
70
|
+
*/
|
|
71
|
+
async function fetchUint8Table(baseUrl, entry, meta) {
|
|
72
|
+
const buffer = await fetchCompressedTableBuffer(baseUrl, TABLES_DIR, entry.file, {
|
|
73
|
+
cacheName: CACHE_NAME,
|
|
74
|
+
compressed: entry.compressed !== false,
|
|
75
|
+
expectedBytes: entry.entries,
|
|
76
|
+
expectedFnv1a: { value: meta.checksum, elementSize: 1 }
|
|
77
|
+
});
|
|
52
78
|
return new Uint8Array(buffer);
|
|
53
79
|
}
|
|
54
|
-
async function fetchUint16Table(baseUrl, entry,
|
|
55
|
-
const buffer = await fetchCompressedTableBuffer(baseUrl, TABLES_DIR, entry.file, {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
80
|
+
async function fetchUint16Table(baseUrl, entry, meta) {
|
|
81
|
+
const buffer = await fetchCompressedTableBuffer(baseUrl, TABLES_DIR, entry.file, {
|
|
82
|
+
cacheName: CACHE_NAME,
|
|
83
|
+
compressed: entry.compressed !== false,
|
|
84
|
+
expectedBytes: entry.entries * 2,
|
|
85
|
+
expectedFnv1a: { value: meta.checksum, elementSize: 2 }
|
|
86
|
+
});
|
|
87
|
+
const values = new Uint16Array(entry.entries);
|
|
59
88
|
const view = new DataView(buffer);
|
|
60
89
|
for (let i = 0; i < values.length; i++)
|
|
61
90
|
values[i] = view.getUint16(i * 2, true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-assets.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/generated-assets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generated-assets.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/generated-assets.ts"],"names":[],"mappings":"AAmBA,wBAAsB,iCAAiC,IAAI,OAAO,CAAC;IACjE,YAAY,EAAE,UAAU,CAAC;IACzB,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,UAAU,CAAC;IAC7B,WAAW,EAAE,UAAU,CAAC;CACzB,CAAC,CAWD"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { getCachedBrowserTables } from "./browser-loader.js";
|
|
2
|
-
|
|
2
|
+
import { loadOnce } from "../../shared/load-once.js";
|
|
3
|
+
// One shared in-flight promise for the node fs load (same pattern as
|
|
4
|
+
// cube3/solver/generated-assets.ts): the previous `cached ??= await …` raced —
|
|
5
|
+
// concurrent callers interleaving on the await both ran `loadNodeTables()`
|
|
6
|
+
// (two filesystem reads, last assignment wins). On rejection the slot is
|
|
7
|
+
// purged so the next call can retry.
|
|
8
|
+
const nodeTablesSlot = { promise: undefined };
|
|
3
9
|
function isBrowser() {
|
|
4
10
|
return typeof self !== "undefined";
|
|
5
11
|
}
|
|
@@ -12,8 +18,7 @@ export async function loadGeneratedPyraminxSolverTables() {
|
|
|
12
18
|
"In browser environments, call `initializeScrambler(baseUrl)` " +
|
|
13
19
|
"before generating scrambles.");
|
|
14
20
|
}
|
|
15
|
-
|
|
16
|
-
return cachedTables;
|
|
21
|
+
return loadOnce(nodeTablesSlot, loadNodeTables);
|
|
17
22
|
}
|
|
18
23
|
async function loadNodeTables() {
|
|
19
24
|
const loader = await import(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgB/D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAGjF;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAG3F;AAMD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGlF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAGvE;AAoCD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,EAAE,CAGtE;AAaD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAsCzG;AAKD,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,OAAO,CAmCT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { POLICY_TABLE, CENTERS_TABLE, PERMUTATION_TABLE, ORIENTATION_TABLE, PYRAMINX_MOVES, MOVE_COUNT, PERMUTATION_COUNT, getCentersIndex, getOrientationIndex, getPermutationCompactIndex, ensureTablesLoaded } from "./tables.js";
|
|
1
|
+
import { POLICY_TABLE, POLICY_TABLE_EXPANDED, CENTERS_TABLE, PERMUTATION_TABLE, ORIENTATION_TABLE, PYRAMINX_MOVES, MOVE_COUNT, PERMUTATION_COUNT, getCentersIndex, getOrientationIndex, getPermutationCompactIndex, ensureTablesLoaded } from "./tables.js";
|
|
2
2
|
export async function solvePyraminx(state) {
|
|
3
3
|
await ensureTablesLoaded();
|
|
4
4
|
return solveWithTables(state).moves;
|
|
@@ -29,7 +29,7 @@ function solveWithTablesIndices(state) {
|
|
|
29
29
|
const centersTable = CENTERS_TABLE;
|
|
30
30
|
const permTable = PERMUTATION_TABLE;
|
|
31
31
|
const orientTable = ORIENTATION_TABLE;
|
|
32
|
-
const policy =
|
|
32
|
+
const policy = POLICY_TABLE_EXPANDED;
|
|
33
33
|
let c = getCentersIndex(state.centers);
|
|
34
34
|
let p = getPermutationCompactIndex(state.edgesPerm);
|
|
35
35
|
let o = getOrientationIndex(state.edgesOrient);
|
|
@@ -38,10 +38,7 @@ function solveWithTablesIndices(state) {
|
|
|
38
38
|
return [];
|
|
39
39
|
const moves = [];
|
|
40
40
|
while (stateIndex !== 0) {
|
|
41
|
-
const
|
|
42
|
-
const byteIndex = bits >> 3;
|
|
43
|
-
const offset = bits & 7;
|
|
44
|
-
const m = ((policy[byteIndex] | ((policy[byteIndex + 1] ?? 0) << 8)) >> offset) & 0x07;
|
|
41
|
+
const m = policy[stateIndex];
|
|
45
42
|
moves.push(m);
|
|
46
43
|
c = centersTable[c * MOVE_COUNT + m];
|
|
47
44
|
p = permTable[p * MOVE_COUNT + m];
|
|
@@ -34,6 +34,12 @@ export declare let CENTERS_TABLE: Uint8Array | null;
|
|
|
34
34
|
export declare let PERMUTATION_TABLE: Uint16Array | null;
|
|
35
35
|
export declare let ORIENTATION_TABLE: Uint8Array | null;
|
|
36
36
|
export declare let POLICY_TABLE: Uint8Array | null;
|
|
37
|
+
/**
|
|
38
|
+
* Byte-expanded policy (one optimal move per state, no bit-unpacking in
|
|
39
|
+
* the hot walk). Built at load from the 3-bit packed table: +0.9 MB RAM,
|
|
40
|
+
* zero wire/format change.
|
|
41
|
+
*/
|
|
42
|
+
export declare let POLICY_TABLE_EXPANDED: Uint8Array | null;
|
|
37
43
|
export declare function ensureTablesLoaded(): Promise<void>;
|
|
38
44
|
export declare function arePyraminxTablesLoaded(): boolean;
|
|
39
45
|
export declare function getPolicyMove(stateIndex: number): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/tables.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ/D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAWnE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAY1E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMrE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAY/D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAElE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ3D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAIjE;AAGD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,eAAe,yBAAkD,CAAC;AAC/E,eAAO,MAAM,eAAe,0BAAqC,CAAC;AAalE,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAK1E;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlE;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAK1D;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAatE;AAMD,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,WAAW,QAA6C,CAAC;AACtE,eAAO,MAAM,qBAAqB,QAAmC,CAAC;AAGtE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMtF;AAED,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAEjD,CAAC;AAMF,wBAAgB,oBAAoB,IAAI,UAAU,CAgBjD;AAED,wBAAgB,wBAAwB,IAAI,WAAW,CAkBtD;AAED,wBAAgB,wBAAwB,IAAI,UAAU,CAgBrD;AAKD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,UAAU,EACxB,SAAS,EAAE,WAAW,EACtB,WAAW,EAAE,UAAU,GACtB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA8C1C;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAO1D;AAOD,eAAO,IAAI,aAAa,EAAE,UAAU,GAAG,IAAW,CAAC;AACnD,eAAO,IAAI,iBAAiB,EAAE,WAAW,GAAG,IAAW,CAAC;AACxD,eAAO,IAAI,iBAAiB,EAAE,UAAU,GAAG,IAAW,CAAC;AACvD,eAAO,IAAI,YAAY,EAAE,UAAU,GAAG,IAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/pyraminx/solver/tables.ts"],"names":[],"mappings":"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"}
|
|
@@ -261,6 +261,12 @@ export let CENTERS_TABLE = null;
|
|
|
261
261
|
export let PERMUTATION_TABLE = null;
|
|
262
262
|
export let ORIENTATION_TABLE = null;
|
|
263
263
|
export let POLICY_TABLE = null;
|
|
264
|
+
/**
|
|
265
|
+
* Byte-expanded policy (one optimal move per state, no bit-unpacking in
|
|
266
|
+
* the hot walk). Built at load from the 3-bit packed table: +0.9 MB RAM,
|
|
267
|
+
* zero wire/format change.
|
|
268
|
+
*/
|
|
269
|
+
export let POLICY_TABLE_EXPANDED = null;
|
|
264
270
|
export async function ensureTablesLoaded() {
|
|
265
271
|
if (tablesLoaded)
|
|
266
272
|
return;
|
|
@@ -269,8 +275,18 @@ export async function ensureTablesLoaded() {
|
|
|
269
275
|
PERMUTATION_TABLE = tables.permutationTable;
|
|
270
276
|
ORIENTATION_TABLE = tables.orientationTable;
|
|
271
277
|
POLICY_TABLE = tables.policyTable;
|
|
278
|
+
POLICY_TABLE_EXPANDED = expandPolicy3Bit(tables.policyTable, STATE_COUNT);
|
|
272
279
|
tablesLoaded = true;
|
|
273
280
|
}
|
|
281
|
+
function expandPolicy3Bit(packed, count) {
|
|
282
|
+
const expanded = new Uint8Array(count);
|
|
283
|
+
for (let index = 0; index < count; index += 1) {
|
|
284
|
+
const bits = index * 3;
|
|
285
|
+
const byteIndex = bits >> 3;
|
|
286
|
+
expanded[index] = (((packed[byteIndex] | ((packed[byteIndex + 1] ?? 0) << 8)) >> (bits & 7)) & 0x07);
|
|
287
|
+
}
|
|
288
|
+
return expanded;
|
|
289
|
+
}
|
|
274
290
|
export function arePyraminxTablesLoaded() {
|
|
275
291
|
return tablesLoaded;
|
|
276
292
|
}
|
|
@@ -300,4 +316,5 @@ export function resetTablesForTests() {
|
|
|
300
316
|
PERMUTATION_TABLE = null;
|
|
301
317
|
ORIENTATION_TABLE = null;
|
|
302
318
|
POLICY_TABLE = null;
|
|
319
|
+
POLICY_TABLE_EXPANDED = null;
|
|
303
320
|
}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
/** FNV-1a expectations from the legacy (non-sha256) manifests. */
|
|
2
|
+
export interface ExpectedFnv1a {
|
|
3
|
+
/** FNV-1a 32-bit checksum (`>>> 0`) over the decoded numeric sequence. */
|
|
4
|
+
value: number;
|
|
5
|
+
/**
|
|
6
|
+
* Wire size of each hashed element: 1 = byte, 2 = uint16 LE, 4 = int32 LE.
|
|
7
|
+
* Mirrors how each node loader decodes values before hashing (`4` also
|
|
8
|
+
* covers the 3x3 int32 move tables: their hashed uint16 values are the
|
|
9
|
+
* same numbers, and XOR/`Math.imul` are sign-insensitive there).
|
|
10
|
+
*/
|
|
11
|
+
elementSize: 1 | 2 | 4;
|
|
12
|
+
/** Hash 1-byte elements as signed int8 (Square-1's int8 tables). */
|
|
13
|
+
signed?: boolean;
|
|
14
|
+
}
|
|
1
15
|
export interface FetchTableBufferOptions {
|
|
2
|
-
/** Cache API cache name to store responses in (used by
|
|
16
|
+
/** Cache API cache name to store responses in (used by all table loaders). */
|
|
3
17
|
cacheName?: string;
|
|
4
18
|
/**
|
|
5
19
|
* Whether the manifest advertises precompressed variants for this file.
|
|
@@ -7,6 +21,28 @@ export interface FetchTableBufferOptions {
|
|
|
7
21
|
* set to false to skip .br/.gz attempts entirely.
|
|
8
22
|
*/
|
|
9
23
|
compressed?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* sha256 hex digest of the UNCOMPRESSED file (from its manifest entry).
|
|
26
|
+
* Verified after decompression; a mismatch rejects with the file URL.
|
|
27
|
+
*/
|
|
28
|
+
expectedSha256?: string;
|
|
29
|
+
/** Exact byte length of the uncompressed file (from its manifest entry). */
|
|
30
|
+
expectedBytes?: number;
|
|
31
|
+
/**
|
|
32
|
+
* FNV-1a checksum from legacy manifests (cube2/cube3/pyraminx/skewb/sq1).
|
|
33
|
+
* Verified after the length check; a mismatch rejects with the file URL.
|
|
34
|
+
*/
|
|
35
|
+
expectedFnv1a?: ExpectedFnv1a;
|
|
10
36
|
}
|
|
11
37
|
export declare function fetchTableBuffer(baseUrl: string, dir: string, file: string, options?: FetchTableBufferOptions): Promise<ArrayBuffer>;
|
|
38
|
+
/**
|
|
39
|
+
* FNV-1a (32-bit) over the elements decoded from a wire buffer: the browser
|
|
40
|
+
* twin of the node loaders' `checksum(values)` (imul multiply, `>>> 0`
|
|
41
|
+
* result). `elementSize` mirrors each loader's decoding of the manifest
|
|
42
|
+
* checksum — see `ExpectedFnv1a`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function fnv1a32(buffer: ArrayBuffer, elementSize: 1 | 2 | 4, signed?: boolean): number;
|
|
45
|
+
/** sha256 hex of a buffer; WebCrypto when available, portable JS fallback otherwise. */
|
|
46
|
+
export declare function sha256Hex(buffer: ArrayBuffer): Promise<string>;
|
|
47
|
+
export declare function sha256HexJs(buffer: ArrayBuffer): string;
|
|
12
48
|
//# sourceMappingURL=compressed-fetch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compressed-fetch.d.ts","sourceRoot":"","sources":["../../../src/puzzles/shared/compressed-fetch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compressed-fetch.d.ts","sourceRoot":"","sources":["../../../src/puzzles/shared/compressed-fetch.ts"],"names":[],"mappings":"AAeA,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,WAAW,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAkBD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,WAAW,CAAC,CAyDtB;AAmCD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,UAAQ,GAAG,MAAM,CAgB3F;AAED,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAYpE;AAcD,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAmEvD"}
|