UNPKG

@vscubing/cubing

Version:

A collection of JavaScript cubing libraries.

554 lines (533 loc) 17.5 kB
import { expose } from "./chunk-6WYRN27C.js"; import { countMoves } from "./chunk-V6NIAUMB.js"; import { addOrientationSuffix, initialize333, mustBeInsideWorker, random333OrientedScramble, random333Scramble, setIsInsideWorker, solve333 } from "./chunk-KE3EXEJK.js"; import "./chunk-RDSQRW3G.js"; import { cube2x2x2, puzzles } from "./chunk-H3JHWQ36.js"; import { from } from "./chunk-7ASPZCMY.js"; import { KPattern, KPuzzle } from "./chunk-4IUILNFM.js"; import { Alg, AlgBuilder, Move } from "./chunk-T3WO4S5D.js"; // src/cubing/search/inside/solve/puzzles/2x2x2.ts import { randomPermuteInPlace, randomUIntBelow } from "random-uint-below"; // src/cubing/search/inside/solve/tremble.ts import { randomChoice } from "random-uint-below"; var DEFAULT_STAGE1_DEPTH_LIMIT = 2; var DOUBLECHECK_PLACED_PIECES = true; var DEBUG = false; function calculateMoves(kpuzzle, moveNames) { const searchMoves = []; for (const moveName of moveNames) { const rootMove = new Move(moveName); if (rootMove.amount !== 1) { throw new Error( "SGS cannot handle def moves with an amount other than 1 yet." ); } let transformation = kpuzzle.identityTransformation(); for (let i = 1; ; i++) { transformation = transformation.applyMove(rootMove); if (transformation.isIdentityTransformation()) { break; } searchMoves.push({ move: rootMove.modified({ amount: i }), transformation }); } } return searchMoves; } var TrembleSolver = class { constructor(kpuzzle, sgs, trembleMoveNames) { this.kpuzzle = kpuzzle; this.sgs = sgs; this.searchMoves = calculateMoves( this.kpuzzle, trembleMoveNames ?? Object.keys(this.kpuzzle.definition.moves) ); } searchMoves; // public badRandomMoves(): KSolvePuzzleState { // return badRandomMoves(this.moves, this.ksp); // } async solve(pattern, stage1DepthLimit = DEFAULT_STAGE1_DEPTH_LIMIT, quantumMoveOrder) { const transformation = pattern.experimentalToTransformation(); if (!transformation) { throw new Error( "distinguishable pieces are not supported in tremble solver yt" ); } let bestAlg = null; let bestLen = 1e6; const recur = (recursiveTransformation, togo, sofar) => { if (togo === 0) { const sgsAlg = this.sgsPhaseSolve(recursiveTransformation, bestLen); if (!sgsAlg) { return; } const newAlg = sofar.concat(sgsAlg).experimentalSimplify({ cancel: { directional: "any-direction", puzzleSpecificModWrap: "canonical-centered" }, puzzleSpecificSimplifyOptions: { quantumMoveOrder } }); const len = countMoves(newAlg); if (bestAlg === null || len < bestLen) { if (DEBUG) { console.log(`New best (${len} moves): ${newAlg.toString()}`); console.log(`Tremble moves are: ${sofar.toString()}`); } bestAlg = newAlg; bestLen = len; } return; } for (const searchMove of this.searchMoves) { recur( recursiveTransformation.applyTransformation( searchMove.transformation ), togo - 1, sofar.concat([searchMove.move]) ); } }; for (let d = 0; d <= stage1DepthLimit; d++) { recur(transformation, d, new Alg()); } if (bestAlg === null) { throw new Error("SGS search failed."); } return bestAlg; } sgsPhaseSolve(initialTransformation, bestLenSofar) { const algBuilder = new AlgBuilder(); let transformation = initialTransformation; for (const step of this.sgs.ordering) { const cubieSeq = step.pieceOrdering; let key = ""; const inverseTransformation = transformation.invert(); for (let i = 0; i < cubieSeq.length; i++) { const loc = cubieSeq[i]; const orbitName = loc.orbitName; const idx = loc.permutationIdx; key += ` ${inverseTransformation.transformationData[orbitName].permutation[idx]} ${inverseTransformation.transformationData[orbitName].orientationDelta[idx]}`; } const info = step.lookup[key]; if (!info) { throw new Error("Missing algorithm in sgs or esgs?"); } algBuilder.experimentalPushAlg(info.alg); if (algBuilder.experimentalNumAlgNodes() >= bestLenSofar) { return null; } transformation = transformation.applyTransformation(info.transformation); if (DOUBLECHECK_PLACED_PIECES) { for (let i = 0; i < cubieSeq.length; i++) { const location = cubieSeq[i]; const orbitName = location.orbitName; const idx = location.permutationIdx; if (transformation.transformationData[orbitName].permutation[idx] !== idx || transformation.transformationData[orbitName].orientationDelta[idx] !== 0) { throw new Error("bad SGS :-("); } } } } return algBuilder.toAlg(); } }; // src/cubing/search/inside/solve/twsearch.ts var twsearchPromise = from(async () => import("./twsearch-SIIRKWRM.js")); async function wasmTwsearch(def, pattern, options) { const { wasmTwsearch: wasmTwsearch2 } = await twsearchPromise; return wasmTwsearch2(def, pattern, options); } async function wasmRandomScrambleForEvent(eventID) { const { wasmRandomScrambleForEvent: wasmRandomScrambleForEvent2 } = await twsearchPromise; return wasmRandomScrambleForEvent2(eventID); } // src/cubing/search/inside/solve/puzzles/dynamic/sgs-side-events/index.ts var searchDynamicSideEvents = from(() => import("./search-dynamic-sgs-side-events-KASNQ2FQ.js")); // src/cubing/search/inside/solve/puzzles/2x2x2.ts var cachedTrembleSolver = null; async function getCachedTrembleSolver() { return cachedTrembleSolver || (cachedTrembleSolver = (async () => { const sgsCachedData = await (await searchDynamicSideEvents).cachedData222(); return new TrembleSolver( await puzzles["2x2x2"].kpuzzle(), sgsCachedData, "URFLBD".split("") ); })()); } async function preInitialize222() { await getCachedTrembleSolver(); } async function solve222(pattern) { mustBeInsideWorker(); return wasmTwsearch((await cube2x2x2.kpuzzle()).definition, pattern, { generatorMoves: "UFLR".split("") }); } // src/cubing/search/inside/solve/puzzles/dynamic/4x4x4/index.ts var dynamic4x4x4Solver = from(() => import("./search-dynamic-solve-4x4x4-EGXWADTJ.js")); // src/cubing/search/inside/solve/puzzles/4x4x4.ts var randomSuffixes = [ [null, "x", "x2", "x'", "z", "z'"], [null, "y", "y2", "y'"] ]; async function initialize444() { return (await dynamic4x4x4Solver).initialize(); } async function random444Scramble() { mustBeInsideWorker(); return (await dynamic4x4x4Solver).random444Scramble(); } async function random444OrientedScramble() { return addOrientationSuffix(await random444Scramble(), randomSuffixes); } // src/cubing/search/inside/solve/puzzles/dynamic/fto/index.ts var dynamicFTO = from( () => import("./search-dynamic-solve-fto-YXHYT3DO.js") ); // src/cubing/search/inside/solve/puzzles/fto.ts var dynamic = from(() => import("./search-dynamic-sgs-unofficial-5UYWXZ4I.js")); async function randomFTOScramble() { mustBeInsideWorker(); return new Alg(await (await dynamicFTO).getRandomFTOScramble()); } // src/cubing/search/inside/solve/puzzles/dynamic/kilominx/index.ts var dynamicKilominxSolver = from(() => import("./search-dynamic-solve-kilominx-PZJHTZBO.js")); // src/cubing/search/inside/solve/puzzles/kilominx.ts async function randomKilominxScramble() { mustBeInsideWorker(); return (await dynamicKilominxSolver).getRandomKilominxScramble(); } // src/cubing/search/inside/solve/puzzles/dynamic/master_tetraminx/index.ts var dynamicMasterTetraminxSolver = from(() => import("./search-dynamic-solve-master_tetraminx-3D4MBF3V.js")); // src/cubing/search/inside/solve/puzzles/master_tetraminx.ts async function randomMasterTetraminxScramble() { mustBeInsideWorker(); return new Alg( await (await dynamicMasterTetraminxSolver).randomMasterTetraminxScrambleString() ); } // src/cubing/search/inside/solve/puzzles/megaminx.ts var TREMBLE_DEPTH = 2; var cachedTrembleSolver2 = null; async function getCachedTrembleSolver2() { return cachedTrembleSolver2 || (cachedTrembleSolver2 = (async () => { const json = await (await searchDynamicSideEvents).cachedSGSDataMegaminx(); return new TrembleSolver( await (await searchDynamicSideEvents).cachedMegaminxKPuzzleWithoutMO(), json, ["U", "R", "F", "L", "BR", "BL", "FR", "FL", "DR", "DL", "B", "D"] ); })()); } async function solveMegaminx(pattern) { mustBeInsideWorker(); const trembleSolver = await getCachedTrembleSolver2(); const patternDataWithoutMO = structuredClone( pattern.patternData ); patternDataWithoutMO["CENTERS"].orientation = new Array(12).fill(0); const patternWithoutMO = new KPattern( await (await searchDynamicSideEvents).cachedMegaminxKPuzzleWithoutMO(), patternDataWithoutMO ); const alg = await trembleSolver.solve( patternWithoutMO, TREMBLE_DEPTH, () => 5 // TODO: Attach quantum move order lookup to puzzle. ); return alg; } // src/cubing/search/inside/solve/puzzles/pyraminx.ts var TREMBLE_DEPTH2 = 3; var cachedTrembleSolver3 = null; async function getCachedTrembleSolver3() { return cachedTrembleSolver3 || (cachedTrembleSolver3 = (async () => { const json = await (await searchDynamicSideEvents).sgsDataPyraminx(); return new TrembleSolver( await puzzles["pyraminx"].kpuzzle(), json, "RLUB".split("") ); })()); } async function solvePyraminx(pattern) { mustBeInsideWorker(); const trembleSolver = await getCachedTrembleSolver3(); const alg = await trembleSolver.solve(pattern, TREMBLE_DEPTH2, () => 3); return alg; } // src/cubing/search/inside/solve/puzzles/dynamic/sgs-unofficial/index.ts var searchDynamicUnofficial = from(() => import("./search-dynamic-sgs-unofficial-5UYWXZ4I.js")); // src/cubing/search/inside/solve/puzzles/redi_cube.ts async function randomRediCubeScramble() { mustBeInsideWorker(); return (await searchDynamicUnofficial).getRandomRediCubeScramble(); } // src/cubing/search/inside/solve/puzzles/skewb.ts var TREMBLE_DEPTH3 = 3; var cachedTrembleSolver4 = null; async function getCachedTrembleSolver4() { return cachedTrembleSolver4 || (cachedTrembleSolver4 = (async () => { const json = await (await searchDynamicSideEvents).sgsDataSkewb(); return new TrembleSolver( await (await searchDynamicSideEvents).skewbKPuzzleWithoutMOCached(), json, "RLUB".split("") ); })()); } async function resetCenterOrientation(pattern) { return new KPattern( await (await searchDynamicSideEvents).skewbKPuzzleWithoutMOCached(), { CORNERS: pattern.patternData["CORNERS"], CENTERS: { pieces: pattern.patternData["CENTERS"].pieces, orientation: new Array(6).fill(0) } } ); } async function solveSkewb(pattern) { mustBeInsideWorker(); const trembleSolver = await getCachedTrembleSolver4(); const alg = await trembleSolver.solve( await resetCenterOrientation(pattern), TREMBLE_DEPTH3, (quantumMove) => quantumMove.family === "y" ? 4 : 3 // TODO: Attach quantum move order lookup to puzzle. ); return alg; } // src/cubing/search/inside/api.ts var IDLE_PREFETCH_TIMEOUT_MS = 1e3; setIsInsideWorker(true); var DEBUG_MEASURE_PERF = true; function setDebugMeasurePerf(newDebugMeasurePerf) { DEBUG_MEASURE_PERF = newDebugMeasurePerf; } function now() { return (typeof performance === "undefined" ? Date : performance).now(); } async function measurePerf(name, f, options) { if (!DEBUG_MEASURE_PERF) { return f(); } const start = now(); const result = f(); if (result?.then) { await result; } const end = now(); console.warn( `${name}${options?.isPrefetch ? " (prefetched)" : ""}: ${Math.round( end - start )}ms` ); return result; } var prefetchPromises = /* @__PURE__ */ new Map(); var queuedPrefetchTimeoutID = null; var scrambleActivityLock; async function randomScrambleForEvent(eventID, options) { return scrambleActivityLock = (async () => { await scrambleActivityLock; function wasm() { return measurePerf( `wasmRandomScrambleForEvent(${JSON.stringify(eventID)})`, () => wasmRandomScrambleForEvent(eventID), { isPrefetch: options?.isPrefetch } ); } switch (eventID) { // case "333": case "222": return (await wasm()).experimentalSimplify({ puzzleSpecificSimplifyOptions: { quantumMoveOrder: () => 4 } }); // case "444": case "555": case "666": case "777": // case "333bf": case "333fm": // case "333oh": // case "clock": case "minx": case "pyram": case "skewb": case "sq1": // case "444bf": case "555bf": // case "333mbf": // case "fto": // case "master_tetraminx": // case "kilominx": // case "redi_cube": case "baby_fto": return wasm(); case "333": case "333oh": case "333ft": return measurePerf("random333Scramble", random333Scramble, { isPrefetch: options?.isPrefetch }); case "333bf": case "333mbf": return measurePerf( "random333OrientedScramble", random333OrientedScramble ); case "444": return measurePerf("random444Scramble", random444Scramble, { isPrefetch: options?.isPrefetch }); case "444bf": return measurePerf( "random444OrientedScramble", random444OrientedScramble ); case "fto": return measurePerf("randomFTOScramble", randomFTOScramble, { isPrefetch: options?.isPrefetch }); case "master_tetraminx": return measurePerf( "randomMasterTetraminxScramble", randomMasterTetraminxScramble ); case "kilominx": return measurePerf("randomKilominxScramble", randomKilominxScramble, { isPrefetch: options?.isPrefetch }); case "redi_cube": return measurePerf("randomRediCubeScramble", randomRediCubeScramble, { isPrefetch: options?.isPrefetch }); default: throw new Error(`unsupported event: ${eventID}`); } })(); } var currentPrefetchLevel = "auto" /* Auto */; var insideAPI = { initialize: async (eventID) => { switch (eventID) { case "222": return measurePerf("preInitialize222", preInitialize222); case "333": case "333oh": case "333ft": return measurePerf("initialize333", initialize333); case "444": return measurePerf("initialize444", initialize444); default: throw new Error(`unsupported event: ${eventID}`); } }, setScramblePrefetchLevel(prefetchLevel) { currentPrefetchLevel = prefetchLevel; }, randomScrambleForEvent: async (eventID) => { let promise = prefetchPromises.get(eventID); if (promise) { prefetchPromises.delete(eventID); } else { promise = randomScrambleForEvent(eventID); } if (currentPrefetchLevel !== "none" /* None */) { promise.then(() => { if (queuedPrefetchTimeoutID) { clearTimeout(queuedPrefetchTimeoutID); } queuedPrefetchTimeoutID = setTimeout( () => { prefetchPromises.set( eventID, randomScrambleForEvent(eventID, { isPrefetch: true }) ); }, currentPrefetchLevel === "immediate" /* Immediate */ ? 0 : IDLE_PREFETCH_TIMEOUT_MS ); }); } return promise; }, randomScrambleStringForEvent: async (eventID) => { return (await insideAPI.randomScrambleForEvent(eventID)).toString(); }, solve333ToString: async (patternData) => { const pattern = new KPattern(await puzzles["3x3x3"].kpuzzle(), patternData); return (await solve333(pattern)).toString(); }, solve222ToString: async (patternData) => { const pattern = new KPattern(await puzzles["2x2x2"].kpuzzle(), patternData); return (await solve222(pattern)).toString(); }, solveSkewbToString: async (patternData) => { const pattern = new KPattern(await puzzles["skewb"].kpuzzle(), patternData); return (await solveSkewb(pattern)).toString(); }, solvePyraminxToString: async (patternData) => { const pattern = new KPattern( await puzzles["pyraminx"].kpuzzle(), patternData ); return (await solvePyraminx(pattern)).toString(); }, solveMegaminxToString: async (patternData) => { const pattern = new KPattern( await puzzles["megaminx"].kpuzzle(), patternData ); return (await solveMegaminx(pattern)).toString(); }, setDebugMeasurePerf: async (measure) => { setDebugMeasurePerf(measure); }, solveTwsearchToString: async (def, patternData, options) => { const kpuzzle = new KPuzzle(def); const pattern = new KPattern(kpuzzle, patternData); return (await wasmTwsearch(def, pattern, options)).toString(); } }; // src/cubing/search/inside/index.ts expose(insideAPI); //# sourceMappingURL=inside-GVBK5DTC.js.map