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