cube-state-engine 1.4.0 → 1.5.1

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/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
7
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
@@ -20,6 +22,7 @@ var __spreadValues = (a, b) => {
20
22
  }
21
23
  return a;
22
24
  };
25
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
26
  var __export = (target, all) => {
24
27
  for (var name in all)
25
28
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -35,24 +38,754 @@ var __copyProps = (to, from, except, desc) => {
35
38
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
39
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
37
40
  var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
41
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
38
42
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
43
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
39
44
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
40
45
 
41
46
  // src/index.js
42
47
  var src_exports = {};
43
48
  __export(src_exports, {
44
49
  COLOR: () => COLOR,
45
- CubeEngine: () => CubeEngine
50
+ CubeEngine: () => CubeEngine,
51
+ analyzeSolution: () => analyzeSolution,
52
+ getMovePermutations: () => getMovePermutations,
53
+ invertSequence: () => invertSequence,
54
+ simplifyMoves: () => simplifyMoves
46
55
  });
47
56
  module.exports = __toCommonJS(src_exports);
48
- var _CubeEngine_instances, initializeState_fn, createFace_fn, rotateU_fn, rotateF_fn, rotateB_fn, rotateR_fn, rotateL_fn, rotateD_fn, rotateDw_fn, rotateUw_fn, rotateRw_fn, rotateLw_fn, rotateM_fn, rotateX_fn, rotateZ_fn, rotateY_fn, switchMatrix_fn, specialFlip_fn, applyMovesFromString_fn;
57
+
58
+ // src/simplify.js
59
+ function canMerge(a, b) {
60
+ return typeof a === "string" && a === b && !a.includes("2");
61
+ }
62
+ function doubled(tok) {
63
+ return tok.replace("'", "") + "2";
64
+ }
65
+ function simplifyTokens(tokens) {
66
+ const out = [];
67
+ for (let i = 0; i < tokens.length; ) {
68
+ const a = tokens[i];
69
+ const b = tokens[i + 1];
70
+ if (i + 1 < tokens.length && canMerge(a, b)) {
71
+ out.push(doubled(a));
72
+ i += 2;
73
+ } else {
74
+ out.push(a);
75
+ i += 1;
76
+ }
77
+ }
78
+ return out;
79
+ }
80
+ function simplifyTimed(moves) {
81
+ const out = [];
82
+ for (let i = 0; i < moves.length; ) {
83
+ const a = moves[i];
84
+ const b = moves[i + 1];
85
+ if (i + 1 < moves.length && canMerge(a == null ? void 0 : a.m, b == null ? void 0 : b.m)) {
86
+ out.push({ m: doubled(a.m), t: b.t });
87
+ i += 2;
88
+ } else {
89
+ out.push(a);
90
+ i += 1;
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ function simplifyMoves(moves) {
96
+ if (typeof moves === "string") {
97
+ const tokens = moves.split(/\s+/).filter((t) => t.length > 0);
98
+ return simplifyTokens(tokens).join(" ");
99
+ }
100
+ if (Array.isArray(moves)) {
101
+ if (moves.length === 0) return [];
102
+ if (typeof moves[0] === "string") return simplifyTokens(moves);
103
+ return simplifyTimed(moves);
104
+ }
105
+ return moves;
106
+ }
107
+
108
+ // src/analyzer.js
109
+ var FACE_NAMES = ["UPPER", "LEFT", "FRONT", "RIGHT", "BACK", "DOWN"];
110
+ var FACE_MOVE_TO_INDEX = { U: 0, L: 1, F: 2, R: 3, B: 4, D: 5 };
111
+ var SUPPORTED_BASES = /* @__PURE__ */ new Set([
112
+ "U",
113
+ "D",
114
+ "L",
115
+ "R",
116
+ "F",
117
+ "B",
118
+ "x",
119
+ "y",
120
+ "z",
121
+ "M",
122
+ "E",
123
+ "S",
124
+ "Uw",
125
+ "Dw",
126
+ "Rw",
127
+ "Lw",
128
+ "Fw"
129
+ ]);
130
+ var WIDE_LOWER = { r: "Rw", u: "Uw", f: "Fw", l: "Lw", d: "Dw", b: "Bw" };
131
+ function normalizeToken(raw) {
132
+ const m = String(raw).trim().match(/^([A-Za-z]w?)('?2?|2?'?)$/);
133
+ if (!m) return { token: raw, base: null };
134
+ let base = m[1];
135
+ if (base.length === 1 && WIDE_LOWER[base]) base = WIDE_LOWER[base];
136
+ return { token: base + m[2], base };
137
+ }
138
+ var GEOMETRY_CACHE = /* @__PURE__ */ new Map();
139
+ function buildGeometry(size) {
140
+ if (GEOMETRY_CACHE.has(size)) return GEOMETRY_CACHE.get(size);
141
+ const perms = getMovePermutations(size);
142
+ const per = size * size;
143
+ const total = per * 6;
144
+ const faceMoves = Object.keys(FACE_MOVE_TO_INDEX);
145
+ const edgeMap = /* @__PURE__ */ new Map();
146
+ const cornerMap = /* @__PURE__ */ new Map();
147
+ for (let i = 0; i < total; i++) {
148
+ const faces = [];
149
+ for (const mv of faceMoves) {
150
+ if (perms[mv].cw[i] !== i) faces.push(FACE_MOVE_TO_INDEX[mv]);
151
+ }
152
+ faces.sort((a, b) => a - b);
153
+ const key = faces.join(",");
154
+ if (faces.length === 2) {
155
+ if (!edgeMap.has(key)) edgeMap.set(key, []);
156
+ edgeMap.get(key).push(i);
157
+ } else if (faces.length === 3) {
158
+ if (!cornerMap.has(key)) cornerMap.set(key, []);
159
+ cornerMap.get(key).push(i);
160
+ }
161
+ }
162
+ const edges = [...edgeMap.entries()].map(([key, indices]) => ({
163
+ faces: key.split(",").map(Number),
164
+ indices
165
+ }));
166
+ const corners = [...cornerMap.entries()].map(([key, indices]) => ({
167
+ faces: key.split(",").map(Number),
168
+ indices
169
+ }));
170
+ const neighbors = Array.from({ length: 6 }, () => /* @__PURE__ */ new Set());
171
+ for (const e of edges) {
172
+ const [a, b] = e.faces;
173
+ neighbors[a].add(b);
174
+ neighbors[b].add(a);
175
+ }
176
+ const opposite = new Array(6).fill(-1);
177
+ for (let f = 0; f < 6; f++) {
178
+ for (let g = 0; g < 6; g++) {
179
+ if (g !== f && !neighbors[f].has(g)) {
180
+ opposite[f] = g;
181
+ break;
182
+ }
183
+ }
184
+ }
185
+ const geo = {
186
+ size,
187
+ per,
188
+ centerIndex: (f) => f * per + Math.floor(per / 2),
189
+ edges,
190
+ corners,
191
+ neighbors,
192
+ opposite,
193
+ edgesByFace: (f) => edges.filter((e) => e.faces.includes(f)),
194
+ cornersByFace: (f) => corners.filter((c) => c.faces.includes(f)),
195
+ edgeByPair: (a, b) => edges.find(
196
+ (e) => e.faces[0] === a && e.faces[1] === b || e.faces[0] === b && e.faces[1] === a
197
+ )
198
+ };
199
+ GEOMETRY_CACHE.set(size, geo);
200
+ return geo;
201
+ }
202
+ function invertToken(tok) {
203
+ if (tok.endsWith("2")) return tok;
204
+ if (tok.endsWith("'")) return tok.slice(0, -1);
205
+ return tok + "'";
206
+ }
207
+ function invertSequence(tokens) {
208
+ return tokens.slice().reverse().map(invertToken);
209
+ }
210
+ function flattenState(state) {
211
+ const out = [];
212
+ for (const name of FACE_NAMES) {
213
+ const matrix = state[name];
214
+ for (const row of matrix) {
215
+ for (const v of row) out.push(v);
216
+ }
217
+ }
218
+ return out;
219
+ }
220
+ function centersOf(st, geo) {
221
+ const centers = new Array(6);
222
+ for (let f = 0; f < 6; f++) centers[f] = st[geo.centerIndex(f)];
223
+ return centers;
224
+ }
225
+ function slotCorrect(st, centers, indices, per) {
226
+ for (const x of indices) {
227
+ if (st[x] !== centers[Math.floor(x / per)]) return false;
228
+ }
229
+ return true;
230
+ }
231
+ function isSolvedFlat(st, per) {
232
+ for (let f = 0; f < 6; f++) {
233
+ const base = f * per;
234
+ const c = st[base];
235
+ for (let i = 1; i < per; i++) if (st[base + i] !== c) return false;
236
+ }
237
+ return true;
238
+ }
239
+ function crossDone(st, geo, color) {
240
+ const centers = centersOf(st, geo);
241
+ const C = centers.indexOf(color);
242
+ if (C < 0) return false;
243
+ return geo.edgesByFace(C).every((e) => slotCorrect(st, centers, e.indices, geo.per));
244
+ }
245
+ function f2lSlotStates(st, geo, color) {
246
+ const centers = centersOf(st, geo);
247
+ const C = centers.indexOf(color);
248
+ const result = {};
249
+ if (C < 0) return result;
250
+ for (const corner of geo.cornersByFace(C)) {
251
+ const sides = corner.faces.filter((f) => f !== C);
252
+ if (sides.length !== 2) continue;
253
+ const [a, b] = sides;
254
+ const edge = geo.edgeByPair(a, b);
255
+ const cornerOk = slotCorrect(st, centers, corner.indices, geo.per);
256
+ const edgeOk = edge ? slotCorrect(st, centers, edge.indices, geo.per) : false;
257
+ const key = [centers[a], centers[b]].sort().join("-");
258
+ result[key] = cornerOk && edgeOk;
259
+ }
260
+ return result;
261
+ }
262
+ function ollDone(st, geo, color) {
263
+ const centers = centersOf(st, geo);
264
+ const C = centers.indexOf(color);
265
+ if (C < 0) return false;
266
+ const O = geo.opposite[C];
267
+ const base = O * geo.per;
268
+ for (let i = 0; i < geo.per; i++) {
269
+ if (st[base + i] !== centers[O]) return false;
270
+ }
271
+ return true;
272
+ }
273
+ function completionIndex(bools) {
274
+ const n = bools.length;
275
+ if (n === 0 || !bools[n - 1]) return null;
276
+ for (let i = 0; i < n; i++) if (bools[i]) return i;
277
+ return null;
278
+ }
279
+ function buildForCross(snapshots, geo, color) {
280
+ const n = snapshots.length;
281
+ const crossBools = snapshots.map((st) => crossDone(st, geo, color));
282
+ const crossIdx = completionIndex(crossBools);
283
+ const slotSeries = /* @__PURE__ */ new Map();
284
+ for (let i = 0; i < n; i++) {
285
+ const states = f2lSlotStates(snapshots[i], geo, color);
286
+ for (const [key, val] of Object.entries(states)) {
287
+ if (!slotSeries.has(key)) slotSeries.set(key, new Array(n).fill(false));
288
+ slotSeries.get(key)[i] = crossBools[i] && val;
289
+ }
290
+ }
291
+ const f2lSlots = [...slotSeries.entries()].map(([slot, bools]) => ({ slot, idx: completionIndex(bools) })).filter((s) => s.idx != null).sort((a, b) => a.idx - b.idx);
292
+ const f2lComplete = new Array(n).fill(false);
293
+ for (let i = 0; i < n; i++) {
294
+ if (!crossBools[i] || slotSeries.size < 4) continue;
295
+ let all = true;
296
+ for (const bools of slotSeries.values()) {
297
+ if (!bools[i]) {
298
+ all = false;
299
+ break;
300
+ }
301
+ }
302
+ f2lComplete[i] = all;
303
+ }
304
+ const ollIdx = completionIndex(
305
+ snapshots.map((st, i) => f2lComplete[i] && ollDone(st, geo, color))
306
+ );
307
+ const pllIdx = completionIndex(snapshots.map((st) => isSolvedFlat(st, geo.per)));
308
+ return { crossIdx, f2lSlots, ollIdx, pllIdx };
309
+ }
310
+ function isCFOP(build) {
311
+ const { crossIdx, f2lSlots, ollIdx, pllIdx } = build;
312
+ if (crossIdx == null || pllIdx == null || ollIdx == null) return false;
313
+ if (f2lSlots.length !== 4) return false;
314
+ if (!f2lSlots.every((s) => s.idx >= crossIdx)) return false;
315
+ const lastF2L = f2lSlots[3].idx;
316
+ return ollIdx >= lastF2L && pllIdx >= ollIdx;
317
+ }
318
+ function analyzeSolution(moves, options = {}) {
319
+ var _a;
320
+ const size = options.size === 2 ? 2 : 3;
321
+ const unsupported = [];
322
+ const seq = (Array.isArray(moves) ? moves : []).map((x) => {
323
+ var _a2;
324
+ const m = String((_a2 = x == null ? void 0 : x.m) != null ? _a2 : "").trim();
325
+ const { token, base } = normalizeToken(m);
326
+ const supported = base != null && SUPPORTED_BASES.has(base);
327
+ if (m.length > 0 && !supported) unsupported.push(m);
328
+ return { m, mm: supported ? token : "", t: Number(x == null ? void 0 : x.t) };
329
+ }).filter((x) => x.m.length > 0);
330
+ const n = seq.length;
331
+ const simplifiedMoves = simplifyMoves(
332
+ (Array.isArray(moves) ? moves : []).filter((x) => x == null ? void 0 : x.m)
333
+ );
334
+ const simplifiedCount = simplifiedMoves.length;
335
+ const empty = {
336
+ size,
337
+ method: "unknown",
338
+ solved: false,
339
+ total: n > 0 ? seq[n - 1].t : 0,
340
+ tps: 0,
341
+ moves: simplifiedMoves,
342
+ cross: null,
343
+ f2l: [],
344
+ oll: null,
345
+ pll: null,
346
+ allCrosses: {},
347
+ unsupported
348
+ };
349
+ if (n === 0) return empty;
350
+ const engine = new CubeEngine("", { size });
351
+ const scramble = invertSequence(seq.map((x) => x.mm).filter(Boolean)).join(" ");
352
+ engine.applyMoves(scramble, { record: false });
353
+ const geo = buildGeometry(size);
354
+ const snapshots = new Array(n);
355
+ for (let i = 0; i < n; i++) {
356
+ if (seq[i].mm) engine.applyMoves(seq[i].mm, { record: false });
357
+ snapshots[i] = flattenState(engine.state());
358
+ }
359
+ const solved = isSolvedFlat(snapshots[n - 1], geo.per);
360
+ const pllIdxOnly = completionIndex(
361
+ snapshots.map((st) => isSolvedFlat(st, geo.per))
362
+ );
363
+ const milestone = (idx, prevAt2) => {
364
+ if (idx == null) return { record: null, at: prevAt2 };
365
+ const at = seq[idx].t;
366
+ return {
367
+ record: { at, duration: at - prevAt2, moveIndex: idx, move: seq[idx].m },
368
+ at
369
+ };
370
+ };
371
+ if (size !== 3) {
372
+ const pll2 = milestone(pllIdxOnly, 0);
373
+ const total2 = seq[n - 1].t;
374
+ return __spreadProps(__spreadValues({}, empty), {
375
+ solved,
376
+ total: total2,
377
+ tps: total2 > 0 ? simplifiedCount / (total2 / 1e3) : 0,
378
+ pll: pll2.record
379
+ });
380
+ }
381
+ const finalCenters = centersOf(snapshots[n - 1], geo);
382
+ const colors = [...new Set(finalCenters)];
383
+ const allCrosses = {};
384
+ for (const color of colors) {
385
+ const idx = completionIndex(
386
+ snapshots.map((st) => crossDone(st, geo, color))
387
+ );
388
+ allCrosses[color] = idx == null ? null : { at: seq[idx].t, moveIndex: idx, move: seq[idx].m };
389
+ }
390
+ const ordered = colors.map((color) => ({ color, build: buildForCross(snapshots, geo, color) })).sort((a, b) => {
391
+ var _a2, _b;
392
+ const ai = (_a2 = a.build.crossIdx) != null ? _a2 : Infinity;
393
+ const bi = (_b = b.build.crossIdx) != null ? _b : Infinity;
394
+ return ai - bi;
395
+ });
396
+ let chosen = (_a = ordered.find((c) => isCFOP(c.build))) != null ? _a : ordered[0];
397
+ const method = chosen && isCFOP(chosen.build) ? "CFOP" : "unknown";
398
+ const { color: crossColor, build } = chosen;
399
+ const crossM = milestone(build.crossIdx, 0);
400
+ const cross = crossM.record ? __spreadValues({ color: crossColor }, crossM.record) : null;
401
+ let prevAt = crossM.at;
402
+ const f2l = [];
403
+ for (const slot of build.f2lSlots) {
404
+ const m = milestone(slot.idx, prevAt);
405
+ if (m.record) {
406
+ f2l.push(__spreadValues({ slot: slot.slot }, m.record));
407
+ prevAt = m.at;
408
+ }
409
+ }
410
+ const ollM = milestone(build.ollIdx, prevAt);
411
+ const oll = ollM.record;
412
+ prevAt = ollM.at;
413
+ const pllM = milestone(build.pllIdx, prevAt);
414
+ const pll = pllM.record;
415
+ const total = seq[n - 1].t;
416
+ return {
417
+ size,
418
+ method,
419
+ solved,
420
+ total,
421
+ tps: total > 0 ? simplifiedCount / (total / 1e3) : 0,
422
+ moves: simplifiedMoves,
423
+ cross,
424
+ f2l,
425
+ oll,
426
+ pll,
427
+ allCrosses,
428
+ unsupported
429
+ };
430
+ }
431
+
432
+ // src/index.js
433
+ var FACE_NAMES2 = ["UPPER", "LEFT", "FRONT", "RIGHT", "BACK", "DOWN"];
434
+ var FACE_COLORS = ["W", "O", "G", "R", "B", "Y"];
435
+ var NOOP_SIZE2 = /* @__PURE__ */ new Set(["Uw", "Dw", "Rw", "Lw", "Fw", "M", "E", "S"]);
436
+ var MOVE_FNS = {
437
+ U: "rotateU",
438
+ D: "rotateD",
439
+ L: "rotateL",
440
+ R: "rotateR",
441
+ F: "rotateF",
442
+ B: "rotateB",
443
+ x: "rotateX",
444
+ y: "rotateY",
445
+ z: "rotateZ",
446
+ M: "rotateM",
447
+ E: "rotateE",
448
+ S: "rotateS",
449
+ Uw: "rotateUw",
450
+ Dw: "rotateDw",
451
+ Rw: "rotateRw",
452
+ Lw: "rotateLw",
453
+ Fw: "rotateFw"
454
+ };
455
+ var PERM_CACHE = /* @__PURE__ */ new Map();
456
+ var _OracleCube = class {
457
+ constructor(size) {
458
+ this.size = size;
459
+ this.STATES = {};
460
+ for (let f = 0; f < FACE_NAMES2.length; f++) {
461
+ const face = [];
462
+ for (let r = 0; r < size; r++) {
463
+ const row = [];
464
+ for (let c = 0; c < size; c++) {
465
+ row.push(f * size * size + r * size + c);
466
+ }
467
+ face.push(row);
468
+ }
469
+ this.STATES[FACE_NAMES2[f]] = face;
470
+ }
471
+ }
472
+ // Concatenate every face row-major into a single flat array of tags.
473
+ flatten() {
474
+ const out = [];
475
+ for (const name of FACE_NAMES2) {
476
+ const face = this.STATES[name];
477
+ for (let r = 0; r < this.size; r++) {
478
+ for (let c = 0; c < this.size; c++) {
479
+ out.push(face[r][c]);
480
+ }
481
+ }
482
+ }
483
+ return out;
484
+ }
485
+ switchMatrix(matrix, clockwise = true) {
486
+ const clone = structuredClone(matrix);
487
+ const size = this.size;
488
+ let tempMatrix = [];
489
+ for (let i = 0; i < size; i++) {
490
+ tempMatrix = [...tempMatrix, ...clone[i]];
491
+ }
492
+ if (size === 2) {
493
+ if (clockwise) {
494
+ return [
495
+ [tempMatrix[2], tempMatrix[0]],
496
+ [tempMatrix[3], tempMatrix[1]]
497
+ ];
498
+ } else {
499
+ return [
500
+ [tempMatrix[1], tempMatrix[3]],
501
+ [tempMatrix[0], tempMatrix[2]]
502
+ ];
503
+ }
504
+ } else {
505
+ if (clockwise) {
506
+ return [
507
+ [tempMatrix[6], tempMatrix[3], tempMatrix[0]],
508
+ [tempMatrix[7], tempMatrix[4], tempMatrix[1]],
509
+ [tempMatrix[8], tempMatrix[5], tempMatrix[2]]
510
+ ];
511
+ } else {
512
+ return [
513
+ [tempMatrix[2], tempMatrix[5], tempMatrix[8]],
514
+ [tempMatrix[1], tempMatrix[4], tempMatrix[7]],
515
+ [tempMatrix[0], tempMatrix[3], tempMatrix[6]]
516
+ ];
517
+ }
518
+ }
519
+ }
520
+ specialFlip(matrix) {
521
+ return structuredClone(matrix).reverse().map((row) => [...row].reverse());
522
+ }
523
+ rotateU(clockwise = true) {
524
+ if (clockwise) {
525
+ this.STATES.UPPER = this.switchMatrix(this.STATES.UPPER, true);
526
+ const tempFront = [...this.STATES.FRONT[0]];
527
+ const tempRight = [...this.STATES.RIGHT[0]];
528
+ const tempLeft = [...this.STATES.LEFT[0]];
529
+ const tempBack = [...this.STATES.BACK[0]];
530
+ this.STATES.FRONT[0] = [...tempRight];
531
+ this.STATES.LEFT[0] = [...tempFront];
532
+ this.STATES.BACK[0] = [...tempLeft];
533
+ this.STATES.RIGHT[0] = [...tempBack];
534
+ } else {
535
+ this.STATES.UPPER = this.switchMatrix(this.STATES.UPPER, false);
536
+ const tempFront = [...this.STATES.FRONT[0]];
537
+ const tempRight = [...this.STATES.RIGHT[0]];
538
+ const tempLeft = [...this.STATES.LEFT[0]];
539
+ const tempBack = [...this.STATES.BACK[0]];
540
+ this.STATES.FRONT[0] = [...tempLeft];
541
+ this.STATES.LEFT[0] = [...tempBack];
542
+ this.STATES.BACK[0] = [...tempRight];
543
+ this.STATES.RIGHT[0] = [...tempFront];
544
+ }
545
+ }
546
+ rotateF(clockwise = true) {
547
+ if (clockwise) {
548
+ this.rotateX(true);
549
+ this.rotateU(true);
550
+ this.rotateX(false);
551
+ } else {
552
+ this.rotateX(true);
553
+ this.rotateU(false);
554
+ this.rotateX(false);
555
+ }
556
+ }
557
+ rotateB(clockwise = true) {
558
+ this.rotateY(true);
559
+ this.rotateY(true);
560
+ if (clockwise) {
561
+ this.rotateF(true);
562
+ } else {
563
+ this.rotateF(false);
564
+ }
565
+ this.rotateY(false);
566
+ this.rotateY(false);
567
+ }
568
+ rotateR(clockwise = true) {
569
+ if (clockwise) {
570
+ this.rotateY(true);
571
+ this.rotateX(true);
572
+ this.rotateU(true);
573
+ this.rotateX(false);
574
+ this.rotateY(false);
575
+ } else {
576
+ this.rotateY(true);
577
+ this.rotateX(true);
578
+ this.rotateU(false);
579
+ this.rotateX(false);
580
+ this.rotateY(false);
581
+ }
582
+ }
583
+ rotateL(clockwise = true) {
584
+ if (clockwise) {
585
+ this.rotateY(false);
586
+ this.rotateX(true);
587
+ this.rotateU(true);
588
+ this.rotateX(false);
589
+ this.rotateY(true);
590
+ } else {
591
+ this.rotateY(false);
592
+ this.rotateX(true);
593
+ this.rotateU(false);
594
+ this.rotateX(false);
595
+ this.rotateY(true);
596
+ }
597
+ }
598
+ rotateD(clockwise = true) {
599
+ if (clockwise) {
600
+ this.rotateX(true);
601
+ this.rotateF(true);
602
+ this.rotateX(false);
603
+ } else {
604
+ this.rotateX(true);
605
+ this.rotateF(false);
606
+ this.rotateX(false);
607
+ }
608
+ }
609
+ rotateDw(clockwise = true) {
610
+ if (this.size === 2) return;
611
+ if (clockwise) {
612
+ this.rotateY(false);
613
+ this.rotateU(true);
614
+ } else {
615
+ this.rotateY(true);
616
+ this.rotateU(false);
617
+ }
618
+ }
619
+ rotateUw(clockwise = true) {
620
+ if (this.size === 2) return;
621
+ if (clockwise) {
622
+ this.rotateY(true);
623
+ this.rotateD(true);
624
+ } else {
625
+ this.rotateY(false);
626
+ this.rotateD(false);
627
+ }
628
+ }
629
+ rotateRw(clockwise = true) {
630
+ if (this.size === 2) return;
631
+ if (clockwise) {
632
+ this.rotateX(true);
633
+ this.rotateL(true);
634
+ } else {
635
+ this.rotateX(false);
636
+ this.rotateL(false);
637
+ }
638
+ }
639
+ rotateLw(clockwise = true) {
640
+ if (this.size === 2) return;
641
+ if (clockwise) {
642
+ this.rotateX(false);
643
+ this.rotateR(true);
644
+ } else {
645
+ this.rotateX(true);
646
+ this.rotateR(false);
647
+ }
648
+ }
649
+ rotateM(clockwise = true) {
650
+ if (this.size === 2) return;
651
+ if (clockwise) {
652
+ this.rotateLw(true);
653
+ this.rotateL(false);
654
+ } else {
655
+ this.rotateLw(false);
656
+ this.rotateL(true);
657
+ }
658
+ }
659
+ rotateE(clockwise = true) {
660
+ if (this.size === 2) return;
661
+ if (clockwise) {
662
+ this.rotateDw(true);
663
+ this.rotateD(false);
664
+ } else {
665
+ this.rotateDw(false);
666
+ this.rotateD(true);
667
+ }
668
+ }
669
+ rotateFw(clockwise = true) {
670
+ if (this.size === 2) return;
671
+ if (clockwise) {
672
+ this.rotateZ(true);
673
+ this.rotateB(true);
674
+ } else {
675
+ this.rotateZ(false);
676
+ this.rotateB(false);
677
+ }
678
+ }
679
+ rotateS(clockwise = true) {
680
+ if (this.size === 2) return;
681
+ if (clockwise) {
682
+ this.rotateFw(true);
683
+ this.rotateF(false);
684
+ } else {
685
+ this.rotateFw(false);
686
+ this.rotateF(true);
687
+ }
688
+ }
689
+ rotateX(clockwise = true) {
690
+ const tempFront = structuredClone(this.STATES.FRONT);
691
+ const tempDown = structuredClone(this.STATES.DOWN);
692
+ const tempUpper = structuredClone(this.STATES.UPPER);
693
+ const tempBack = structuredClone(this.STATES.BACK);
694
+ const tempLeft = structuredClone(this.STATES.LEFT);
695
+ const tempRight = structuredClone(this.STATES.RIGHT);
696
+ if (clockwise) {
697
+ this.STATES.LEFT = this.switchMatrix(tempLeft, false);
698
+ this.STATES.RIGHT = this.switchMatrix(tempRight, true);
699
+ this.STATES.FRONT = [...tempDown];
700
+ this.STATES.UPPER = [...tempFront];
701
+ this.STATES.BACK = this.specialFlip(tempUpper);
702
+ this.STATES.DOWN = this.specialFlip(tempBack);
703
+ } else {
704
+ this.STATES.LEFT = this.switchMatrix(tempLeft, true);
705
+ this.STATES.RIGHT = this.switchMatrix(tempRight, false);
706
+ this.STATES.FRONT = [...tempUpper];
707
+ this.STATES.DOWN = [...tempFront];
708
+ this.STATES.BACK = this.specialFlip(tempDown);
709
+ this.STATES.UPPER = this.specialFlip(tempBack);
710
+ }
711
+ }
712
+ rotateZ(clockwise = true) {
713
+ const tempUpper = structuredClone(this.STATES.UPPER);
714
+ const tempRight = structuredClone(this.STATES.RIGHT);
715
+ const tempDown = structuredClone(this.STATES.DOWN);
716
+ const tempLeft = structuredClone(this.STATES.LEFT);
717
+ const tempFront = structuredClone(this.STATES.FRONT);
718
+ const tempBack = structuredClone(this.STATES.BACK);
719
+ if (clockwise) {
720
+ this.STATES.FRONT = this.switchMatrix(tempFront, true);
721
+ this.STATES.BACK = this.switchMatrix(tempBack, false);
722
+ this.STATES.RIGHT = this.switchMatrix(tempUpper, true);
723
+ this.STATES.DOWN = this.switchMatrix(tempRight, true);
724
+ this.STATES.LEFT = this.switchMatrix(tempDown, true);
725
+ this.STATES.UPPER = this.switchMatrix(tempLeft, true);
726
+ } else {
727
+ this.STATES.FRONT = this.switchMatrix(tempFront, false);
728
+ this.STATES.BACK = this.switchMatrix(tempBack, true);
729
+ this.STATES.RIGHT = this.switchMatrix(tempDown, false);
730
+ this.STATES.DOWN = this.switchMatrix(tempLeft, false);
731
+ this.STATES.LEFT = this.switchMatrix(tempUpper, false);
732
+ this.STATES.UPPER = this.switchMatrix(tempRight, false);
733
+ }
734
+ }
735
+ rotateY(clockwise = true) {
736
+ const tempFront = structuredClone(this.STATES.FRONT);
737
+ const tempRight = structuredClone(this.STATES.RIGHT);
738
+ const tempBack = structuredClone(this.STATES.BACK);
739
+ const tempLeft = structuredClone(this.STATES.LEFT);
740
+ if (clockwise) {
741
+ this.STATES.UPPER = this.switchMatrix(this.STATES.UPPER, true);
742
+ this.STATES.DOWN = this.switchMatrix(this.STATES.DOWN, false);
743
+ this.STATES.FRONT = [...tempRight];
744
+ this.STATES.RIGHT = [...tempBack];
745
+ this.STATES.LEFT = [...tempFront];
746
+ this.STATES.BACK = [...tempLeft];
747
+ } else {
748
+ this.STATES.UPPER = this.switchMatrix(this.STATES.UPPER, false);
749
+ this.STATES.DOWN = this.switchMatrix(this.STATES.DOWN, true);
750
+ this.STATES.FRONT = [...tempLeft];
751
+ this.STATES.RIGHT = [...tempFront];
752
+ this.STATES.LEFT = [...tempBack];
753
+ this.STATES.BACK = [...tempRight];
754
+ }
755
+ }
756
+ };
757
+ function buildPerm(size, fnName, clockwise) {
758
+ const oracle = new _OracleCube(size);
759
+ oracle[fnName](clockwise);
760
+ return oracle.flatten();
761
+ }
762
+ function getPerms(size) {
763
+ if (PERM_CACHE.has(size)) return PERM_CACHE.get(size);
764
+ const perms = {};
765
+ for (const key of Object.keys(MOVE_FNS)) {
766
+ perms[key] = {
767
+ cw: buildPerm(size, MOVE_FNS[key], true),
768
+ ccw: buildPerm(size, MOVE_FNS[key], false)
769
+ };
770
+ }
771
+ PERM_CACHE.set(size, perms);
772
+ return perms;
773
+ }
774
+ function getMovePermutations(size = 3) {
775
+ const allowedSizes = [2, 3];
776
+ return getPerms(allowedSizes.includes(size) ? size : 3);
777
+ }
778
+ var _stickers, _perms, _CubeEngine_instances, initializeState_fn, applyPerm_fn, apply_fn, faceMatrix_fn, applyMovesFromString_fn;
49
779
  var CubeEngine = class {
50
780
  constructor(initialScramble = "", options = { size: 3 }) {
51
781
  __privateAdd(this, _CubeEngine_instances);
52
782
  __publicField(this, "MOVES", []);
53
783
  __publicField(this, "size", 3);
784
+ __privateAdd(this, _stickers, []);
785
+ __privateAdd(this, _perms, null);
54
786
  const allowedSizes = [2, 3];
55
787
  this.size = allowedSizes.includes(options.size) ? options.size : 3;
788
+ __privateSet(this, _perms, getPerms(this.size));
56
789
  __privateMethod(this, _CubeEngine_instances, initializeState_fn).call(this);
57
790
  if (typeof initialScramble === "string" && initialScramble.trim().length > 0) {
58
791
  __privateMethod(this, _CubeEngine_instances, applyMovesFromString_fn).call(this, initialScramble, false);
@@ -63,195 +796,131 @@ var CubeEngine = class {
63
796
  * Rotates the (UPPER) layer clockwise or counterclockwise.
64
797
  */
65
798
  rotateU(clockwise = true) {
66
- if (clockwise) {
67
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, true);
68
- this.MOVES.push("U");
69
- } else {
70
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, false);
71
- this.MOVES.push("U'");
72
- }
799
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "U", clockwise ? "cw" : "ccw", true);
73
800
  }
74
801
  /**
75
802
  * Rotates the (FRONT) layer clockwise or counterclockwise.
76
803
  */
77
804
  rotateF(clockwise = true) {
78
- if (clockwise) {
79
- __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, true);
80
- this.MOVES.push("F");
81
- } else {
82
- __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, false);
83
- this.MOVES.push("F'");
84
- }
805
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "F", clockwise ? "cw" : "ccw", true);
85
806
  }
86
807
  /**
87
808
  * Rotates the (BACK) layer clockwise or counterclockwise.
88
809
  */
89
810
  rotateB(clockwise = true) {
90
- if (clockwise) {
91
- __privateMethod(this, _CubeEngine_instances, rotateB_fn).call(this, true);
92
- this.MOVES.push("B");
93
- } else {
94
- __privateMethod(this, _CubeEngine_instances, rotateB_fn).call(this, false);
95
- this.MOVES.push("B'");
96
- }
811
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "B", clockwise ? "cw" : "ccw", true);
97
812
  }
98
813
  /**
99
814
  * Rotates the (RIGHT) layer clockwise or counterclockwise.
100
815
  */
101
816
  rotateR(clockwise = true) {
102
- if (clockwise) {
103
- __privateMethod(this, _CubeEngine_instances, rotateR_fn).call(this, true);
104
- this.MOVES.push("R");
105
- } else {
106
- __privateMethod(this, _CubeEngine_instances, rotateR_fn).call(this, false);
107
- this.MOVES.push("R'");
108
- }
817
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "R", clockwise ? "cw" : "ccw", true);
109
818
  }
110
819
  /**
111
820
  * Rotates the (LEFT) layer clockwise or counterclockwise.
112
821
  */
113
822
  rotateL(clockwise = true) {
114
- if (clockwise) {
115
- __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, true);
116
- this.MOVES.push("L");
117
- } else {
118
- __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, false);
119
- this.MOVES.push("L'");
120
- }
823
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "L", clockwise ? "cw" : "ccw", true);
121
824
  }
122
825
  /**
123
826
  * Rotates the (DOWN) layer clockwise or counterclockwise.
124
827
  */
125
828
  rotateD(clockwise = true) {
126
- if (clockwise) {
127
- __privateMethod(this, _CubeEngine_instances, rotateD_fn).call(this, true);
128
- this.MOVES.push("D");
129
- } else {
130
- __privateMethod(this, _CubeEngine_instances, rotateD_fn).call(this, false);
131
- this.MOVES.push("D'");
132
- }
829
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "D", clockwise ? "cw" : "ccw", true);
133
830
  }
134
831
  /**
135
832
  * Rotates the wide (DOWN two layers) clockwise or counterclockwise.
136
833
  */
137
834
  rotateDw(clockwise = true) {
138
- if (this.size === 2) return;
139
- if (clockwise) {
140
- __privateMethod(this, _CubeEngine_instances, rotateDw_fn).call(this, true);
141
- this.MOVES.push("Dw");
142
- } else {
143
- __privateMethod(this, _CubeEngine_instances, rotateDw_fn).call(this, false);
144
- this.MOVES.push("Dw'");
145
- }
835
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "Dw", clockwise ? "cw" : "ccw", true);
146
836
  }
147
837
  /**
148
838
  * Rotates the wide (UPPER two layers) clockwise or counterclockwise.
149
839
  */
150
840
  rotateUw(clockwise = true) {
151
- if (this.size === 2) return;
152
- if (clockwise) {
153
- __privateMethod(this, _CubeEngine_instances, rotateUw_fn).call(this, true);
154
- this.MOVES.push("Uw");
155
- } else {
156
- __privateMethod(this, _CubeEngine_instances, rotateUw_fn).call(this, false);
157
- this.MOVES.push("Uw'");
158
- }
841
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "Uw", clockwise ? "cw" : "ccw", true);
159
842
  }
160
843
  /**
161
844
  * Rotates the wide (RIGHT two layers) clockwise or counterclockwise.
162
845
  */
163
846
  rotateRw(clockwise = true) {
164
- if (this.size === 2) return;
165
- if (clockwise) {
166
- __privateMethod(this, _CubeEngine_instances, rotateRw_fn).call(this, true);
167
- this.MOVES.push("Rw");
168
- } else {
169
- __privateMethod(this, _CubeEngine_instances, rotateRw_fn).call(this, false);
170
- this.MOVES.push("Rw'");
171
- }
847
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "Rw", clockwise ? "cw" : "ccw", true);
172
848
  }
173
849
  /**
174
850
  * Rotates the wide (LEFT two layers) clockwise or counterclockwise.
175
851
  */
176
852
  rotateLw(clockwise = true) {
177
- if (this.size === 2) return;
178
- if (clockwise) {
179
- __privateMethod(this, _CubeEngine_instances, rotateLw_fn).call(this, true);
180
- this.MOVES.push("Lw");
181
- } else {
182
- __privateMethod(this, _CubeEngine_instances, rotateLw_fn).call(this, false);
183
- this.MOVES.push("Lw'");
184
- }
853
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "Lw", clockwise ? "cw" : "ccw", true);
185
854
  }
186
855
  /**
187
856
  * Rotates the middle slice (M) parallel to L/R. Clockwise corresponds to Lw followed by L'.
188
857
  */
189
858
  rotateM(clockwise = true) {
190
- if (this.size === 2) return;
191
- if (clockwise) {
192
- __privateMethod(this, _CubeEngine_instances, rotateM_fn).call(this, true);
193
- this.MOVES.push("M");
194
- } else {
195
- __privateMethod(this, _CubeEngine_instances, rotateM_fn).call(this, false);
196
- this.MOVES.push("M'");
197
- }
859
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "M", clockwise ? "cw" : "ccw", true);
860
+ }
861
+ /**
862
+ * Rotates the equatorial slice (E) parallel to U/D. Clockwise follows the D direction (E = Dw D').
863
+ */
864
+ rotateE(clockwise = true) {
865
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "E", clockwise ? "cw" : "ccw", true);
866
+ }
867
+ /**
868
+ * Rotates the wide (FRONT two layers) clockwise or counterclockwise. Equivalent to z B.
869
+ */
870
+ rotateFw(clockwise = true) {
871
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "Fw", clockwise ? "cw" : "ccw", true);
872
+ }
873
+ /**
874
+ * Rotates the standing slice (S) parallel to F/B. Clockwise follows the F direction (S = Fw F').
875
+ */
876
+ rotateS(clockwise = true) {
877
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "S", clockwise ? "cw" : "ccw", true);
198
878
  }
199
879
  /**
200
880
  * Rotates the (x) axis clockwise or counterclockwise.
201
881
  */
202
882
  rotateX(clockwise = true) {
203
- if (clockwise) {
204
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
205
- this.MOVES.push("x");
206
- } else {
207
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
208
- this.MOVES.push("x'");
209
- }
883
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "x", clockwise ? "cw" : "ccw", true);
210
884
  }
211
885
  /**
212
886
  * Rotates the (z) axis clockwise or counterclockwise.
213
887
  */
214
888
  rotateZ(clockwise = true) {
215
- if (clockwise) {
216
- __privateMethod(this, _CubeEngine_instances, rotateZ_fn).call(this, true);
217
- this.MOVES.push("z");
218
- } else {
219
- __privateMethod(this, _CubeEngine_instances, rotateZ_fn).call(this, false);
220
- this.MOVES.push("z'");
221
- }
889
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "z", clockwise ? "cw" : "ccw", true);
222
890
  }
223
891
  /**
224
892
  * Rotates the (y) axis clockwise or counterclockwise.
225
893
  */
226
894
  rotateY(clockwise = true) {
227
- if (clockwise) {
228
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
229
- this.MOVES.push("y");
230
- } else {
231
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
232
- this.MOVES.push("y'");
233
- }
895
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, "y", clockwise ? "cw" : "ccw", true);
234
896
  }
235
897
  /**
236
898
  * Logs the current state of the cube.
237
899
  */
238
900
  state() {
239
- return __spreadValues({}, this.STATES);
901
+ return {
902
+ UPPER: __privateMethod(this, _CubeEngine_instances, faceMatrix_fn).call(this, 0),
903
+ LEFT: __privateMethod(this, _CubeEngine_instances, faceMatrix_fn).call(this, 1),
904
+ FRONT: __privateMethod(this, _CubeEngine_instances, faceMatrix_fn).call(this, 2),
905
+ RIGHT: __privateMethod(this, _CubeEngine_instances, faceMatrix_fn).call(this, 3),
906
+ BACK: __privateMethod(this, _CubeEngine_instances, faceMatrix_fn).call(this, 4),
907
+ DOWN: __privateMethod(this, _CubeEngine_instances, faceMatrix_fn).call(this, 5)
908
+ };
240
909
  }
241
910
  /**
242
911
  * Indicates if the cube is solve or not in all layers.
243
912
  */
244
913
  isSolved() {
245
- const temp = __spreadValues({}, this.STATES);
246
- const layersSolved = Object.keys(temp).map((layer) => {
247
- let mixedMatrix = [];
248
- for (let i = 0; i < this.size; i++) {
249
- mixedMatrix = [...mixedMatrix, ...temp[layer][i]];
914
+ const per = this.size * this.size;
915
+ const centerOffset = this.size === 2 ? 0 : 4;
916
+ for (let f = 0; f < FACE_COLORS.length; f++) {
917
+ const base = f * per;
918
+ const centerColor = __privateGet(this, _stickers)[base + centerOffset];
919
+ for (let i = 0; i < per; i++) {
920
+ if (__privateGet(this, _stickers)[base + i] !== centerColor) return false;
250
921
  }
251
- const centerColor = this.size === 2 ? mixedMatrix[0] : mixedMatrix[4];
252
- return mixedMatrix.every((currentColor) => currentColor === centerColor);
253
- });
254
- return layersSolved.every((isLayerSolved) => isLayerSolved);
922
+ }
923
+ return true;
255
924
  }
256
925
  /**
257
926
  * Returns the history of all movements made.
@@ -271,8 +940,8 @@ var CubeEngine = class {
271
940
  }
272
941
  /**
273
942
  * Applies a sequence of moves provided as a string.
274
- * Supports: U, D, L, R, F, x, y, z; slice moves: M; and wide moves: Dw, Uw, Rw, Lw with optional ' for counterclockwise and 2 for double turns.
275
- * @param {string} sequence - e.g. "R U' F R2 D Dw Uw Rw Rw' Lw Lw2 M M' M2"
943
+ * Supports: U, D, L, R, F, B, x, y, z; slice moves: M, E, S; and wide moves: Dw, Uw, Rw, Lw, Fw with optional ' for counterclockwise and 2 for double turns.
944
+ * @param {string} sequence - e.g. "R U' F R2 D Dw Uw Rw Rw' Lw Lw2 M M' M2 E E' S S2 Fw"
276
945
  * @param {object} options - { record: boolean } whether to record moves in history (default true)
277
946
  */
278
947
  applyMoves(sequence, options = { record: false }) {
@@ -280,269 +949,51 @@ var CubeEngine = class {
280
949
  __privateMethod(this, _CubeEngine_instances, applyMovesFromString_fn).call(this, sequence, record);
281
950
  }
282
951
  };
952
+ _stickers = new WeakMap();
953
+ _perms = new WeakMap();
283
954
  _CubeEngine_instances = new WeakSet();
284
955
  initializeState_fn = function() {
285
- this.STATES = {
286
- UPPER: __privateMethod(this, _CubeEngine_instances, createFace_fn).call(this, "W"),
287
- LEFT: __privateMethod(this, _CubeEngine_instances, createFace_fn).call(this, "O"),
288
- FRONT: __privateMethod(this, _CubeEngine_instances, createFace_fn).call(this, "G"),
289
- RIGHT: __privateMethod(this, _CubeEngine_instances, createFace_fn).call(this, "R"),
290
- BACK: __privateMethod(this, _CubeEngine_instances, createFace_fn).call(this, "B"),
291
- DOWN: __privateMethod(this, _CubeEngine_instances, createFace_fn).call(this, "Y")
292
- };
293
- };
294
- // Create a face matrix based on cube size
295
- createFace_fn = function(color) {
296
- const face = [];
297
- for (let i = 0; i < this.size; i++) {
298
- const row = [];
299
- for (let j = 0; j < this.size; j++) {
300
- row.push(color);
956
+ const per = this.size * this.size;
957
+ const stickers = new Array(FACE_COLORS.length * per);
958
+ for (let f = 0; f < FACE_COLORS.length; f++) {
959
+ const color = FACE_COLORS[f];
960
+ const base = f * per;
961
+ for (let i = 0; i < per; i++) {
962
+ stickers[base + i] = color;
301
963
  }
302
- face.push(row);
303
- }
304
- return face;
305
- };
306
- rotateU_fn = function(clockwise = true) {
307
- if (clockwise) {
308
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, this.STATES.UPPER, true);
309
- const tempFront = [...this.STATES.FRONT[0]];
310
- const tempRight = [...this.STATES.RIGHT[0]];
311
- const tempLeft = [...this.STATES.LEFT[0]];
312
- const tempBack = [...this.STATES.BACK[0]];
313
- this.STATES.FRONT[0] = [...tempRight];
314
- this.STATES.LEFT[0] = [...tempFront];
315
- this.STATES.BACK[0] = [...tempLeft];
316
- this.STATES.RIGHT[0] = [...tempBack];
317
- } else {
318
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, this.STATES.UPPER, false);
319
- const tempFront = [...this.STATES.FRONT[0]];
320
- const tempRight = [...this.STATES.RIGHT[0]];
321
- const tempLeft = [...this.STATES.LEFT[0]];
322
- const tempBack = [...this.STATES.BACK[0]];
323
- this.STATES.FRONT[0] = [...tempLeft];
324
- this.STATES.LEFT[0] = [...tempBack];
325
- this.STATES.BACK[0] = [...tempRight];
326
- this.STATES.RIGHT[0] = [...tempFront];
327
- }
328
- };
329
- rotateF_fn = function(clockwise = true) {
330
- if (clockwise) {
331
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
332
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, true);
333
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
334
- } else {
335
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
336
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, false);
337
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
338
- }
339
- };
340
- rotateB_fn = function(clockwise = true) {
341
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
342
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
343
- if (clockwise) {
344
- __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, true);
345
- } else {
346
- __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, false);
347
- }
348
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
349
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
350
- };
351
- rotateR_fn = function(clockwise = true) {
352
- if (clockwise) {
353
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
354
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
355
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, true);
356
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
357
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
358
- } else {
359
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
360
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
361
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, false);
362
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
363
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
364
- }
365
- };
366
- rotateL_fn = function(clockwise = true) {
367
- if (clockwise) {
368
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
369
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
370
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, true);
371
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
372
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
373
- } else {
374
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
375
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
376
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, false);
377
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
378
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
379
964
  }
965
+ __privateSet(this, _stickers, stickers);
380
966
  };
381
- rotateD_fn = function(clockwise = true) {
382
- if (clockwise) {
383
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
384
- __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, true);
385
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
386
- } else {
387
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
388
- __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, false);
389
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
967
+ // Apply a precomputed permutation: newState[i] = oldState[perm[i]].
968
+ applyPerm_fn = function(perm) {
969
+ const current = __privateGet(this, _stickers);
970
+ const next = new Array(current.length);
971
+ for (let i = 0; i < current.length; i++) {
972
+ next[i] = current[perm[i]];
390
973
  }
974
+ __privateSet(this, _stickers, next);
391
975
  };
392
- rotateDw_fn = function(clockwise = true) {
393
- if (clockwise) {
394
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
395
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, true);
396
- } else {
397
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
398
- __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, false);
399
- }
400
- };
401
- rotateUw_fn = function(clockwise = true) {
402
- if (clockwise) {
403
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true);
404
- __privateMethod(this, _CubeEngine_instances, rotateD_fn).call(this, true);
405
- } else {
406
- __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false);
407
- __privateMethod(this, _CubeEngine_instances, rotateD_fn).call(this, false);
408
- }
976
+ // Core move dispatch. dir is "cw" or "ccw"; record controls history logging.
977
+ apply_fn = function(key, dir, record) {
978
+ if (this.size === 2 && NOOP_SIZE2.has(key)) return;
979
+ __privateMethod(this, _CubeEngine_instances, applyPerm_fn).call(this, __privateGet(this, _perms)[key][dir]);
980
+ if (record) this.MOVES.push(dir === "ccw" ? key + "'" : key);
409
981
  };
410
- rotateRw_fn = function(clockwise = true) {
411
- if (clockwise) {
412
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
413
- __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, true);
414
- } else {
415
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
416
- __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, false);
417
- }
418
- };
419
- rotateLw_fn = function(clockwise = true) {
420
- if (clockwise) {
421
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false);
422
- __privateMethod(this, _CubeEngine_instances, rotateR_fn).call(this, true);
423
- } else {
424
- __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true);
425
- __privateMethod(this, _CubeEngine_instances, rotateR_fn).call(this, false);
426
- }
427
- };
428
- rotateM_fn = function(clockwise = true) {
429
- if (clockwise) {
430
- __privateMethod(this, _CubeEngine_instances, rotateLw_fn).call(this, true);
431
- __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, false);
432
- } else {
433
- __privateMethod(this, _CubeEngine_instances, rotateLw_fn).call(this, false);
434
- __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, true);
435
- }
436
- };
437
- rotateX_fn = function(clockwise = true) {
438
- const tempFront = structuredClone(this.STATES.FRONT);
439
- const tempDown = structuredClone(this.STATES.DOWN);
440
- const tempUpper = structuredClone(this.STATES.UPPER);
441
- const tempBack = structuredClone(this.STATES.BACK);
442
- const tempLeft = structuredClone(this.STATES.LEFT);
443
- const tempRight = structuredClone(this.STATES.RIGHT);
444
- if (clockwise) {
445
- this.STATES.LEFT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempLeft, false);
446
- this.STATES.RIGHT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempRight, true);
447
- this.STATES.FRONT = [...tempDown];
448
- this.STATES.UPPER = [...tempFront];
449
- this.STATES.BACK = __privateMethod(this, _CubeEngine_instances, specialFlip_fn).call(this, tempUpper);
450
- this.STATES.DOWN = __privateMethod(this, _CubeEngine_instances, specialFlip_fn).call(this, tempBack);
451
- } else {
452
- this.STATES.LEFT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempLeft, true);
453
- this.STATES.RIGHT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempRight, false);
454
- this.STATES.FRONT = [...tempUpper];
455
- this.STATES.DOWN = [...tempFront];
456
- this.STATES.BACK = __privateMethod(this, _CubeEngine_instances, specialFlip_fn).call(this, tempDown);
457
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, specialFlip_fn).call(this, tempBack);
458
- }
459
- };
460
- rotateZ_fn = function(clockwise = true) {
461
- const tempUpper = structuredClone(this.STATES.UPPER);
462
- const tempRight = structuredClone(this.STATES.RIGHT);
463
- const tempDown = structuredClone(this.STATES.DOWN);
464
- const tempLeft = structuredClone(this.STATES.LEFT);
465
- const tempFront = structuredClone(this.STATES.FRONT);
466
- const tempBack = structuredClone(this.STATES.BACK);
467
- if (clockwise) {
468
- this.STATES.FRONT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempFront, true);
469
- this.STATES.BACK = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempBack, false);
470
- this.STATES.RIGHT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempUpper, true);
471
- this.STATES.DOWN = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempRight, true);
472
- this.STATES.LEFT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempDown, true);
473
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempLeft, true);
474
- } else {
475
- this.STATES.FRONT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempFront, false);
476
- this.STATES.BACK = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempBack, true);
477
- this.STATES.RIGHT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempDown, false);
478
- this.STATES.DOWN = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempLeft, false);
479
- this.STATES.LEFT = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempUpper, false);
480
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, tempRight, false);
481
- }
482
- };
483
- rotateY_fn = function(clockwise = true) {
484
- const tempFront = structuredClone(this.STATES.FRONT);
485
- const tempRight = structuredClone(this.STATES.RIGHT);
486
- const tempBack = structuredClone(this.STATES.BACK);
487
- const tempLeft = structuredClone(this.STATES.LEFT);
488
- if (clockwise) {
489
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, this.STATES.UPPER, true);
490
- this.STATES.DOWN = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, this.STATES.DOWN, false);
491
- this.STATES.FRONT = [...tempRight];
492
- this.STATES.RIGHT = [...tempBack];
493
- this.STATES.LEFT = [...tempFront];
494
- this.STATES.BACK = [...tempLeft];
495
- } else {
496
- this.STATES.UPPER = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, this.STATES.UPPER, false);
497
- this.STATES.DOWN = __privateMethod(this, _CubeEngine_instances, switchMatrix_fn).call(this, this.STATES.DOWN, true);
498
- this.STATES.FRONT = [...tempLeft];
499
- this.STATES.RIGHT = [...tempFront];
500
- this.STATES.LEFT = [...tempBack];
501
- this.STATES.BACK = [...tempRight];
502
- }
503
- };
504
- /**
505
- * Rotate the entire face in the direction set
506
- */
507
- switchMatrix_fn = function(matrix, clockwise = true) {
508
- const clone = structuredClone(matrix);
982
+ // Build a single face matrix from the flat sticker array.
983
+ faceMatrix_fn = function(faceIndex) {
509
984
  const size = this.size;
510
- let tempMatrix = [];
511
- for (let i = 0; i < size; i++) {
512
- tempMatrix = [...tempMatrix, ...clone[i]];
513
- }
514
- if (size === 2) {
515
- if (clockwise) {
516
- return [
517
- [tempMatrix[2], tempMatrix[0]],
518
- [tempMatrix[3], tempMatrix[1]]
519
- ];
520
- } else {
521
- return [
522
- [tempMatrix[1], tempMatrix[3]],
523
- [tempMatrix[0], tempMatrix[2]]
524
- ];
525
- }
526
- } else {
527
- if (clockwise) {
528
- return [
529
- [tempMatrix[6], tempMatrix[3], tempMatrix[0]],
530
- [tempMatrix[7], tempMatrix[4], tempMatrix[1]],
531
- [tempMatrix[8], tempMatrix[5], tempMatrix[2]]
532
- ];
533
- } else {
534
- return [
535
- [tempMatrix[2], tempMatrix[5], tempMatrix[8]],
536
- [tempMatrix[1], tempMatrix[4], tempMatrix[7]],
537
- [tempMatrix[0], tempMatrix[3], tempMatrix[6]]
538
- ];
985
+ const base = faceIndex * size * size;
986
+ const matrix = [];
987
+ for (let r = 0; r < size; r++) {
988
+ const row = [];
989
+ for (let c = 0; c < size; c++) {
990
+ row.push(__privateGet(this, _stickers)[base + r * size + c]);
539
991
  }
992
+ matrix.push(row);
540
993
  }
994
+ return matrix;
541
995
  };
542
- specialFlip_fn = function(matrix) {
543
- return structuredClone(matrix).reverse().map((row) => [...row].reverse());
544
- };
545
- // Internal: parses and applies moves. If record=false, uses private methods to avoid logging.
996
+ // Internal: parses and applies moves, optionally recording them in history.
546
997
  applyMovesFromString_fn = function(sequence, record = true) {
547
998
  if (typeof sequence !== "string") return;
548
999
  const tokens = sequence.split(/\s+/).map((t) => t.trim()).filter((t) => t.length > 0);
@@ -551,121 +1002,55 @@ applyMovesFromString_fn = function(sequence, record = true) {
551
1002
  const rest = token.slice(1);
552
1003
  const isDouble = rest.includes("2");
553
1004
  const isPrime = rest.includes("'");
554
- const exec = (fnClockwise, fnCounter) => {
555
- if (isDouble) {
556
- fnClockwise();
557
- fnClockwise();
558
- } else {
559
- if (isPrime) {
560
- fnCounter();
561
- } else {
562
- fnClockwise();
563
- }
564
- }
565
- };
1005
+ const isWide = /w/i.test(rest);
1006
+ let key;
566
1007
  switch (base) {
567
1008
  case "U":
568
- {
569
- const isWide = /w/i.test(rest);
570
- if (isWide) {
571
- exec(
572
- () => record ? this.rotateUw(true) : __privateMethod(this, _CubeEngine_instances, rotateUw_fn).call(this, true),
573
- () => record ? this.rotateUw(false) : __privateMethod(this, _CubeEngine_instances, rotateUw_fn).call(this, false)
574
- );
575
- } else {
576
- exec(
577
- () => record ? this.rotateU(true) : __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, true),
578
- () => record ? this.rotateU(false) : __privateMethod(this, _CubeEngine_instances, rotateU_fn).call(this, false)
579
- );
580
- }
581
- }
1009
+ key = isWide ? "Uw" : "U";
582
1010
  break;
583
1011
  case "D":
584
- {
585
- const isWide = /w/i.test(rest);
586
- if (isWide) {
587
- exec(
588
- () => record ? this.rotateDw(true) : __privateMethod(this, _CubeEngine_instances, rotateDw_fn).call(this, true),
589
- () => record ? this.rotateDw(false) : __privateMethod(this, _CubeEngine_instances, rotateDw_fn).call(this, false)
590
- );
591
- } else {
592
- exec(
593
- () => record ? this.rotateD(true) : __privateMethod(this, _CubeEngine_instances, rotateD_fn).call(this, true),
594
- () => record ? this.rotateD(false) : __privateMethod(this, _CubeEngine_instances, rotateD_fn).call(this, false)
595
- );
596
- }
597
- }
1012
+ key = isWide ? "Dw" : "D";
598
1013
  break;
599
1014
  case "L":
600
- {
601
- const isWide = /w/i.test(rest);
602
- if (isWide) {
603
- exec(
604
- () => record ? this.rotateLw(true) : __privateMethod(this, _CubeEngine_instances, rotateLw_fn).call(this, true),
605
- () => record ? this.rotateLw(false) : __privateMethod(this, _CubeEngine_instances, rotateLw_fn).call(this, false)
606
- );
607
- } else {
608
- exec(
609
- () => record ? this.rotateL(true) : __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, true),
610
- () => record ? this.rotateL(false) : __privateMethod(this, _CubeEngine_instances, rotateL_fn).call(this, false)
611
- );
612
- }
613
- }
1015
+ key = isWide ? "Lw" : "L";
614
1016
  break;
615
1017
  case "R":
616
- {
617
- const isWide = /w/i.test(rest);
618
- if (isWide) {
619
- exec(
620
- () => record ? this.rotateRw(true) : __privateMethod(this, _CubeEngine_instances, rotateRw_fn).call(this, true),
621
- () => record ? this.rotateRw(false) : __privateMethod(this, _CubeEngine_instances, rotateRw_fn).call(this, false)
622
- );
623
- } else {
624
- exec(
625
- () => record ? this.rotateR(true) : __privateMethod(this, _CubeEngine_instances, rotateR_fn).call(this, true),
626
- () => record ? this.rotateR(false) : __privateMethod(this, _CubeEngine_instances, rotateR_fn).call(this, false)
627
- );
628
- }
629
- }
1018
+ key = isWide ? "Rw" : "R";
630
1019
  break;
631
1020
  case "F":
632
- exec(
633
- () => record ? this.rotateF(true) : __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, true),
634
- () => record ? this.rotateF(false) : __privateMethod(this, _CubeEngine_instances, rotateF_fn).call(this, false)
635
- );
1021
+ key = isWide ? "Fw" : "F";
636
1022
  break;
637
1023
  case "B":
638
- exec(
639
- () => record ? this.rotateB(true) : __privateMethod(this, _CubeEngine_instances, rotateB_fn).call(this, true),
640
- () => record ? this.rotateB(false) : __privateMethod(this, _CubeEngine_instances, rotateB_fn).call(this, false)
641
- );
1024
+ key = "B";
642
1025
  break;
643
1026
  case "x":
644
- exec(
645
- () => record ? this.rotateX(true) : __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, true),
646
- () => record ? this.rotateX(false) : __privateMethod(this, _CubeEngine_instances, rotateX_fn).call(this, false)
647
- );
1027
+ key = "x";
648
1028
  break;
649
1029
  case "y":
650
- exec(
651
- () => record ? this.rotateY(true) : __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, true),
652
- () => record ? this.rotateY(false) : __privateMethod(this, _CubeEngine_instances, rotateY_fn).call(this, false)
653
- );
1030
+ key = "y";
654
1031
  break;
655
1032
  case "z":
656
- exec(
657
- () => record ? this.rotateZ(true) : __privateMethod(this, _CubeEngine_instances, rotateZ_fn).call(this, true),
658
- () => record ? this.rotateZ(false) : __privateMethod(this, _CubeEngine_instances, rotateZ_fn).call(this, false)
659
- );
1033
+ key = "z";
660
1034
  break;
661
1035
  case "M":
662
- exec(
663
- () => record ? this.rotateM(true) : __privateMethod(this, _CubeEngine_instances, rotateM_fn).call(this, true),
664
- () => record ? this.rotateM(false) : __privateMethod(this, _CubeEngine_instances, rotateM_fn).call(this, false)
665
- );
1036
+ key = "M";
666
1037
  break;
667
- default:
1038
+ case "E":
1039
+ key = "E";
668
1040
  break;
1041
+ case "S":
1042
+ key = "S";
1043
+ break;
1044
+ default:
1045
+ continue;
1046
+ }
1047
+ if (isDouble) {
1048
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, key, "cw", record);
1049
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, key, "cw", record);
1050
+ } else if (isPrime) {
1051
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, key, "ccw", record);
1052
+ } else {
1053
+ __privateMethod(this, _CubeEngine_instances, apply_fn).call(this, key, "cw", record);
669
1054
  }
670
1055
  }
671
1056
  };
@@ -680,5 +1065,9 @@ var COLOR = {
680
1065
  // Annotate the CommonJS export names for ESM import in node:
681
1066
  0 && (module.exports = {
682
1067
  COLOR,
683
- CubeEngine
1068
+ CubeEngine,
1069
+ analyzeSolution,
1070
+ getMovePermutations,
1071
+ invertSequence,
1072
+ simplifyMoves
684
1073
  });