squanlib 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,7 +70,6 @@
70
70
  "d2": "-1,5", "d2'": "1,-5",
71
71
  "K": "5,2", "K'": "-5,-2",
72
72
  "k": "2,5", "k'": "-2,-5",
73
- "A": "1,0", "A'": "-1,0",
74
73
  "G": "5,-4", "G'": "-5,4",
75
74
  "g": "4,-5", "g'": "-4,5",
76
75
  };
@@ -277,10 +276,10 @@
277
276
  * GOOD_FINISHES: moves that are acceptable as the last move
278
277
  */
279
278
  static GOOD_FINISHES = new Set([
280
- "11", "-1-1", "22", "-2-2", "2-1", "-21", "1-2", "-12",
281
- "30", "-30", "03", "0-3", "33", "3-3", "-3-3", "-33",
282
- "41", "-4-1", "14", "-1-4", "2-4", "-24", "4-2", "-42",
283
- "5-1", "-51", "-45", "-54", "63",
279
+ "1,1", "-1,-1", "2,2", "-2,-2", "2,-1", "-2,1", "1,-2", "-1,2",
280
+ "3,0", "-3,0", "0,3", "0,-3", "3,3", "3,-3", "-3,-3", "-3,3",
281
+ "4,1", "-4,-1", "1,4", "-1,-4", "2,-4", "-2,4", "4,-2", "-4,2",
282
+ "5,-1", "-5,1", "-4,5", "-5,4", "6,3",
284
283
  ]);
285
284
 
286
285
  /**
@@ -717,14 +716,6 @@
717
716
  // overrides
718
717
  if (alg in this.tempReplacements) return this.tempReplacements[alg];
719
718
 
720
- // p scrambles
721
- let isPScramble = /^p[ /\\|]/.test(alg);
722
- let startingSlice;
723
- if (isPScramble) {
724
- startingSlice = alg.charAt(1) === " " ? "/" : alg.charAt(1);
725
- alg = alg.slice(2, -3);
726
- }
727
-
728
719
  // legacy character substitutions
729
720
  alg = alg
730
721
  .replaceAll('&', '-1')
@@ -733,6 +724,17 @@
733
724
  .replaceAll('8', '-4')
734
725
  .replaceAll('7', '-5');
735
726
 
727
+ // remove potential move counts, comments
728
+ alg = alg.replaceAll(/\[.*?\]/g, "");
729
+
730
+ // p scrambles
731
+ let isPScramble = /^p[ /\\|]/.test(alg);
732
+ let startingSlice;
733
+ if (isPScramble) {
734
+ startingSlice = alg.charAt(1) === " " ? "/" : alg.charAt(1);
735
+ alg = alg.slice(2, -3);
736
+ }
737
+
736
738
  // expand move groups, e.g. "(U U')3" → "U U' U U' U U'"
737
739
  for (const group of alg.matchAll(/(\(.*?\))(\d+)/g)) {
738
740
  const inner = group[1].replaceAll(/[()]/g, '');
@@ -1038,10 +1040,22 @@
1038
1040
  // now go through scramble move by move to apply base karn
1039
1041
  let s = alg.split(" ").filter(Boolean);
1040
1042
  for (let i = 0; i < s.length; i++) {
1041
- if (i === 0 && !startsSlice) continue;
1042
- if (i === s.length - 1 && !endsSlice) break;
1043
+ if (i === 0 && !startsSlice) {
1044
+ // even if it's in base karn, we can't karnify
1045
+ s[i] = s[i].replace(",", "");
1046
+ continue;
1047
+ }
1048
+ if (i === s.length - 1 && !endsSlice) {
1049
+ // even if it's in base karn, we can't karnify
1050
+ s[i] = s[i].replace(",", "");
1051
+ break;
1052
+ }
1043
1053
  // good to replace
1044
- s[i] = SquanLib.wcaToBaseKarn[s[i]] ? SquanLib.wcaToBaseKarn[s[i]] : s[i].replace(",", "");
1054
+ let inBaseKarn = s[i] in SquanLib.wcaToBaseKarn;
1055
+ s[i] = inBaseKarn ? SquanLib.wcaToBaseKarn[s[i]] : s[i].replace(",", "");
1056
+ // prevent an additional leading slice for first move karn
1057
+ if (inBaseKarn && i === 0) startingSlice = startingSlice.replace("/", "");
1058
+ if (inBaseKarn && i === s.length - 1) endingSlice = "";
1045
1059
  }
1046
1060
 
1047
1061
  alg = startingSlice + s.join(" ") + endingSlice;
@@ -1366,16 +1380,32 @@
1366
1380
  rated = true;
1367
1381
 
1368
1382
  if (rated && ["/", "\\", "|"].includes(sliceStart)) {
1369
- // Replace the first '/' in the alg-only portion of the display line.
1370
- const slashPos = line.indexOf('/');
1371
- if (slashPos >= 0)
1372
- result.alg = line.slice(0, slashPos) + sliceStart + line.slice(slashPos + 1);
1383
+ result.alg = this.injectSliceStart(line, sliceStart);
1373
1384
  }
1374
1385
 
1375
1386
  return result;
1376
1387
  }).sort((a, b) => b.score - a.score);
1377
1388
  }
1378
1389
 
1390
+ /**
1391
+ * injectSliceStart: injects the slice start into an alg
1392
+ *
1393
+ * @param {string} alg the alg. no extra spaces allowed
1394
+ * @param {string} sliceStart " " | "/" | "\\" | "|"
1395
+ * @returns {string} the alg with slice start injected at the first slice
1396
+ */
1397
+ injectSliceStart(alg, sliceStart) {
1398
+ let moreThan1 = /[/\\| ]/.test(alg); // is there ANY slice chars?
1399
+ let firstMove = moreThan1 ? alg.match(/^([^/\\| ]*)[/\\| ]/)?.[1] : alg;
1400
+ // only tests if it's a karn
1401
+ if (firstMove in SquanLib.karnToWCA) return sliceStart + alg;
1402
+ if (!moreThan1) return alg; // no slice to inject to
1403
+
1404
+ // guaranteed to have a slice
1405
+ const slashPos = alg.search(/[/\\| ]/);
1406
+ return alg.slice(0, slashPos) + sliceStart + alg.slice(slashPos + 1);
1407
+ }
1408
+
1379
1409
  // =========================================================================
1380
1410
  // SECTION 8: ALG TRANSFORM
1381
1411
  // =========================================================================
@@ -1396,28 +1426,38 @@
1396
1426
  /**
1397
1427
  * compl: get the complement of a move
1398
1428
  *
1399
- * @param {string} a a move without commas, e.g. "-12"
1400
- * @returns {string} the complement move
1401
- * @example "-12" → "5-4"
1429
+ * @param {string} a a move
1430
+ * @returns {string} the complement move with commas
1431
+ * @example "-12" → "5,-4"; "-1,2" → "5,-4"
1402
1432
  */
1403
1433
  compl(a) {
1404
1434
  if (!a) return a;
1405
- const inx = this.sepIndex(a);
1406
- return String(this.legalMove(6 + parseInt(a.slice(0, inx), 10))) +
1407
- String(this.legalMove(6 + parseInt(a.slice(inx), 10)));
1435
+ let u, d;
1436
+ if (a.includes(',')) [u, d] = a.split(",");
1437
+ else {
1438
+ const inx = this.sepIndex(a);
1439
+ [u, d] = [a.slice(0, inx), a.slice(inx)];
1440
+ }
1441
+ return String(this.legalMove(6 + parseInt(u, 10))) + "," +
1442
+ String(this.legalMove(6 + parseInt(d, 10)));
1408
1443
  }
1409
1444
 
1410
1445
  /**
1411
1446
  * lf: get the layer flip of a move
1412
1447
  *
1413
- * @param {string} a a move without commas, e.g. "-12"
1448
+ * @param {string} a a move
1414
1449
  * @returns {string} the layer flip move
1415
- * @example "-12" → "2-1"
1450
+ * @example "-12" → "2,-1"; "-1,2" → "2,-1"
1416
1451
  */
1417
1452
  lf(a) {
1418
1453
  if (!a) return a;
1419
- const inx = this.sepIndex(a);
1420
- return a.slice(inx) + a.slice(0, inx);
1454
+ let u, d;
1455
+ if (a.includes(',')) [u, d] = a.split(",");
1456
+ else {
1457
+ const inx = this.sepIndex(a);
1458
+ [u, d] = [a.slice(0, inx), a.slice(inx)];
1459
+ }
1460
+ return d + "," + u;
1421
1461
  }
1422
1462
 
1423
1463
  /**
@@ -1430,11 +1470,11 @@
1430
1470
  compact(algIn) {
1431
1471
  let alg = algIn
1432
1472
  .replace(/\[.*?\]/g, "")
1433
- .replace(/[()]/g, "")
1434
- .replaceAll(" ", "").trim();
1473
+ .replace(/[()]/g, "").trim();
1435
1474
  if (this.isKarn(alg)) {
1436
1475
  const numeric = this.unkarnify(alg);
1437
- return numeric.split("/").filter(Boolean).map(m => {
1476
+ return numeric.split("/").map(m => {
1477
+ if (!m) return m;
1438
1478
  if (!m.includes(","))
1439
1479
  throw new Error(
1440
1480
  `algToInternal: m doesn't have commas post karnifying: ${m}`
@@ -1444,7 +1484,7 @@
1444
1484
  String(this.legalMove(parseInt(d, 10)));
1445
1485
  }).join(" ");
1446
1486
  }
1447
- alg = alg.trim();
1487
+ alg = alg.replaceAll(" ", "");
1448
1488
  if (alg.includes("/")) {
1449
1489
  return alg.split("/").filter(Boolean).map(m => {
1450
1490
  if (!m.includes(",")) m = this.addCommas(m);
@@ -1473,7 +1513,8 @@
1473
1513
  * @returns {number} how many positions the alg can y2 at
1474
1514
  */
1475
1515
  countY2Positions(algIn) {
1476
- const segs = this.compact(algIn).split(" ").filter(p => p);
1516
+ // spaces ARE slices, cannot trim or do anything like that
1517
+ const segs = this.compact(algIn).split(" ");
1477
1518
  return Math.max(0, segs.length - 3);
1478
1519
  }
1479
1520
 
@@ -1625,7 +1666,7 @@
1625
1666
  isOBLCase(l, target) {
1626
1667
  const targetPattern = Object.entries(SquanLib.OBLToEnglish)
1627
1668
  .find(([, v]) => v === target
1628
- )?.[0];
1669
+ )?.[0];
1629
1670
  if (!targetPattern) return false;
1630
1671
  // to corner first
1631
1672
  if (l[0] !== l[0].toUpperCase()) l = this.shift(l, -1);
@@ -1,2 +1,2 @@
1
1
  /*! squanlib | GPL-3.0-or-later | https://github.com/Mattttttttttttttttttttttttttttttt/squan-lib */
2
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).squanlib=e()}(this,function(){"use strict";class t{static karnToWCA={U4:"U U' U U'","U4'":"U' U U' U",D4:"D D' D D'","D4'":"D' D D' D",u4:"u u' u u'","u4'":"u' u u' u",d4:"d d' d d'","d4'":"d' d d' d",U3:"U U' U","U3'":"U' U U'",D3:"D D' D","D3'":"D' D D'",u3:"u u' u","u3'":"u' u u'",d3:"d d' d","d3'":"d' d d'",F3:"F F' F","F3'":"F' F F'",f3:"f f' f","f3'":"f' f f'",W:"U U'","W'":"U' U",B:"D D'","B'":"D' D",w:"u u'","w'":"u' u",b:"d d'","b'":"d' d",F2:"F F'","F2'":"F' F",f2:"f f'","f2'":"f' f",UU:"U U","UU'":"U' U'",DD:"D D","DD'":"D' D'",T2:"T T'","T2'":"T' T",t2:"t t'","t2'":"t' t",E2:"E E'","E2'":"E' E","ɇ":"U D","ɇ'":"U' D'","Ɇ":"U D'","Ɇ'":"U' D",U2:"6,0","U2'":"6,0",D2:"0,6",U2D:"6,3","U2D'":"6,-3","U2'D":"6,3","U2'D'":"6,-3",U2D2:"6,6",UD2:"3,6","U'D2":"-3,6",U:"3,0","U'":"-3,0",D:"0,3","D'":"0,-3",E:"3,-3","E'":"-3,3",e:"3,3","e'":"-3,-3",u:"2,-1","u'":"-2,1",d:"-1,2","d'":"1,-2",F:"4,1","F'":"-4,-1",f:"1,4","f'":"-1,-4",T:"2,-4","T'":"-2,4",t:"4,-2","t'":"-4,2",m:"2,2","m'":"-2,-2",M:"1,1","M'":"-1,-1",u2:"5,-1","u2'":"-5,1",d2:"-1,5","d2'":"1,-5",K:"5,2","K'":"-5,-2",k:"2,5","k'":"-2,-5",A:"1,0","A'":"-1,0",G:"5,-4","G'":"-5,4",g:"4,-5","g'":"-4,5"};static shorthandToKarn={bjj:"U' e D'",fjj:"U e' D",e2bjj:"U' e' U'",e2fjj:"U e U",nn:"E E'",jn:"D4'",nj:"U4",jj:"U e' D","bjj+e2":"U' e' U'","-nn":"E' E","-jn":"D4","-nj":"D4'",bpj10:"d m' U","bpj0-1":"u' m D'",fpj10:"u m' D","fpj0-1":"d' m U'",aa10:"u m' u T'","aa0-1":"U m' U t'",fadj10:"D M' d'",dadj10:"D M' d'","fadj0-1":"U' M u","u'adj0-1":"U' M u",badj10:"U M' u'",uadj10:"U M' u'","badj0-1":"D' M d","d'adj0-1":"D' M d",bb10:"T u' e U'","bb0-1":"t d e' D",fdd10:"D e' d t","fdd0-1":"U' e u' T",bdd10:"U e' u T'","bdd0-1":"D' e d' t'",ff10:"d m' d M E","ff0-1":"u' m U' M T",fv10:"d4","fv0-1":"d4'",vf10:"u4","vf0-1":"u4'",y2fv10:"u d' u -5,4",jf10:"w D' u T'","jf0-1":"w' D u' T",fj10:"b U' d t","fj0-1":"b' U d' t'",jr00:"e' w e",jr10:"e' b e","jr0-1":"e' w' e","jr1-1":"e' b' e",rj00:"e b' e'",rj10:"e w e'","rj0-1":"e b' e'","rj1-1":"e w e'",jv10:"b D d d2'","jv0-1":"b' D' d' d2",vj10:"w U u u2'","vj0-1":"w' U' u' u2",kk10:"u m' U E'","kk0-1":"U m' u E'",opp10:"u2 u2'","opp0-1":"u2' u2",pn10:"T T'","pn0-1":"t t'",px10:"f' d3' f'","px0-1":"f d3 f",xp10:"F' u3' F'","xp0-1":"F u3 F",tt10:"d m' F' u2'",fss10:"u M D' E'","fss0-1":"D' M u E'",bss10:"D M' u' E","bss0-1":"U' M d E",vv10:"u M u m' E'",zz10:"u M t' M D'","zz0-1":"D' M t' M u","30adj10":"U M' u'","-30adj0-1":"U' M u","03adj10":"D M' d'",obopp00:"1,0/M' F M' F M'/0,1","oaopp1-1":"0,1/M' u' M' u' M'/0,1",but00:"",also00:"","done!00":"0,0"};static alignmentIndependent=new Set(["bjj","fjj","nn","jn","nj","e2bjj","e2fjj","jj","bjj+e2","-nn","-jn","-nj"]);static wcaToBaseKarn={"6,0":"U2","6,3":"U2D","6,-3":"U2D'","6,6":"U2D2","0,6":"D2","3,6":"UD2","-3,6":"U'D2","3,0":"U","-3,0":"U'","0,3":"D","0,-3":"D'","3,-3":"E","-3,3":"E'","3,3":"e","-3,-3":"e'","2,-1":"u","-2,1":"u'","-1,2":"d","1,-2":"d'","4,1":"F","-4,-1":"F'","1,4":"f","-1,-4":"f'","2,-4":"T","-2,4":"T'","4,-2":"t","-4,2":"t'","2,2":"m","-2,-2":"m'","1,1":"M","-1,-1":"M'","5,-1":"u2","-5,1":"u2'","-1,5":"d2","1,-5":"d2'","5,2":"K","-5,-2":"K'","2,5":"k","-2,-5":"k'"};static baseKarnToHighKarn={"U U' U U'":"U4","U' U U' U":"U4'","D D' D D'":"D4","D' D D' D":"D4'","u u' u u'":"u4","u' u u' u":"u4'","d d' d d'":"d4","d' d d' d":"d4'","U U' U":"U3","U' U U'":"U3'","D D' D":"D3","D' D D'":"D3'","u u' u":"u3","u' u u'":"u3'","d d' d":"d3","d' d d'":"d3'","F F' F":"F3","F' F F'":"F3'","f f' f":"f3","f' f f'":"f3'","U U'":"W","U' U":"W'","D D'":"B","D' D":"B'","u u'":"w","u' u":"w'","d d'":"b","d' d":"b'","F F'":"F2","F' F":"F2'","f f'":"f2","f' f":"f2'","U U":"UU","U' U'":"UU'","D D":"DD","D' D'":"DD'"};static A_MOVES=[[3,0],[-3,0],[0,3],[0,-3],[3,3],[2,-1],[-1,2],[-4,-1],[-1,-4],[2,-4],[2,2],[-1,-1],[5,-1]];static a_MOVES=[[3,0],[-3,0],[0,3],[0,-3],[3,3],[-2,1],[1,-2],[4,1],[1,4],[-2,4],[-2,-2],[1,1],[-5,1]];static OPTIM={"/0,0/":"","/3,3/3,3/":"-3,-3/-3,-3","/-3,-3/-3,-3/":"3,3/3,3","/2,2/-2,-2/":"2,2/-2,-2","/-2,-2/2,2/":"-2,-2/2,2","/1,1/-1,-1/":"1,1/-1,-1","/-1,-1/1,1/":"-1,-1/1,1","/2,-4/-2,4/2,-4/":"2,-4/-2,4/2,-4","/-2,4/2,-4/-2,4/":"-2,4/2,-4/-2,4","/5,-1/-5,1/5,-1/":"5,-1/-5,1/5,-1","/-5,1/5,-1/-5,1/":"-5,1/5,-1/-5,1"};static CLOSEST_MAP=new Map([[-5,-6],[-4,-3],[-3,-3],[-2,-3],[-1,0],[0,0],[1,0],[2,3],[3,3],[4,3],[5,6],[6,6]]);static MOVE_VALUES=new Map([["A/0,3",16],["A/0,6",1],["A/0,-3",18],["A/3,0",16],["A/3,3",12],["A/3,6",0],["A/3,-3",13],["A/6,0",12],["A/6,3",11],["A/6,6",2],["A/6,-3",12],["A/-3,0",9],["A/-3,3",13],["A/-3,6",4],["A/-3,-3",12],["A\\0,3",17],["A\\0,6",1],["A\\0,-3",8],["A\\3,0",6],["A\\3,3",14],["A\\3,6",1],["A\\3,-3",12],["A\\6,0",14],["A\\6,3",11],["A\\6,6",5],["A\\6,-3",8],["A\\-3,0",11],["A\\-3,3",14],["A\\-3,6",6],["A\\-3,-3",9],["a/0,3",5],["a/0,6",5],["a/0,-3",12],["a/3,0",17],["a/3,3",10],["a/3,6",5],["a/3,-3",7],["a/6,0",4],["a/6,3",2],["a/6,6",0],["a/6,-3",3],["a/-3,0",18],["a/-3,3",12],["a/-3,6",7],["a/-3,-3",11],["a\\0,3",5],["a\\0,6",5],["a\\0,-3",5],["a\\3,0",16],["a\\3,3",11],["a\\3,6",4],["a\\3,-3",6],["a\\6,0",4],["a\\6,3",2],["a\\6,6",0],["a\\6,-3",1],["a\\-3,0",15],["a\\-3,3",10],["a\\-3,6",2],["a\\-3,-3",5],["/1,-2",4],["\\1,-2",17],["/-1,2",15],["\\-1,2",14],["/1,-5",3],["\\1,-5",1],["/-1,5",8],["\\-1,5",3],["/1,4",7],["\\1,4",14],["/-1,-4",12],["\\-1,-4",9],["/1,1",11],["\\1,1",20],["/-1,-1",20],["\\-1,-1",10],["/2,-1",20],["\\2,-1",12],["/-2,1",14],["\\-2,1",18],["/2,2",12],["\\2,2",13],["/-2,-2",14],["\\-2,-2",8],["/2,5",5],["\\2,5",3],["/-2,-5",4],["\\-2,-5",3],["/2,-4",14],["\\2,-4",6],["/-2,4",13],["\\-2,4",13],["/4,4",5],["\\4,4",12],["/-4,-4",12],["\\-4,-4",4],["/4,1",6],["\\4,1",13],["/-4,-1",16],["\\-4,-1",6],["/4,-2",12],["\\4,-2",9],["/-4,2",16],["\\-4,2",13],["/4,-5",2],["\\4,-5",5],["/-4,5",13],["\\-4,5",3],["/5,5",1],["\\5,5",4],["/-5,-5",2],["\\-5,-5",0],["/5,2",6],["\\5,2",10],["/-5,-2",12],["\\-5,-2",13],["/5,-1",11],["\\5,-1",7],["/-5,1",14],["\\-5,1",15],["/5,-4",2],["\\5,-4",2],["/-5,4",12],["\\-5,4",14]]);static GOOD_FINISHES=new Set(["11","-1-1","22","-2-2","2-1","-21","1-2","-12","30","-30","03","0-3","33","3-3","-3-3","-33","41","-4-1","14","-1-4","2-4","-24","4-2","-42","5-1","-51","-45","-54","63"]);static OBLToEnglish={BBbBBbBBbBBb:"solved",BBwWWwWWwWWw:"1c",BBwBBwWWwWWw:"cadj",BBwWWwBBwWWw:"copp",BBwBBwBBwWWw:"3c",BBwBBwBBwBBw:"4e",WWbWWbWWbWWw:"3e",WWbWWwWWbWWw:"line",WWbWWbWWwWWw:"L",WWbWWwWWwWWw:"1e",WWbBBwWWwWWw:"left pair",BBbWWwWWwWWw:"right pair",BBwWWwWWbWWw:"left arrow",BBwWWbWWwWWw:"right arrow",WWbBBbWWwWWw:"gem",WWwWWbWWbBBw:"left knight",BBbWWbWWwWWw:"right knight",WWwWWbWWwBBb:"left axe",BBwWWbWWwWWb:"right axe",BBwWWbWWbWWw:"squid",WWwWWbBBbWWb:"left thumb",WWbBBbWWwWWb:"right thumb",WWwBBbWWbWWb:"left bunny",WWbWWbBBwWWb:"right bunny",BBbBBwWWwWWw:"shell",BBwWWwWWbBBw:"left bird",BBwBBbWWwWWw:"right bird",BBwWWbWWwBBw:"hazard",BBbBBbWWwWWw:"left kite",WWwWWbBBbBBw:"right kite",BBwBBwWWbWWb:"left cut",BBwBBbWWbWWw:"right cut",BBbBBwWWbWWw:"black T",WWwWWbBBwBBb:"white T",WWbBBwWWbBBw:"left N",WWwBBbWWwBBb:"right N",WWbBBbWWwBBw:"black tie",BBwWWwBBbWWb:"white tie",BBbWWwBBwWWw:"left yoshi",WWwBBwWWbBBw:"right yoshi"};static OBLToState=Object.fromEntries(Object.entries(this.OBLToEnglish).map(([t,e])=>[e,t]));static NAMING={solved:"O","1c":"D",cadj:"J",copp:"V","3c":"M","4e":"Q","3e":"W",line:"F",L:"L","1e":"E","left pair":"Pw","right pair":"Pc","left arrow":"Aw","right arrow":"Ac",gem:"G","left knight":"Hw","right knight":"Hc","left axe":"Xc","right axe":"Xw",squid:"S","left thumb":"THw","right thumb":"THc","left bunny":"Uc","right bunny":"Uw",shell:"SH","left bird":"Bc","right bird":"Bw",hazard:"Z","left kite":"Kc","right kite":"Kw","left cut":"Cw","right cut":"Cc","black T":"Tu","white T":"Td","left N":"Nw","right N":"Nc","black tie":"Iu","white tie":"Id","left yoshi":"Yc","right yoshi":"Yw"};static OBL_ANGLES={solved:"-","1c":"UR",cadj:"R",copp:"/","3c":"DR","4e":"-","3e":"D",line:"—",L:"DR","1e":"R","left pair":"DR","right pair":"UR","left arrow":"UR","right arrow":"UR",gem:"DR","left knight":"L","right knight":"R","left axe":"L","right axe":"R",squid:"UR","left thumb":"DL","right thumb":"DR","left bunny":"DR","right bunny":"DL",shell:"R","left bird":"R","right bird":"U",hazard:"U","left kite":"R","right kite":"L","left cut":"R","right cut":"R","black T":"R","white T":"R","left N":"\\","right N":"\\","black tie":"DR","white tie":"DR","left yoshi":"UL","right yoshi":"UR"};static nextAngle={"-":"-","/":"\\","\\":"/","—":"|","|":"—",U:"R",R:"D",D:"L",L:"U",UR:"DR",DR:"DL",DL:"UL",UL:"UR"};static get HALF_L(){return 6}static get LAYERL(){return 12}static get THREE_FOUR_L(){return 18}static get CUBEL(){return 24}static get SOLVED(){return"bBBbBBbBBbBBwWWwWWwWWwWW"}static POSSIBLE_OBL=[["","solved","solved"],["","1c","1c"],["","cadj","cadj"],["","cadj","copp"],["","copp","copp"],["","3c","3c"],["","4e","4e"],["","3e","3e"],["","line","line"],["","L","line"],["","L","L"],["","1e","1e"],["good","pair","pair"],["bad","pair","pair"],["good","arrow","pair"],["bad","arrow","pair"],["good","arrow","arrow"],["bad","arrow","arrow"],["","gem","gem"],["","gem","knight"],["","gem","axe"],["","gem","squid"],["good","knight","knight"],["bad","knight","knight"],["good","knight","axe"],["bad","knight","axe"],["same","axe","axe"],["diff","axe","axe"],["","squid","knight"],["","squid","axe"],["","squid","squid"],["good","thumb","thumb"],["bad","thumb","thumb"],["good","thumb","bunny"],["bad","thumb","bunny"],["good","bunny","bunny"],["bad","bunny","bunny"],["","shell","shell"],["","shell","bird"],["","shell","hazard"],["","yoshi","shell"],["good","bird","bird"],["bad","bird","bird"],["","bird","hazard"],["","hazard","hazard"],["good","yoshi","bird"],["bad","yoshi","bird"],["","yoshi","hazard"],["same","yoshi","yoshi"],["diff","yoshi","yoshi"],["good","kite","kite"],["bad","kite","kite"],["good","kite","cut"],["bad","kite","cut"],["","kite","T"],["good","kite","N"],["bad","kite","N"],["","kite","tie"],["","cut","T"],["good","cut","N"],["bad","cut","N"],["","cut","tie"],["good","cut","cut"],["bad","cut","cut"],["good","T","T"],["bad","T","T"],["","T","N"],["good","T","tie"],["bad","T","tie"],["good","N","N"],["bad","N","N"],["","tie","N"],["good","tie","tie"],["bad","tie","tie"]];static OBL_LEN={"solved/solved":0,"1c/1c":5,"cadj/cadj":4,"cadj/copp":5,"copp/copp":2,"3c/3c":5,"4e/4e":4,"3e/3e":5,"line/line":2,"L/line":5,"L/L":4,"1e/1e":5,"good pair/pair":2,"bad pair/pair":4,"good arrow/pair":3,"bad arrow/pair":4,"good arrow/arrow":3,"bad arrow/arrow":4,"gem/gem":4,"gem/knight":4,"gem/axe":3,"gem/squid":4,"good knight/knight":4,"bad knight/knight":5,"good knight/axe":3,"bad knight/axe":4,"same axe/axe":5,"diff axe/axe":5,"squid/knight":4,"squid/axe":4,"squid/squid":5,"good thumb/thumb":2,"bad thumb/thumb":5,"good thumb/bunny":4,"bad thumb/bunny":4,"good bunny/bunny":3,"bad bunny/bunny":5,"shell/shell":4,"shell/bird":4,"shell/hazard":4,"yoshi/shell":3,"good bird/bird":4,"bad bird/bird":5,"bird/hazard":4,"hazard/hazard":5,"good yoshi/bird":3,"bad yoshi/bird":4,"yoshi/hazard":4,"same yoshi/yoshi":5,"diff yoshi/yoshi":5,"good kite/kite":1,"bad kite/kite":5,"good kite/cut":3,"bad kite/cut":6,"kite/T":4,"good kite/N":3,"bad kite/N":4,"kite/tie":4,"cut/T":4,"good cut/N":4,"bad cut/N":5,"cut/tie":4,"good cut/cut":3,"bad cut/cut":6,"good T/T":3,"bad T/T":4,"T/N":5,"good T/tie":3,"bad T/tie":4,"good N/N":2,"bad N/N":4,"tie/N":5,"good tie/tie":3,"bad tie/tie":4};static OBL_TRANSLATION={"solved/solved":["solved/solved"],"1c/1c":["1c/1c"],"cadj/cadj":["cadj/cadj"],"cadj/copp":["cadj/copp"],"copp/copp":["copp/copp"],"3c/3c":["3c/3c"],"4e/4e":["4e/4e"],"3e/3e":["3e/3e"],"line/line":["line/line"],"L/line":["L/line"],"L/L":["L/L"],"1e/1e":["1e/1e"],"good pair/pair":["left pair/left pair","right pair/right pair"],"bad pair/pair":["left pair/right pair"],"good arrow/pair":["left arrow/right pair","right arrow/left pair"],"bad arrow/pair":["left arrow/left pair","right arrow/right pair"],"good arrow/arrow":["left arrow/left arrow","right arrow/right arrow"],"bad arrow/arrow":["left arrow/right arrow"],"gem/gem":["gem/gem"],"gem/knight":["gem/left knight","gem/right knight"],"gem/axe":["gem/left axe","gem/right axe"],"gem/squid":["gem/squid"],"good knight/knight":["left knight/right knight"],"bad knight/knight":["left knight/left knight","right knight/right knight"],"good knight/axe":["left knight/left axe","right knight/right axe"],"bad knight/axe":["left knight/right axe","right knight/left axe"],"same axe/axe":["left axe/left axe","right axe/right axe"],"diff axe/axe":["left axe/right axe"],"squid/knight":["squid/left knight","squid/right knight"],"squid/axe":["squid/left axe","squid/right axe"],"squid/squid":["squid/squid"],"good thumb/thumb":["left thumb/left thumb","right thumb/right thumb"],"bad thumb/thumb":["left thumb/right thumb"],"good thumb/bunny":["left thumb/right bunny","right thumb/left bunny"],"bad thumb/bunny":["left thumb/left bunny","right thumb/right bunny"],"good bunny/bunny":["left bunny/left bunny","right bunny/right bunny"],"bad bunny/bunny":["left bunny/right bunny"],"shell/shell":["shell/shell"],"shell/bird":["shell/left bird","shell/right bird"],"shell/hazard":["shell/hazard"],"yoshi/shell":["left yoshi/shell","right yoshi/shell"],"good bird/bird":["left bird/right bird"],"bad bird/bird":["left bird/left bird","right bird/right bird"],"bird/hazard":["left bird/hazard","right bird/hazard"],"hazard/hazard":["hazard/hazard"],"good yoshi/bird":["left yoshi/left bird","right yoshi/right bird"],"bad yoshi/bird":["left yoshi/right bird","right yoshi/left bird"],"yoshi/hazard":["left yoshi/hazard","right yoshi/hazard"],"same yoshi/yoshi":["left yoshi/left yoshi","right yoshi/right yoshi"],"diff yoshi/yoshi":["left yoshi/right yoshi"],"good kite/kite":["left kite/left kite","right kite/right kite"],"bad kite/kite":["left kite/right kite"],"good kite/cut":["left kite/left cut","right kite/right cut"],"bad kite/cut":["left kite/right cut","right kite/left cut"],"kite/T":["left kite/black T","left kite/white T","right kite/black T","right kite/white T"],"good kite/N":["left kite/right N","right kite/left N"],"bad kite/N":["left kite/left N","right kite/right N"],"kite/tie":["left kite/black tie","left kite/white tie","right kite/black tie","right kite/white tie"],"cut/T":["left cut/black T","left cut/white T","right cut/black T","right cut/white T"],"good cut/N":["left cut/left N","right cut/right N"],"bad cut/N":["left cut/right N","right cut/left N"],"cut/tie":["left cut/black tie","left cut/white tie","right cut/black tie","right cut/white tie"],"good cut/cut":["left cut/left cut","right cut/right cut"],"bad cut/cut":["left cut/right cut"],"good T/T":["black T/black T","white T/white T"],"bad T/T":["black T/white T"],"T/N":["black T/left N","black T/right N","white T/left N","white T/right N"],"good T/tie":["black T/black tie","white T/white tie"],"bad T/tie":["black T/white tie","white T/black tie"],"good N/N":["left N/left N","right N/right N"],"bad N/N":["left N/right N"],"tie/N":["black tie/left N","black tie/right N","white tie/left N","white tie/right N"],"good tie/tie":["black tie/black tie","white tie/white tie"],"bad tie/tie":["black tie/white tie"]};static CORNERS=[[""],["1","3","5","7"],["13","15","17","35","37","57"],["135","137","157","357"],["1357"]];static EDGES=[[""],["2","4","6","8"],["24","26","28","46","48","68"],["246","248","268","468"],["2468"]];static TOTAL_CORNERS=["","1","3","5","7","13","15","17","35","37","57","135","137","157","357","1357"];static TOTAL_EDGES=["","2","4","6","8","24","26","28","46","48","68","246","248","268","468","2468"];constructor(t={"meow :3":"meow :3"}){this.tempReplacements={...t}}setTempReplacements(t){return this.tempReplacements={...t},this}addTempReplacements(t){return Object.assign(this.tempReplacements,t),this}dictReplace(t,e){const i=new RegExp(Object.keys(e).map(t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|"),"g");let r;do{r=t,t=t.replace(i,t=>e[t])}while(t!==r);return t}addCommas(t){return t.split(/[/\\| ]/).map(t=>{if(!t||isNaN(Number(t.replaceAll("-","")))||t.includes(","))return t;switch(t.length){case 1:return t+",0";case 2:return"-"===t.charAt(0)?t+",0":t[0]+","+t[1];case 3:return"-"===t.charAt(0)?t.slice(0,2)+","+t[2]:t[0]+","+t.slice(1);case 4:return t.slice(0,2)+","+t.slice(2);default:throw new Error(`"${t}" is not a valid karn numeric move`)}}).join(" ")}isKarn(t){return/[a-zA-Z]/.test(t)}getAlignmentMove(t,e){return(t?"1":"0")+(e?"-1":"0")}getAlignment(t){if(!t)return{topA:!1,bottomA:!1};if(!(t=this.addCommas(t)).includes(","))throw new Error("getAlignment: move is weird: "+t);const[e,i]=t.split(",");return{topA:"0"!==e,bottomA:"0"!==i}}unkarnifyHelp(e){if(e=(e=e.trim().replaceAll(/[()]/g,"")).replaceAll(/ ([\/\\\|]) /g,"$1"),/[\/\\\|]{2,}/.test(e))throw new Error("unkarnifyHelp: Two slices in a row.");if(!this.isKarn(e))return e;let i,r;/[/\\| ]/.test(e)?(i=e.match(/^([^/\\| ]*)[/\\| ]/)?.[1],r=e.match(/[/\\| ]([^/\\| ]*)$/)?.[1]):i=r=e;let a=["/","\\","|"].includes(e.charAt(0))?e.charAt(0):i in t.karnToWCA?"/":"",n="/"===e.at(-1)||r in t.karnToWCA?"/":"";e=e.replaceAll(/[/\\| ]+/g," ");let s=(e=this.addCommas(e)).split(" ").filter(Boolean);for(let e=0;e<s.length;e++)s[e]in t.karnToWCA&&(s[e]=t.karnToWCA[s[e]].split(" "));s=s.flat();for(let e=0;e<s.length;e++)s[e]in t.karnToWCA&&(s[e]=t.karnToWCA[s[e]]);if(e=(e=a+s.join("/")+n).replaceAll(/ +/g,""),/[\/\\\|]{2,}/.test(e))throw new Error("unkarnifyHelp: Two slices in a row post-replacements.");return e}unkarnify(t){if(t in this.tempReplacements)return this.tempReplacements[t];let e,i=/^p[ /\\|]/.test(t);i&&(e=" "===t.charAt(1)?"/":t.charAt(1),t=t.slice(2,-3)),t=t.replaceAll("&","-1").replaceAll("^","-2").replaceAll("9","-3").replaceAll("8","-4").replaceAll("7","-5");for(const e of t.matchAll(/(\(.*?\))(\d+)/g)){const i=e[1].replaceAll(/[()]/g,""),r=parseInt(e[2],10);t=t.replace(e[0],Array(r).fill(i).join(" "))}let r=this.replaceShorthands(this.unkarnifyHelp(t));return i&&(["/","\\","|"].includes(r.charAt(0))&&(r=r.slice(1)),r="p"+e+r+"/p'"),r=r.replaceAll(/\/+/g,"/"),r}replaceShorthands(e){const i=e.split(/[\/\\\|]/);if(i.every(e=>!e||!this.isKarn(e)||" "+e+" "in t.karnToWCA))return this.unkarnifyHelp(e);let r=!1,a=!1;for(const n of i)if(n)if(n.includes(",")){const[t,e]=n.split(",");parseInt(t,10)%3!=0&&(r=!r),parseInt(e,10)%3!=0&&(a=!a)}else{const i=t.alignmentIndependent.has(n.toLowerCase())?n.toLowerCase():n.toLowerCase()+this.getAlignmentMove(r,a),s=t.shorthandToKarn[i];if(void 0===s)throw new Error(`replaceShorthands: "${n}" with alignment ${this.getAlignmentMove(r,a)} is not defined.`);e=e.replace(n,s);for(const t of this.unkarnifyHelp(s).split("/")){if(!t)continue;const[e,i]=t.split(",");parseInt(e,10)%3!=0&&(r=!r),parseInt(i,10)%3!=0&&(a=!a)}}return this.unkarnifyHelp(e)}parseScramble(t){const e=[],i=t.replace(/[\/\\\|]/g," / ").trim().split(/\s+/).filter(Boolean);for(let t of i)if(t.startsWith("p"))e.push({type:"turn",top:0,bottom:0});else if("/"===t)e.push({type:"twist"});else{if(t=this.addCommas(t.replace(/[()]/g,"")),!t.includes(","))throw new Error(`parseScramble: move: ${t} is weird.`);const[i,r]=t.split(",").map(t=>parseInt(t.trim(),10));isNaN(i)||isNaN(r)||e.push({type:"turn",top:i,bottom:r})}return e}twist(t,e){return{tlHex:t.slice(0,6)+e.slice(0,6),blHex:t.slice(6)+e.slice(6)}}doSlice(e){const[i,r,a,n]=[e.slice(0,t.HALF_L),e.slice(t.HALF_L,t.LAYERL),e.slice(t.LAYERL,t.THREE_FOUR_L),e.slice(t.THREE_FOUR_L,t.CUBEL)],s=t=>t===t.toUpperCase();if(![i,r,a,n].map(t=>!s(t.at(0))||s(t.at(1))&&!s(t.at(-1))||s(t.at(-2))).every(Boolean))throw new Error("doSlice: unsliceable position encountered");return a+r+i+n}algToHex(t){let e="011233455677",i="998bbaddcffe";for(const r of this.parseScramble(this.unkarnify(t)))"twist"===r.type?({tlHex:e,blHex:i}=this.twist(e,i)):(e=this.shift(e,-r.top),i=this.shift(i,-r.bottom));return{tlHex:e,blHex:i}}doMoves(e,i){void 0===i&&(i=t.SOLVED);for(const t of this.unkarnify(e).split("/")){const e=t.trim();if(""!==e){const[t,r]=e.split(",").map(Number);i=this.moveCube(i,t,r)}i=this.doSlice(i)}return this.doSlice(i)}moveCube(e,i,r){return this.shift(e.slice(0,t.LAYERL),i)+this.shift(e.slice(t.LAYERL),r)}invertScramble(t){return t?this.unkarnify(t).trim().split("/").reverse().map(t=>{const e=(t=t.trim()).includes("(")?t.match(/\(([^)]+)\)/)?.[1]:t.includes(",")?t:null;if(!e)return t;const i=e.split(",").map(t=>{const e=parseInt(t.trim(),10);return isNaN(e)?t.trim():String(-e)}).join(",");return t.includes("(")?`(${i})`:i}).join("/"):t}isPBL(t){let{tlHex:e,blHex:i}=t,r=[...e],a=[...i];return r[1]===r[2]&&r[4]===r[5]&&r[7]===r[8]&&r[10]===r[11]&&(parseInt(r[0],10)%2==0&&parseInt(r[1],10)%2==1&&parseInt(r[3],10)%2==0&&parseInt(r[4],10)%2==1&&parseInt(r[6],10)%2==0&&parseInt(r[7],10)%2==1&&parseInt(r[9],10)%2==0&&parseInt(r[10],10)%2==1&&(!!(r.includes("0")&&r.includes("1")&&r.includes("2")&&r.includes("3")&&r.includes("4")&&r.includes("5")&&r.includes("6")&&r.includes("7"))&&(a[0]===a[1]&&a[3]===a[4]&&a[6]===a[7]&&a[9]===a[10]&&(parseInt(a[0],16)%2==1&&parseInt(a[2],16)%2==0&&parseInt(a[3],16)%2==1&&parseInt(a[5],16)%2==0&&parseInt(a[6],16)%2==1&&parseInt(a[8],16)%2==0&&parseInt(a[9],16)%2==1&&parseInt(a[11],16)%2==0&&!!(a.includes("8")&&a.includes("9")&&a.includes("a")&&a.includes("b")&&a.includes("c")&&a.includes("d")&&a.includes("e")&&a.includes("f"))))))}karnify(e){if(e=e.trim(),/[\/\\\|]{2,}/.test(e))throw new Error("karnify: Two slices in a row.");if(this.isKarn(e))throw new Error("karnify: Alg has letters. Try unkarnifying first.");let i=["/","\\","|"].includes(e.charAt(0)),r=i?e.charAt(0):"",a="/"===e.at(-1),n=a?"/":"",s=(e=e.replaceAll(/[/\\| ]+/g," ")).split(" ").filter(Boolean);for(let e=0;e<s.length;e++)if(0!==e||i){if(e===s.length-1&&!a)break;s[e]=t.wcaToBaseKarn[s[e]]?t.wcaToBaseKarn[s[e]]:s[e].replace(",","")}return e=r+s.join(" ")+n,e=this.dictReplace(e,t.baseKarnToHighKarn)}legalMove(t){return(t%=12)<-5?t+12:t>6?t-12:t}addMoves(t,e){if(!t&&!e)throw new Error("addMoves: both moves are empty.");if(!t)return e;if(!e)return t;const i={A:"a",a:"A"};if(t in i&&e in i)throw new Error("addMoves: both moves cannot be alignment markers.");if(t in i){const r=parseInt(e.split(",")[0],10);return this.changesAlignment(r)?i[t]:t}if(e in i){const r=parseInt(t.split(",")[0],10);return this.changesAlignment(r)?i[e]:e}const[r,a]=t.split(",").map(Number),[n,s]=e.split(",").map(Number);return`${this.legalMove(r+n)},${this.legalMove(a+s)}`}changesAlignment(t){return t%3!=0}optimize(e){const i=Object.keys(t.OPTIM);for(;this.dictReplace(e,t.OPTIM)!==e;){const r=e.split("/").map(t=>t.trim());let a=0,n=!1;for(let s=0;s<e.length&&!n;s++)if("/"===e[s]){a++;for(const l of i)if(!(e.length-1-s<l.length)&&e.slice(s,s+l.length)===l){if("/0,0/"===l)r[a-1]=this.addMoves(r[a-1],r[a+1]),r.splice(a,2);else{const e=l.split("/").length,i=t.OPTIM[l].split("/"),n=e-2;r[a-1]=this.addMoves(r[a-1],i.shift()),r[a+e-2]=this.addMoves(r[a+e-2],i.pop()),r.splice(a,n,...i)}e=r.join("/"),n=!0;break}}}return e}getMoveValue(e,i,r){let a=r.indexOf(",");if(-1===a&&(a=this.addCommas(r).indexOf(","),-1===a))throw new Error(`getMoveValue: move: ${r} is weird`);const n=i?"/":"\\";let s;return s=parseInt(r.slice(0,a),10)%3==0?(e?"A":"a")+n+r:n+r,t.MOVE_VALUES.get(s)??5}getOverwork(e){const i=[],r=[];for(const t of e){let e=t.indexOf(",");if(-1===e){if(e=this.addCommas(t).indexOf(","),-1===e)throw new Error(`getOverwork: in moves, m: ${t} is weird.`)}i.push(parseInt(t.slice(0,e),10)||0),r.push(parseInt(t.slice(e+1),10)||0)}let a=0,n=0,s=0,l=0,o=0;for(const e of i){if(6===e||e<0){if(s++,!t.CLOSEST_MAP.has(e))throw new Error("getOverwork: top move is weird: "+e);l+=Math.abs(t.CLOSEST_MAP.get(e)),o+=Math.abs(e),s>1&&l>3&&(a+=o,o=0)}else s=0,l=0,o=0}s=0,l=0,o=0;for(const e of r){if(e>0){if(s++,!t.CLOSEST_MAP.has(e))throw new Error("getOverwork: top move is weird: "+e);l+=Math.abs(t.CLOSEST_MAP.get(e)),o+=Math.abs(e),s>1&&l>3&&(a+=o,o=0)}else s=0,l=0,o=0}for(let t=0;t+1<i.length;t++)i[t]+i[t+1]===0&&n++,r[t]+r[t+1]===0&&n++;return{movement:a,bonus:n}}rateAlg(t,e=!1,i={}){const r=i.W1??34,a=i.W2??100,n=i.W3??38,s=i.W4??500,l=i.W5??10;let o=t.replace(/\[.*$/,"").trim();const h=(this.isKarn(o)?this.unkarnify(o):o.replaceAll(" ","")).split("/").filter((t,e)=>0===e||""!==t.trim()).map(t=>t.trim()),d=h.length-1;if(d<=0)return{score:s,sliceStart:" "};let c=0,u=0,g=!1,f=!0;for(let i=0;i<h.length-1;i++){let r=h[i],a=r.indexOf(",");if(-1===a&&(r=r?this.addCommas(r):"0,0",a=r.indexOf(","),-1===a))throw new Error(`rateAlg:\nalg: ${t}\nmove: ${r}\nis weird.`);const n=parseInt(r.slice(0,a),10);if(isNaN(n))throw new Error(`rateAlg:\nalg: ${t}\nmove: ${r}\nis weird.`);0!==i?(c+=this.getMoveValue(g,f,r),u+=this.getMoveValue(g,!f,r),g=g!==(n%3!=0),f=!f):(g=e!==(n%3!=0),f=!0)}const b=r*Math.max(c,u)/d;let p="|";Math.abs(c-u)/d>5&&(p=c>u?"/":"\\");const w=a*d,m=h.slice(1,-1),{movement:W,bonus:B}=this.getOverwork(m);return{score:b-w-n*W/d+B*l/d+s,sliceStart:p}}rateAndSort(t,e=""){let i=!1;if(e){const t=e[0];i=/[A-HU-W]/i.test(t)}return t.map(t=>{const e=t.indexOf("["),r=e>0?t.slice(0,e).trim():t.trim();let a={alg:t,score:500},n=!1,s=" ";const l=this.isKarn(r)?this.unkarnify(r):r;if(({score:a.score,sliceStart:s}=this.rateAlg(l,i)),n=!0,["/","\\","|"].includes(s)){const e=t.indexOf("/");e>=0&&(a.alg=t.slice(0,e)+s+t.slice(e+1))}return a}).sort((t,e)=>e.score-t.score)}sepIndex(t){let e=0;for(const i of t)if(e++,/\d/.test(i))break;return e}compl(t){if(!t)return t;const e=this.sepIndex(t);return String(this.legalMove(6+parseInt(t.slice(0,e),10)))+String(this.legalMove(6+parseInt(t.slice(e),10)))}lf(t){if(!t)return t;const e=this.sepIndex(t);return t.slice(e)+t.slice(0,e)}compact(t){let e=t.replace(/\[.*?\]/g,"").replace(/[()]/g,"").replaceAll(" ","").trim();if(this.isKarn(e)){return this.unkarnify(e).split("/").filter(Boolean).map(t=>{if(!t.includes(","))throw new Error(`algToInternal: m doesn't have commas post karnifying: ${t}`);const[e,i]=t.split(",");return String(this.legalMove(parseInt(e,10)))+String(this.legalMove(parseInt(i,10)))}).join(" ")}return e=e.trim(),e.includes("/")?e.split("/").filter(Boolean).map(t=>{if(t.includes(",")||(t=this.addCommas(t)),!t.includes(","))throw new Error(`algToInternal: m doesn't have commas post addComma: ${t}`);const[e,i]=t.split(",");return String(this.legalMove(parseInt(e,10)))+String(this.legalMove(parseInt(i,10)))}).join(" "):e.split(" ").filter(t=>t).map(t=>{const e=t.includes(",")?t.split(","):[t.slice(0,this.sepIndex(t)),t.slice(this.sepIndex(t))];return String(this.legalMove(parseInt(e[0],10)))+String(this.legalMove(parseInt(e[1],10)))}).join(" ")}countY2Positions(t){const e=this.compact(t).split(" ").filter(t=>t);return Math.max(0,e.length-3)}applyY2s(e,i,r=null){let a=e.replaceAll(/\[.*?\]/g,"").trim();i||(i=[]);const n=this.isKarn(a),s=null===r?n:r;a=this.unkarnify(e);let l=a.split("/");const o=l[0],h=l[l.length-1];let d=!1,c=!1;for(let t=1;t<=l.length-3;t++){let e=l[t];e=c?this.lf(e):e,i.includes(t)&&(e=this.compl(e),d=!d),c=d?!c:c,l[t]=e}const u=l.length-2;c&&(l[u]=this.lf(l[u])),d!==c&&(l[u]=this.compl(l[u]));const g=l[u];for(let t=0;t<l.length;t++)l[t]=this.addCommas(l[t]);a=l.join("/");let f="";g&&!t.GOOD_FINISHES.has(g)&&(f+=" (bad finish)");const{topA:b,bottomA:p}=this.getAlignment(o),{topA:w,bottomA:m}=this.getAlignment(h);return b!==p&&b!==w&&w!==m&&(f+=" (alignment changes in CS)"),s&&(a=this.karnify(a)),a+f}layerFlip(t){const e={b:"w",B:"W",w:"b",W:"B"};return[...t].map(t=>{if(t in e)return e[t];throw new Error("layerFlip: unrecognized character: "+t)}).join("")}shift(t,e){return e=(-e%t.length+t.length)%t.length,t.slice(e)+t.slice(0,e)}oblName(t){return t[0]?`${t[0]} ${t[1]}/${t[2]}`:`${t[1]}/${t[2]}`}layerFlipName(t){const e=(t=t.replace("/"," ")).split(" ");return 2===e.length?e[1]+"/"+e[0]:e[0]+" "+e[2]+"/"+e[1]}speToNonSpe(e){const[i,r]=e.split("/"),a=i.split(" ").pop(),n=r.split(" ").pop(),s=t.POSSIBLE_OBL.filter(t=>t.includes(a)&&t.includes(n)).map(t=>this.oblName(t));for(const i of s){const r=t.OBL_TRANSLATION[i]||[];for(const t of r){if(t===e)return i;const[r,a]=t.split("/");if(`${a}/${r}`===e)return this.layerFlipName(i)}}throw new Error(`speToNonSpe: No non-specific OBL found for: ${e}`)}isOBLCase(e,i){const r=Object.entries(t.OBLToEnglish).find(([,t])=>t===i)?.[0];if(!r)return!1;e[0]!==e[0].toUpperCase()&&(e=this.shift(e,-1));for(let t=0;t<4;t++)if(r===this.shift(e,-3*t))return t;if(!["T","tie"].includes(i.split(" ").pop())){const t=this.layerFlip(e);for(let e=0;e<4;e++)if(r===this.shift(t,-3*e))return e}return!1}layerToOBL(e){for(const i of Object.keys(t.OBLToState))if(this.isOBLCase(e,i))return{obl:i,angleOffset:this.isOBLCase(e,i)};throw new Error("layerToOBL: no OBL matched layer: "+e)}getAngle(e,i,r,a){let n=t.OBL_ANGLES[e],s=t.OBL_ANGLES[i];for(let e=0;e<r%4;e++)n=t.nextAngle[n];for(let e=0;e<a%4;e++)s=t.nextAngle[s];return`${n} ${s}`}cubeToSpe(e){return[this.layerToOBL(e.slice(0,t.LAYERL)),this.layerToOBL(e.slice(t.LAYERL))]}getOBLLen(t){return t in OBL_LEN?OBL_LEN[t]:OBL_LEN[layer_flip_name(t)]}stateToLen(t,e){return this.getOBLLen(this.speToNonSpe(t+"/"+e))}getOBLNaming(e,i){return t.NAMING[e]+"/"+t.NAMING[i]}stateToMatt(e){let i=e.slice(0,t.LAYERL),r=e.slice(t.LAYERL);i=i[0]!==i[0].toLowerCase()?this.shift(i,3):this.shift(i,2),r=r[0]!==r[0].toLowerCase()?this.shift(r,3):this.shift(r,2);let a="",n=1;for(let e=0;e<t.LAYERL;e+=3)"B"===i[e]&&(a+=n),"b"===i[e+2]&&(a+=n+1),n+=2;a=""===a?"- ":a+" ",n=1;for(let e=0;e<t.LAYERL;e+=3)"B"===r[e]&&(a+=n),"b"===r[e+2]&&(a+=n+1),n+=2;return" "===a[a.length-1]?a+"-":a}mattToLayer(t){const e=["W","W","w","W","W","w","W","W","w","W","W","w"];for(const i of t){const t=parseInt(i,10);t%2!=0?(e[3*Math.floor(t/2)]="B",e[3*Math.floor(t/2)+1]="B"):e[3*Math.floor(t/2)-1]="b"}return e.join("")}mattToNonSpe(t){const[e,i]=t.split(" ");return this.speToNonSpe(`${this.layerToOBL(this.mattToLayer(e))}/${this.layerToOBL(this.mattToLayer(i))}`)}sortOblp(t){return[...t].sort().join("")}}return t});
2
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).squanlib=e()}(this,function(){"use strict";class t{static karnToWCA={U4:"U U' U U'","U4'":"U' U U' U",D4:"D D' D D'","D4'":"D' D D' D",u4:"u u' u u'","u4'":"u' u u' u",d4:"d d' d d'","d4'":"d' d d' d",U3:"U U' U","U3'":"U' U U'",D3:"D D' D","D3'":"D' D D'",u3:"u u' u","u3'":"u' u u'",d3:"d d' d","d3'":"d' d d'",F3:"F F' F","F3'":"F' F F'",f3:"f f' f","f3'":"f' f f'",W:"U U'","W'":"U' U",B:"D D'","B'":"D' D",w:"u u'","w'":"u' u",b:"d d'","b'":"d' d",F2:"F F'","F2'":"F' F",f2:"f f'","f2'":"f' f",UU:"U U","UU'":"U' U'",DD:"D D","DD'":"D' D'",T2:"T T'","T2'":"T' T",t2:"t t'","t2'":"t' t",E2:"E E'","E2'":"E' E","ɇ":"U D","ɇ'":"U' D'","Ɇ":"U D'","Ɇ'":"U' D",U2:"6,0","U2'":"6,0",D2:"0,6",U2D:"6,3","U2D'":"6,-3","U2'D":"6,3","U2'D'":"6,-3",U2D2:"6,6",UD2:"3,6","U'D2":"-3,6",U:"3,0","U'":"-3,0",D:"0,3","D'":"0,-3",E:"3,-3","E'":"-3,3",e:"3,3","e'":"-3,-3",u:"2,-1","u'":"-2,1",d:"-1,2","d'":"1,-2",F:"4,1","F'":"-4,-1",f:"1,4","f'":"-1,-4",T:"2,-4","T'":"-2,4",t:"4,-2","t'":"-4,2",m:"2,2","m'":"-2,-2",M:"1,1","M'":"-1,-1",u2:"5,-1","u2'":"-5,1",d2:"-1,5","d2'":"1,-5",K:"5,2","K'":"-5,-2",k:"2,5","k'":"-2,-5",G:"5,-4","G'":"-5,4",g:"4,-5","g'":"-4,5"};static shorthandToKarn={bjj:"U' e D'",fjj:"U e' D",e2bjj:"U' e' U'",e2fjj:"U e U",nn:"E E'",jn:"D4'",nj:"U4",jj:"U e' D","bjj+e2":"U' e' U'","-nn":"E' E","-jn":"D4","-nj":"D4'",bpj10:"d m' U","bpj0-1":"u' m D'",fpj10:"u m' D","fpj0-1":"d' m U'",aa10:"u m' u T'","aa0-1":"U m' U t'",fadj10:"D M' d'",dadj10:"D M' d'","fadj0-1":"U' M u","u'adj0-1":"U' M u",badj10:"U M' u'",uadj10:"U M' u'","badj0-1":"D' M d","d'adj0-1":"D' M d",bb10:"T u' e U'","bb0-1":"t d e' D",fdd10:"D e' d t","fdd0-1":"U' e u' T",bdd10:"U e' u T'","bdd0-1":"D' e d' t'",ff10:"d m' d M E","ff0-1":"u' m U' M T",fv10:"d4","fv0-1":"d4'",vf10:"u4","vf0-1":"u4'",y2fv10:"u d' u -5,4",jf10:"w D' u T'","jf0-1":"w' D u' T",fj10:"b U' d t","fj0-1":"b' U d' t'",jr00:"e' w e",jr10:"e' b e","jr0-1":"e' w' e","jr1-1":"e' b' e",rj00:"e b' e'",rj10:"e w e'","rj0-1":"e b' e'","rj1-1":"e w e'",jv10:"b D d d2'","jv0-1":"b' D' d' d2",vj10:"w U u u2'","vj0-1":"w' U' u' u2",kk10:"u m' U E'","kk0-1":"U m' u E'",opp10:"u2 u2'","opp0-1":"u2' u2",pn10:"T T'","pn0-1":"t t'",px10:"f' d3' f'","px0-1":"f d3 f",xp10:"F' u3' F'","xp0-1":"F u3 F",tt10:"d m' F' u2'",fss10:"u M D' E'","fss0-1":"D' M u E'",bss10:"D M' u' E","bss0-1":"U' M d E",vv10:"u M u m' E'",zz10:"u M t' M D'","zz0-1":"D' M t' M u","30adj10":"U M' u'","-30adj0-1":"U' M u","03adj10":"D M' d'",obopp00:"1,0/M' F M' F M'/0,1","oaopp1-1":"0,1/M' u' M' u' M'/0,1",but00:"",also00:"","done!00":"0,0"};static alignmentIndependent=new Set(["bjj","fjj","nn","jn","nj","e2bjj","e2fjj","jj","bjj+e2","-nn","-jn","-nj"]);static wcaToBaseKarn={"6,0":"U2","6,3":"U2D","6,-3":"U2D'","6,6":"U2D2","0,6":"D2","3,6":"UD2","-3,6":"U'D2","3,0":"U","-3,0":"U'","0,3":"D","0,-3":"D'","3,-3":"E","-3,3":"E'","3,3":"e","-3,-3":"e'","2,-1":"u","-2,1":"u'","-1,2":"d","1,-2":"d'","4,1":"F","-4,-1":"F'","1,4":"f","-1,-4":"f'","2,-4":"T","-2,4":"T'","4,-2":"t","-4,2":"t'","2,2":"m","-2,-2":"m'","1,1":"M","-1,-1":"M'","5,-1":"u2","-5,1":"u2'","-1,5":"d2","1,-5":"d2'","5,2":"K","-5,-2":"K'","2,5":"k","-2,-5":"k'"};static baseKarnToHighKarn={"U U' U U'":"U4","U' U U' U":"U4'","D D' D D'":"D4","D' D D' D":"D4'","u u' u u'":"u4","u' u u' u":"u4'","d d' d d'":"d4","d' d d' d":"d4'","U U' U":"U3","U' U U'":"U3'","D D' D":"D3","D' D D'":"D3'","u u' u":"u3","u' u u'":"u3'","d d' d":"d3","d' d d'":"d3'","F F' F":"F3","F' F F'":"F3'","f f' f":"f3","f' f f'":"f3'","U U'":"W","U' U":"W'","D D'":"B","D' D":"B'","u u'":"w","u' u":"w'","d d'":"b","d' d":"b'","F F'":"F2","F' F":"F2'","f f'":"f2","f' f":"f2'","U U":"UU","U' U'":"UU'","D D":"DD","D' D'":"DD'"};static A_MOVES=[[3,0],[-3,0],[0,3],[0,-3],[3,3],[2,-1],[-1,2],[-4,-1],[-1,-4],[2,-4],[2,2],[-1,-1],[5,-1]];static a_MOVES=[[3,0],[-3,0],[0,3],[0,-3],[3,3],[-2,1],[1,-2],[4,1],[1,4],[-2,4],[-2,-2],[1,1],[-5,1]];static OPTIM={"/0,0/":"","/3,3/3,3/":"-3,-3/-3,-3","/-3,-3/-3,-3/":"3,3/3,3","/2,2/-2,-2/":"2,2/-2,-2","/-2,-2/2,2/":"-2,-2/2,2","/1,1/-1,-1/":"1,1/-1,-1","/-1,-1/1,1/":"-1,-1/1,1","/2,-4/-2,4/2,-4/":"2,-4/-2,4/2,-4","/-2,4/2,-4/-2,4/":"-2,4/2,-4/-2,4","/5,-1/-5,1/5,-1/":"5,-1/-5,1/5,-1","/-5,1/5,-1/-5,1/":"-5,1/5,-1/-5,1"};static CLOSEST_MAP=new Map([[-5,-6],[-4,-3],[-3,-3],[-2,-3],[-1,0],[0,0],[1,0],[2,3],[3,3],[4,3],[5,6],[6,6]]);static MOVE_VALUES=new Map([["A/0,3",16],["A/0,6",1],["A/0,-3",18],["A/3,0",16],["A/3,3",12],["A/3,6",0],["A/3,-3",13],["A/6,0",12],["A/6,3",11],["A/6,6",2],["A/6,-3",12],["A/-3,0",9],["A/-3,3",13],["A/-3,6",4],["A/-3,-3",12],["A\\0,3",17],["A\\0,6",1],["A\\0,-3",8],["A\\3,0",6],["A\\3,3",14],["A\\3,6",1],["A\\3,-3",12],["A\\6,0",14],["A\\6,3",11],["A\\6,6",5],["A\\6,-3",8],["A\\-3,0",11],["A\\-3,3",14],["A\\-3,6",6],["A\\-3,-3",9],["a/0,3",5],["a/0,6",5],["a/0,-3",12],["a/3,0",17],["a/3,3",10],["a/3,6",5],["a/3,-3",7],["a/6,0",4],["a/6,3",2],["a/6,6",0],["a/6,-3",3],["a/-3,0",18],["a/-3,3",12],["a/-3,6",7],["a/-3,-3",11],["a\\0,3",5],["a\\0,6",5],["a\\0,-3",5],["a\\3,0",16],["a\\3,3",11],["a\\3,6",4],["a\\3,-3",6],["a\\6,0",4],["a\\6,3",2],["a\\6,6",0],["a\\6,-3",1],["a\\-3,0",15],["a\\-3,3",10],["a\\-3,6",2],["a\\-3,-3",5],["/1,-2",4],["\\1,-2",17],["/-1,2",15],["\\-1,2",14],["/1,-5",3],["\\1,-5",1],["/-1,5",8],["\\-1,5",3],["/1,4",7],["\\1,4",14],["/-1,-4",12],["\\-1,-4",9],["/1,1",11],["\\1,1",20],["/-1,-1",20],["\\-1,-1",10],["/2,-1",20],["\\2,-1",12],["/-2,1",14],["\\-2,1",18],["/2,2",12],["\\2,2",13],["/-2,-2",14],["\\-2,-2",8],["/2,5",5],["\\2,5",3],["/-2,-5",4],["\\-2,-5",3],["/2,-4",14],["\\2,-4",6],["/-2,4",13],["\\-2,4",13],["/4,4",5],["\\4,4",12],["/-4,-4",12],["\\-4,-4",4],["/4,1",6],["\\4,1",13],["/-4,-1",16],["\\-4,-1",6],["/4,-2",12],["\\4,-2",9],["/-4,2",16],["\\-4,2",13],["/4,-5",2],["\\4,-5",5],["/-4,5",13],["\\-4,5",3],["/5,5",1],["\\5,5",4],["/-5,-5",2],["\\-5,-5",0],["/5,2",6],["\\5,2",10],["/-5,-2",12],["\\-5,-2",13],["/5,-1",11],["\\5,-1",7],["/-5,1",14],["\\-5,1",15],["/5,-4",2],["\\5,-4",2],["/-5,4",12],["\\-5,4",14]]);static GOOD_FINISHES=new Set(["1,1","-1,-1","2,2","-2,-2","2,-1","-2,1","1,-2","-1,2","3,0","-3,0","0,3","0,-3","3,3","3,-3","-3,-3","-3,3","4,1","-4,-1","1,4","-1,-4","2,-4","-2,4","4,-2","-4,2","5,-1","-5,1","-4,5","-5,4","6,3"]);static OBLToEnglish={BBbBBbBBbBBb:"solved",BBwWWwWWwWWw:"1c",BBwBBwWWwWWw:"cadj",BBwWWwBBwWWw:"copp",BBwBBwBBwWWw:"3c",BBwBBwBBwBBw:"4e",WWbWWbWWbWWw:"3e",WWbWWwWWbWWw:"line",WWbWWbWWwWWw:"L",WWbWWwWWwWWw:"1e",WWbBBwWWwWWw:"left pair",BBbWWwWWwWWw:"right pair",BBwWWwWWbWWw:"left arrow",BBwWWbWWwWWw:"right arrow",WWbBBbWWwWWw:"gem",WWwWWbWWbBBw:"left knight",BBbWWbWWwWWw:"right knight",WWwWWbWWwBBb:"left axe",BBwWWbWWwWWb:"right axe",BBwWWbWWbWWw:"squid",WWwWWbBBbWWb:"left thumb",WWbBBbWWwWWb:"right thumb",WWwBBbWWbWWb:"left bunny",WWbWWbBBwWWb:"right bunny",BBbBBwWWwWWw:"shell",BBwWWwWWbBBw:"left bird",BBwBBbWWwWWw:"right bird",BBwWWbWWwBBw:"hazard",BBbBBbWWwWWw:"left kite",WWwWWbBBbBBw:"right kite",BBwBBwWWbWWb:"left cut",BBwBBbWWbWWw:"right cut",BBbBBwWWbWWw:"black T",WWwWWbBBwBBb:"white T",WWbBBwWWbBBw:"left N",WWwBBbWWwBBb:"right N",WWbBBbWWwBBw:"black tie",BBwWWwBBbWWb:"white tie",BBbWWwBBwWWw:"left yoshi",WWwBBwWWbBBw:"right yoshi"};static OBLToState=Object.fromEntries(Object.entries(this.OBLToEnglish).map(([t,e])=>[e,t]));static NAMING={solved:"O","1c":"D",cadj:"J",copp:"V","3c":"M","4e":"Q","3e":"W",line:"F",L:"L","1e":"E","left pair":"Pw","right pair":"Pc","left arrow":"Aw","right arrow":"Ac",gem:"G","left knight":"Hw","right knight":"Hc","left axe":"Xc","right axe":"Xw",squid:"S","left thumb":"THw","right thumb":"THc","left bunny":"Uc","right bunny":"Uw",shell:"SH","left bird":"Bc","right bird":"Bw",hazard:"Z","left kite":"Kc","right kite":"Kw","left cut":"Cw","right cut":"Cc","black T":"Tu","white T":"Td","left N":"Nw","right N":"Nc","black tie":"Iu","white tie":"Id","left yoshi":"Yc","right yoshi":"Yw"};static OBL_ANGLES={solved:"-","1c":"UR",cadj:"R",copp:"/","3c":"DR","4e":"-","3e":"D",line:"—",L:"DR","1e":"R","left pair":"DR","right pair":"UR","left arrow":"UR","right arrow":"UR",gem:"DR","left knight":"L","right knight":"R","left axe":"L","right axe":"R",squid:"UR","left thumb":"DL","right thumb":"DR","left bunny":"DR","right bunny":"DL",shell:"R","left bird":"R","right bird":"U",hazard:"U","left kite":"R","right kite":"L","left cut":"R","right cut":"R","black T":"R","white T":"R","left N":"\\","right N":"\\","black tie":"DR","white tie":"DR","left yoshi":"UL","right yoshi":"UR"};static nextAngle={"-":"-","/":"\\","\\":"/","—":"|","|":"—",U:"R",R:"D",D:"L",L:"U",UR:"DR",DR:"DL",DL:"UL",UL:"UR"};static get HALF_L(){return 6}static get LAYERL(){return 12}static get THREE_FOUR_L(){return 18}static get CUBEL(){return 24}static get SOLVED(){return"bBBbBBbBBbBBwWWwWWwWWwWW"}static POSSIBLE_OBL=[["","solved","solved"],["","1c","1c"],["","cadj","cadj"],["","cadj","copp"],["","copp","copp"],["","3c","3c"],["","4e","4e"],["","3e","3e"],["","line","line"],["","L","line"],["","L","L"],["","1e","1e"],["good","pair","pair"],["bad","pair","pair"],["good","arrow","pair"],["bad","arrow","pair"],["good","arrow","arrow"],["bad","arrow","arrow"],["","gem","gem"],["","gem","knight"],["","gem","axe"],["","gem","squid"],["good","knight","knight"],["bad","knight","knight"],["good","knight","axe"],["bad","knight","axe"],["same","axe","axe"],["diff","axe","axe"],["","squid","knight"],["","squid","axe"],["","squid","squid"],["good","thumb","thumb"],["bad","thumb","thumb"],["good","thumb","bunny"],["bad","thumb","bunny"],["good","bunny","bunny"],["bad","bunny","bunny"],["","shell","shell"],["","shell","bird"],["","shell","hazard"],["","yoshi","shell"],["good","bird","bird"],["bad","bird","bird"],["","bird","hazard"],["","hazard","hazard"],["good","yoshi","bird"],["bad","yoshi","bird"],["","yoshi","hazard"],["same","yoshi","yoshi"],["diff","yoshi","yoshi"],["good","kite","kite"],["bad","kite","kite"],["good","kite","cut"],["bad","kite","cut"],["","kite","T"],["good","kite","N"],["bad","kite","N"],["","kite","tie"],["","cut","T"],["good","cut","N"],["bad","cut","N"],["","cut","tie"],["good","cut","cut"],["bad","cut","cut"],["good","T","T"],["bad","T","T"],["","T","N"],["good","T","tie"],["bad","T","tie"],["good","N","N"],["bad","N","N"],["","tie","N"],["good","tie","tie"],["bad","tie","tie"]];static OBL_LEN={"solved/solved":0,"1c/1c":5,"cadj/cadj":4,"cadj/copp":5,"copp/copp":2,"3c/3c":5,"4e/4e":4,"3e/3e":5,"line/line":2,"L/line":5,"L/L":4,"1e/1e":5,"good pair/pair":2,"bad pair/pair":4,"good arrow/pair":3,"bad arrow/pair":4,"good arrow/arrow":3,"bad arrow/arrow":4,"gem/gem":4,"gem/knight":4,"gem/axe":3,"gem/squid":4,"good knight/knight":4,"bad knight/knight":5,"good knight/axe":3,"bad knight/axe":4,"same axe/axe":5,"diff axe/axe":5,"squid/knight":4,"squid/axe":4,"squid/squid":5,"good thumb/thumb":2,"bad thumb/thumb":5,"good thumb/bunny":4,"bad thumb/bunny":4,"good bunny/bunny":3,"bad bunny/bunny":5,"shell/shell":4,"shell/bird":4,"shell/hazard":4,"yoshi/shell":3,"good bird/bird":4,"bad bird/bird":5,"bird/hazard":4,"hazard/hazard":5,"good yoshi/bird":3,"bad yoshi/bird":4,"yoshi/hazard":4,"same yoshi/yoshi":5,"diff yoshi/yoshi":5,"good kite/kite":1,"bad kite/kite":5,"good kite/cut":3,"bad kite/cut":6,"kite/T":4,"good kite/N":3,"bad kite/N":4,"kite/tie":4,"cut/T":4,"good cut/N":4,"bad cut/N":5,"cut/tie":4,"good cut/cut":3,"bad cut/cut":6,"good T/T":3,"bad T/T":4,"T/N":5,"good T/tie":3,"bad T/tie":4,"good N/N":2,"bad N/N":4,"tie/N":5,"good tie/tie":3,"bad tie/tie":4};static OBL_TRANSLATION={"solved/solved":["solved/solved"],"1c/1c":["1c/1c"],"cadj/cadj":["cadj/cadj"],"cadj/copp":["cadj/copp"],"copp/copp":["copp/copp"],"3c/3c":["3c/3c"],"4e/4e":["4e/4e"],"3e/3e":["3e/3e"],"line/line":["line/line"],"L/line":["L/line"],"L/L":["L/L"],"1e/1e":["1e/1e"],"good pair/pair":["left pair/left pair","right pair/right pair"],"bad pair/pair":["left pair/right pair"],"good arrow/pair":["left arrow/right pair","right arrow/left pair"],"bad arrow/pair":["left arrow/left pair","right arrow/right pair"],"good arrow/arrow":["left arrow/left arrow","right arrow/right arrow"],"bad arrow/arrow":["left arrow/right arrow"],"gem/gem":["gem/gem"],"gem/knight":["gem/left knight","gem/right knight"],"gem/axe":["gem/left axe","gem/right axe"],"gem/squid":["gem/squid"],"good knight/knight":["left knight/right knight"],"bad knight/knight":["left knight/left knight","right knight/right knight"],"good knight/axe":["left knight/left axe","right knight/right axe"],"bad knight/axe":["left knight/right axe","right knight/left axe"],"same axe/axe":["left axe/left axe","right axe/right axe"],"diff axe/axe":["left axe/right axe"],"squid/knight":["squid/left knight","squid/right knight"],"squid/axe":["squid/left axe","squid/right axe"],"squid/squid":["squid/squid"],"good thumb/thumb":["left thumb/left thumb","right thumb/right thumb"],"bad thumb/thumb":["left thumb/right thumb"],"good thumb/bunny":["left thumb/right bunny","right thumb/left bunny"],"bad thumb/bunny":["left thumb/left bunny","right thumb/right bunny"],"good bunny/bunny":["left bunny/left bunny","right bunny/right bunny"],"bad bunny/bunny":["left bunny/right bunny"],"shell/shell":["shell/shell"],"shell/bird":["shell/left bird","shell/right bird"],"shell/hazard":["shell/hazard"],"yoshi/shell":["left yoshi/shell","right yoshi/shell"],"good bird/bird":["left bird/right bird"],"bad bird/bird":["left bird/left bird","right bird/right bird"],"bird/hazard":["left bird/hazard","right bird/hazard"],"hazard/hazard":["hazard/hazard"],"good yoshi/bird":["left yoshi/left bird","right yoshi/right bird"],"bad yoshi/bird":["left yoshi/right bird","right yoshi/left bird"],"yoshi/hazard":["left yoshi/hazard","right yoshi/hazard"],"same yoshi/yoshi":["left yoshi/left yoshi","right yoshi/right yoshi"],"diff yoshi/yoshi":["left yoshi/right yoshi"],"good kite/kite":["left kite/left kite","right kite/right kite"],"bad kite/kite":["left kite/right kite"],"good kite/cut":["left kite/left cut","right kite/right cut"],"bad kite/cut":["left kite/right cut","right kite/left cut"],"kite/T":["left kite/black T","left kite/white T","right kite/black T","right kite/white T"],"good kite/N":["left kite/right N","right kite/left N"],"bad kite/N":["left kite/left N","right kite/right N"],"kite/tie":["left kite/black tie","left kite/white tie","right kite/black tie","right kite/white tie"],"cut/T":["left cut/black T","left cut/white T","right cut/black T","right cut/white T"],"good cut/N":["left cut/left N","right cut/right N"],"bad cut/N":["left cut/right N","right cut/left N"],"cut/tie":["left cut/black tie","left cut/white tie","right cut/black tie","right cut/white tie"],"good cut/cut":["left cut/left cut","right cut/right cut"],"bad cut/cut":["left cut/right cut"],"good T/T":["black T/black T","white T/white T"],"bad T/T":["black T/white T"],"T/N":["black T/left N","black T/right N","white T/left N","white T/right N"],"good T/tie":["black T/black tie","white T/white tie"],"bad T/tie":["black T/white tie","white T/black tie"],"good N/N":["left N/left N","right N/right N"],"bad N/N":["left N/right N"],"tie/N":["black tie/left N","black tie/right N","white tie/left N","white tie/right N"],"good tie/tie":["black tie/black tie","white tie/white tie"],"bad tie/tie":["black tie/white tie"]};static CORNERS=[[""],["1","3","5","7"],["13","15","17","35","37","57"],["135","137","157","357"],["1357"]];static EDGES=[[""],["2","4","6","8"],["24","26","28","46","48","68"],["246","248","268","468"],["2468"]];static TOTAL_CORNERS=["","1","3","5","7","13","15","17","35","37","57","135","137","157","357","1357"];static TOTAL_EDGES=["","2","4","6","8","24","26","28","46","48","68","246","248","268","468","2468"];constructor(t={"meow :3":"meow :3"}){this.tempReplacements={...t}}setTempReplacements(t){return this.tempReplacements={...t},this}addTempReplacements(t){return Object.assign(this.tempReplacements,t),this}dictReplace(t,e){const i=new RegExp(Object.keys(e).map(t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|"),"g");let r;do{r=t,t=t.replace(i,t=>e[t])}while(t!==r);return t}addCommas(t){return t.split(/[/\\| ]/).map(t=>{if(!t||isNaN(Number(t.replaceAll("-","")))||t.includes(","))return t;switch(t.length){case 1:return t+",0";case 2:return"-"===t.charAt(0)?t+",0":t[0]+","+t[1];case 3:return"-"===t.charAt(0)?t.slice(0,2)+","+t[2]:t[0]+","+t.slice(1);case 4:return t.slice(0,2)+","+t.slice(2);default:throw new Error(`"${t}" is not a valid karn numeric move`)}}).join(" ")}isKarn(t){return/[a-zA-Z]/.test(t)}getAlignmentMove(t,e){return(t?"1":"0")+(e?"-1":"0")}getAlignment(t){if(!t)return{topA:!1,bottomA:!1};if(!(t=this.addCommas(t)).includes(","))throw new Error("getAlignment: move is weird: "+t);const[e,i]=t.split(",");return{topA:"0"!==e,bottomA:"0"!==i}}unkarnifyHelp(e){if(e=(e=e.trim().replaceAll(/[()]/g,"")).replaceAll(/ ([\/\\\|]) /g,"$1"),/[\/\\\|]{2,}/.test(e))throw new Error("unkarnifyHelp: Two slices in a row.");if(!this.isKarn(e))return e;let i,r;/[/\\| ]/.test(e)?(i=e.match(/^([^/\\| ]*)[/\\| ]/)?.[1],r=e.match(/[/\\| ]([^/\\| ]*)$/)?.[1]):i=r=e;let a=["/","\\","|"].includes(e.charAt(0))?e.charAt(0):i in t.karnToWCA?"/":"",n="/"===e.at(-1)||r in t.karnToWCA?"/":"";e=e.replaceAll(/[/\\| ]+/g," ");let s=(e=this.addCommas(e)).split(" ").filter(Boolean);for(let e=0;e<s.length;e++)s[e]in t.karnToWCA&&(s[e]=t.karnToWCA[s[e]].split(" "));s=s.flat();for(let e=0;e<s.length;e++)s[e]in t.karnToWCA&&(s[e]=t.karnToWCA[s[e]]);if(e=(e=a+s.join("/")+n).replaceAll(/ +/g,""),/[\/\\\|]{2,}/.test(e))throw new Error("unkarnifyHelp: Two slices in a row post-replacements.");return e}unkarnify(t){if(t in this.tempReplacements)return this.tempReplacements[t];t=(t=t.replaceAll("&","-1").replaceAll("^","-2").replaceAll("9","-3").replaceAll("8","-4").replaceAll("7","-5")).replaceAll(/\[.*?\]/g,"");let e,i=/^p[ /\\|]/.test(t);i&&(e=" "===t.charAt(1)?"/":t.charAt(1),t=t.slice(2,-3));for(const e of t.matchAll(/(\(.*?\))(\d+)/g)){const i=e[1].replaceAll(/[()]/g,""),r=parseInt(e[2],10);t=t.replace(e[0],Array(r).fill(i).join(" "))}let r=this.replaceShorthands(this.unkarnifyHelp(t));return i&&(["/","\\","|"].includes(r.charAt(0))&&(r=r.slice(1)),r="p"+e+r+"/p'"),r=r.replaceAll(/\/+/g,"/"),r}replaceShorthands(e){const i=e.split(/[\/\\\|]/);if(i.every(e=>!e||!this.isKarn(e)||" "+e+" "in t.karnToWCA))return this.unkarnifyHelp(e);let r=!1,a=!1;for(const n of i)if(n)if(n.includes(",")){const[t,e]=n.split(",");parseInt(t,10)%3!=0&&(r=!r),parseInt(e,10)%3!=0&&(a=!a)}else{const i=t.alignmentIndependent.has(n.toLowerCase())?n.toLowerCase():n.toLowerCase()+this.getAlignmentMove(r,a),s=t.shorthandToKarn[i];if(void 0===s)throw new Error(`replaceShorthands: "${n}" with alignment ${this.getAlignmentMove(r,a)} is not defined.`);e=e.replace(n,s);for(const t of this.unkarnifyHelp(s).split("/")){if(!t)continue;const[e,i]=t.split(",");parseInt(e,10)%3!=0&&(r=!r),parseInt(i,10)%3!=0&&(a=!a)}}return this.unkarnifyHelp(e)}parseScramble(t){const e=[],i=t.replace(/[\/\\\|]/g," / ").trim().split(/\s+/).filter(Boolean);for(let t of i)if(t.startsWith("p"))e.push({type:"turn",top:0,bottom:0});else if("/"===t)e.push({type:"twist"});else{if(t=this.addCommas(t.replace(/[()]/g,"")),!t.includes(","))throw new Error(`parseScramble: move: ${t} is weird.`);const[i,r]=t.split(",").map(t=>parseInt(t.trim(),10));isNaN(i)||isNaN(r)||e.push({type:"turn",top:i,bottom:r})}return e}twist(t,e){return{tlHex:t.slice(0,6)+e.slice(0,6),blHex:t.slice(6)+e.slice(6)}}doSlice(e){const[i,r,a,n]=[e.slice(0,t.HALF_L),e.slice(t.HALF_L,t.LAYERL),e.slice(t.LAYERL,t.THREE_FOUR_L),e.slice(t.THREE_FOUR_L,t.CUBEL)],s=t=>t===t.toUpperCase();if(![i,r,a,n].map(t=>!s(t.at(0))||s(t.at(1))&&!s(t.at(-1))||s(t.at(-2))).every(Boolean))throw new Error("doSlice: unsliceable position encountered");return a+r+i+n}algToHex(t){let e="011233455677",i="998bbaddcffe";for(const r of this.parseScramble(this.unkarnify(t)))"twist"===r.type?({tlHex:e,blHex:i}=this.twist(e,i)):(e=this.shift(e,-r.top),i=this.shift(i,-r.bottom));return{tlHex:e,blHex:i}}doMoves(e,i){void 0===i&&(i=t.SOLVED);for(const t of this.unkarnify(e).split("/")){const e=t.trim();if(""!==e){const[t,r]=e.split(",").map(Number);i=this.moveCube(i,t,r)}i=this.doSlice(i)}return this.doSlice(i)}moveCube(e,i,r){return this.shift(e.slice(0,t.LAYERL),i)+this.shift(e.slice(t.LAYERL),r)}invertScramble(t){return t?this.unkarnify(t).trim().split("/").reverse().map(t=>{const e=(t=t.trim()).includes("(")?t.match(/\(([^)]+)\)/)?.[1]:t.includes(",")?t:null;if(!e)return t;const i=e.split(",").map(t=>{const e=parseInt(t.trim(),10);return isNaN(e)?t.trim():String(-e)}).join(",");return t.includes("(")?`(${i})`:i}).join("/"):t}isPBL(t){let{tlHex:e,blHex:i}=t,r=[...e],a=[...i];return r[1]===r[2]&&r[4]===r[5]&&r[7]===r[8]&&r[10]===r[11]&&(parseInt(r[0],10)%2==0&&parseInt(r[1],10)%2==1&&parseInt(r[3],10)%2==0&&parseInt(r[4],10)%2==1&&parseInt(r[6],10)%2==0&&parseInt(r[7],10)%2==1&&parseInt(r[9],10)%2==0&&parseInt(r[10],10)%2==1&&(!!(r.includes("0")&&r.includes("1")&&r.includes("2")&&r.includes("3")&&r.includes("4")&&r.includes("5")&&r.includes("6")&&r.includes("7"))&&(a[0]===a[1]&&a[3]===a[4]&&a[6]===a[7]&&a[9]===a[10]&&(parseInt(a[0],16)%2==1&&parseInt(a[2],16)%2==0&&parseInt(a[3],16)%2==1&&parseInt(a[5],16)%2==0&&parseInt(a[6],16)%2==1&&parseInt(a[8],16)%2==0&&parseInt(a[9],16)%2==1&&parseInt(a[11],16)%2==0&&!!(a.includes("8")&&a.includes("9")&&a.includes("a")&&a.includes("b")&&a.includes("c")&&a.includes("d")&&a.includes("e")&&a.includes("f"))))))}karnify(e){if(e=e.trim(),/[\/\\\|]{2,}/.test(e))throw new Error("karnify: Two slices in a row.");if(this.isKarn(e))throw new Error("karnify: Alg has letters. Try unkarnifying first.");let i=["/","\\","|"].includes(e.charAt(0)),r=i?e.charAt(0):"",a="/"===e.at(-1),n=a?"/":"",s=(e=e.replaceAll(/[/\\| ]+/g," ")).split(" ").filter(Boolean);for(let e=0;e<s.length;e++){if(0===e&&!i){s[e]=s[e].replace(",","");continue}if(e===s.length-1&&!a){s[e]=s[e].replace(",","");break}let l=s[e]in t.wcaToBaseKarn;s[e]=l?t.wcaToBaseKarn[s[e]]:s[e].replace(",",""),l&&0===e&&(r=r.replace("/","")),l&&e===s.length-1&&(n="")}return e=r+s.join(" ")+n,e=this.dictReplace(e,t.baseKarnToHighKarn)}legalMove(t){return(t%=12)<-5?t+12:t>6?t-12:t}addMoves(t,e){if(!t&&!e)throw new Error("addMoves: both moves are empty.");if(!t)return e;if(!e)return t;const i={A:"a",a:"A"};if(t in i&&e in i)throw new Error("addMoves: both moves cannot be alignment markers.");if(t in i){const r=parseInt(e.split(",")[0],10);return this.changesAlignment(r)?i[t]:t}if(e in i){const r=parseInt(t.split(",")[0],10);return this.changesAlignment(r)?i[e]:e}const[r,a]=t.split(",").map(Number),[n,s]=e.split(",").map(Number);return`${this.legalMove(r+n)},${this.legalMove(a+s)}`}changesAlignment(t){return t%3!=0}optimize(e){const i=Object.keys(t.OPTIM);for(;this.dictReplace(e,t.OPTIM)!==e;){const r=e.split("/").map(t=>t.trim());let a=0,n=!1;for(let s=0;s<e.length&&!n;s++)if("/"===e[s]){a++;for(const l of i)if(!(e.length-1-s<l.length)&&e.slice(s,s+l.length)===l){if("/0,0/"===l)r[a-1]=this.addMoves(r[a-1],r[a+1]),r.splice(a,2);else{const e=l.split("/").length,i=t.OPTIM[l].split("/"),n=e-2;r[a-1]=this.addMoves(r[a-1],i.shift()),r[a+e-2]=this.addMoves(r[a+e-2],i.pop()),r.splice(a,n,...i)}e=r.join("/"),n=!0;break}}}return e}getMoveValue(e,i,r){let a=r.indexOf(",");if(-1===a&&(a=this.addCommas(r).indexOf(","),-1===a))throw new Error(`getMoveValue: move: ${r} is weird`);const n=i?"/":"\\";let s;return s=parseInt(r.slice(0,a),10)%3==0?(e?"A":"a")+n+r:n+r,t.MOVE_VALUES.get(s)??5}getOverwork(e){const i=[],r=[];for(const t of e){let e=t.indexOf(",");if(-1===e){if(e=this.addCommas(t).indexOf(","),-1===e)throw new Error(`getOverwork: in moves, m: ${t} is weird.`)}i.push(parseInt(t.slice(0,e),10)||0),r.push(parseInt(t.slice(e+1),10)||0)}let a=0,n=0,s=0,l=0,o=0;for(const e of i){if(6===e||e<0){if(s++,!t.CLOSEST_MAP.has(e))throw new Error("getOverwork: top move is weird: "+e);l+=Math.abs(t.CLOSEST_MAP.get(e)),o+=Math.abs(e),s>1&&l>3&&(a+=o,o=0)}else s=0,l=0,o=0}s=0,l=0,o=0;for(const e of r){if(e>0){if(s++,!t.CLOSEST_MAP.has(e))throw new Error("getOverwork: top move is weird: "+e);l+=Math.abs(t.CLOSEST_MAP.get(e)),o+=Math.abs(e),s>1&&l>3&&(a+=o,o=0)}else s=0,l=0,o=0}for(let t=0;t+1<i.length;t++)i[t]+i[t+1]===0&&n++,r[t]+r[t+1]===0&&n++;return{movement:a,bonus:n}}rateAlg(t,e=!1,i={}){const r=i.W1??34,a=i.W2??100,n=i.W3??38,s=i.W4??500,l=i.W5??10;let o=t.replace(/\[.*$/,"").trim();const h=(this.isKarn(o)?this.unkarnify(o):o.replaceAll(" ","")).split("/").filter((t,e)=>0===e||""!==t.trim()).map(t=>t.trim()),d=h.length-1;if(d<=0)return{score:s,sliceStart:" "};let c=0,u=0,g=!1,f=!0;for(let i=0;i<h.length-1;i++){let r=h[i],a=r.indexOf(",");if(-1===a&&(r=r?this.addCommas(r):"0,0",a=r.indexOf(","),-1===a))throw new Error(`rateAlg:\nalg: ${t}\nmove: ${r}\nis weird.`);const n=parseInt(r.slice(0,a),10);if(isNaN(n))throw new Error(`rateAlg:\nalg: ${t}\nmove: ${r}\nis weird.`);0!==i?(c+=this.getMoveValue(g,f,r),u+=this.getMoveValue(g,!f,r),g=g!==(n%3!=0),f=!f):(g=e!==(n%3!=0),f=!0)}const b=r*Math.max(c,u)/d;let p="|";Math.abs(c-u)/d>5&&(p=c>u?"/":"\\");const w=a*d,m=h.slice(1,-1),{movement:W,bonus:B}=this.getOverwork(m);return{score:b-w-n*W/d+B*l/d+s,sliceStart:p}}rateAndSort(t,e=""){let i=!1;if(e){const t=e[0];i=/[A-HU-W]/i.test(t)}return t.map(t=>{const e=t.indexOf("["),r=e>0?t.slice(0,e).trim():t.trim();let a={alg:t,score:500},n=!1,s=" ";const l=this.isKarn(r)?this.unkarnify(r):r;return({score:a.score,sliceStart:s}=this.rateAlg(l,i)),n=!0,["/","\\","|"].includes(s)&&(a.alg=this.injectSliceStart(t,s)),a}).sort((t,e)=>e.score-t.score)}injectSliceStart(e,i){let r=/[/\\| ]/.test(e);if((r?e.match(/^([^/\\| ]*)[/\\| ]/)?.[1]:e)in t.karnToWCA)return i+e;if(!r)return e;const a=e.search(/[/\\| ]/);return e.slice(0,a)+i+e.slice(a+1)}sepIndex(t){let e=0;for(const i of t)if(e++,/\d/.test(i))break;return e}compl(t){if(!t)return t;let e,i;if(t.includes(","))[e,i]=t.split(",");else{const r=this.sepIndex(t);[e,i]=[t.slice(0,r),t.slice(r)]}return String(this.legalMove(6+parseInt(e,10)))+","+String(this.legalMove(6+parseInt(i,10)))}lf(t){if(!t)return t;let e,i;if(t.includes(","))[e,i]=t.split(",");else{const r=this.sepIndex(t);[e,i]=[t.slice(0,r),t.slice(r)]}return i+","+e}compact(t){let e=t.replace(/\[.*?\]/g,"").replace(/[()]/g,"").trim();if(this.isKarn(e)){return this.unkarnify(e).split("/").map(t=>{if(!t)return t;if(!t.includes(","))throw new Error(`algToInternal: m doesn't have commas post karnifying: ${t}`);const[e,i]=t.split(",");return String(this.legalMove(parseInt(e,10)))+String(this.legalMove(parseInt(i,10)))}).join(" ")}return e=e.replaceAll(" ",""),e.includes("/")?e.split("/").filter(Boolean).map(t=>{if(t.includes(",")||(t=this.addCommas(t)),!t.includes(","))throw new Error(`algToInternal: m doesn't have commas post addComma: ${t}`);const[e,i]=t.split(",");return String(this.legalMove(parseInt(e,10)))+String(this.legalMove(parseInt(i,10)))}).join(" "):e.split(" ").filter(t=>t).map(t=>{const e=t.includes(",")?t.split(","):[t.slice(0,this.sepIndex(t)),t.slice(this.sepIndex(t))];return String(this.legalMove(parseInt(e[0],10)))+String(this.legalMove(parseInt(e[1],10)))}).join(" ")}countY2Positions(t){const e=this.compact(t).split(" ");return Math.max(0,e.length-3)}applyY2s(e,i,r=null){let a=e.replaceAll(/\[.*?\]/g,"").trim();i||(i=[]);const n=this.isKarn(a),s=null===r?n:r;a=this.unkarnify(e);let l=a.split("/");const o=l[0],h=l[l.length-1];let d=!1,c=!1;for(let t=1;t<=l.length-3;t++){let e=l[t];e=c?this.lf(e):e,i.includes(t)&&(e=this.compl(e),d=!d),c=d?!c:c,l[t]=e}const u=l.length-2;c&&(l[u]=this.lf(l[u])),d!==c&&(l[u]=this.compl(l[u]));const g=l[u];for(let t=0;t<l.length;t++)l[t]=this.addCommas(l[t]);a=l.join("/");let f="";g&&!t.GOOD_FINISHES.has(g)&&(f+=" (bad finish)");const{topA:b,bottomA:p}=this.getAlignment(o),{topA:w,bottomA:m}=this.getAlignment(h);return b!==p&&b!==w&&w!==m&&(f+=" (alignment changes in CS)"),s&&(a=this.karnify(a)),a+f}layerFlip(t){const e={b:"w",B:"W",w:"b",W:"B"};return[...t].map(t=>{if(t in e)return e[t];throw new Error("layerFlip: unrecognized character: "+t)}).join("")}shift(t,e){return e=(-e%t.length+t.length)%t.length,t.slice(e)+t.slice(0,e)}oblName(t){return t[0]?`${t[0]} ${t[1]}/${t[2]}`:`${t[1]}/${t[2]}`}layerFlipName(t){const e=(t=t.replace("/"," ")).split(" ");return 2===e.length?e[1]+"/"+e[0]:e[0]+" "+e[2]+"/"+e[1]}speToNonSpe(e){const[i,r]=e.split("/"),a=i.split(" ").pop(),n=r.split(" ").pop(),s=t.POSSIBLE_OBL.filter(t=>t.includes(a)&&t.includes(n)).map(t=>this.oblName(t));for(const i of s){const r=t.OBL_TRANSLATION[i]||[];for(const t of r){if(t===e)return i;const[r,a]=t.split("/");if(`${a}/${r}`===e)return this.layerFlipName(i)}}throw new Error(`speToNonSpe: No non-specific OBL found for: ${e}`)}isOBLCase(e,i){const r=Object.entries(t.OBLToEnglish).find(([,t])=>t===i)?.[0];if(!r)return!1;e[0]!==e[0].toUpperCase()&&(e=this.shift(e,-1));for(let t=0;t<4;t++)if(r===this.shift(e,-3*t))return t;if(!["T","tie"].includes(i.split(" ").pop())){const t=this.layerFlip(e);for(let e=0;e<4;e++)if(r===this.shift(t,-3*e))return e}return!1}layerToOBL(e){for(const i of Object.keys(t.OBLToState))if(this.isOBLCase(e,i))return{obl:i,angleOffset:this.isOBLCase(e,i)};throw new Error("layerToOBL: no OBL matched layer: "+e)}getAngle(e,i,r,a){let n=t.OBL_ANGLES[e],s=t.OBL_ANGLES[i];for(let e=0;e<r%4;e++)n=t.nextAngle[n];for(let e=0;e<a%4;e++)s=t.nextAngle[s];return`${n} ${s}`}cubeToSpe(e){return[this.layerToOBL(e.slice(0,t.LAYERL)),this.layerToOBL(e.slice(t.LAYERL))]}getOBLLen(t){return t in OBL_LEN?OBL_LEN[t]:OBL_LEN[layer_flip_name(t)]}stateToLen(t,e){return this.getOBLLen(this.speToNonSpe(t+"/"+e))}getOBLNaming(e,i){return t.NAMING[e]+"/"+t.NAMING[i]}stateToMatt(e){let i=e.slice(0,t.LAYERL),r=e.slice(t.LAYERL);i=i[0]!==i[0].toLowerCase()?this.shift(i,3):this.shift(i,2),r=r[0]!==r[0].toLowerCase()?this.shift(r,3):this.shift(r,2);let a="",n=1;for(let e=0;e<t.LAYERL;e+=3)"B"===i[e]&&(a+=n),"b"===i[e+2]&&(a+=n+1),n+=2;a=""===a?"- ":a+" ",n=1;for(let e=0;e<t.LAYERL;e+=3)"B"===r[e]&&(a+=n),"b"===r[e+2]&&(a+=n+1),n+=2;return" "===a[a.length-1]?a+"-":a}mattToLayer(t){const e=["W","W","w","W","W","w","W","W","w","W","W","w"];for(const i of t){const t=parseInt(i,10);t%2!=0?(e[3*Math.floor(t/2)]="B",e[3*Math.floor(t/2)+1]="B"):e[3*Math.floor(t/2)-1]="b"}return e.join("")}mattToNonSpe(t){const[e,i]=t.split(" ");return this.speToNonSpe(`${this.layerToOBL(this.mattToLayer(e))}/${this.layerToOBL(this.mattToLayer(i))}`)}sortOblp(t){return[...t].sort().join("")}}return t});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squanlib",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "squan helper toolkit",
5
5
  "type": "module",
6
6
  "main": "./squanlib.js",
package/squanlib.js CHANGED
@@ -63,7 +63,6 @@ export default class SquanLib {
63
63
  "d2": "-1,5", "d2'": "1,-5",
64
64
  "K": "5,2", "K'": "-5,-2",
65
65
  "k": "2,5", "k'": "-2,-5",
66
- "A": "1,0", "A'": "-1,0",
67
66
  "G": "5,-4", "G'": "-5,4",
68
67
  "g": "4,-5", "g'": "-4,5",
69
68
  };
@@ -270,10 +269,10 @@ export default class SquanLib {
270
269
  * GOOD_FINISHES: moves that are acceptable as the last move
271
270
  */
272
271
  static GOOD_FINISHES = new Set([
273
- "11", "-1-1", "22", "-2-2", "2-1", "-21", "1-2", "-12",
274
- "30", "-30", "03", "0-3", "33", "3-3", "-3-3", "-33",
275
- "41", "-4-1", "14", "-1-4", "2-4", "-24", "4-2", "-42",
276
- "5-1", "-51", "-45", "-54", "63",
272
+ "1,1", "-1,-1", "2,2", "-2,-2", "2,-1", "-2,1", "1,-2", "-1,2",
273
+ "3,0", "-3,0", "0,3", "0,-3", "3,3", "3,-3", "-3,-3", "-3,3",
274
+ "4,1", "-4,-1", "1,4", "-1,-4", "2,-4", "-2,4", "4,-2", "-4,2",
275
+ "5,-1", "-5,1", "-4,5", "-5,4", "6,3",
277
276
  ]);
278
277
 
279
278
  /**
@@ -710,14 +709,6 @@ export default class SquanLib {
710
709
  // overrides
711
710
  if (alg in this.tempReplacements) return this.tempReplacements[alg];
712
711
 
713
- // p scrambles
714
- let isPScramble = /^p[ /\\|]/.test(alg);
715
- let startingSlice;
716
- if (isPScramble) {
717
- startingSlice = alg.charAt(1) === " " ? "/" : alg.charAt(1);
718
- alg = alg.slice(2, -3);
719
- }
720
-
721
712
  // legacy character substitutions
722
713
  alg = alg
723
714
  .replaceAll('&', '-1')
@@ -726,6 +717,17 @@ export default class SquanLib {
726
717
  .replaceAll('8', '-4')
727
718
  .replaceAll('7', '-5');
728
719
 
720
+ // remove potential move counts, comments
721
+ alg = alg.replaceAll(/\[.*?\]/g, "");
722
+
723
+ // p scrambles
724
+ let isPScramble = /^p[ /\\|]/.test(alg);
725
+ let startingSlice;
726
+ if (isPScramble) {
727
+ startingSlice = alg.charAt(1) === " " ? "/" : alg.charAt(1);
728
+ alg = alg.slice(2, -3);
729
+ }
730
+
729
731
  // expand move groups, e.g. "(U U')3" → "U U' U U' U U'"
730
732
  for (const group of alg.matchAll(/(\(.*?\))(\d+)/g)) {
731
733
  const inner = group[1].replaceAll(/[()]/g, '');
@@ -1031,10 +1033,22 @@ export default class SquanLib {
1031
1033
  // now go through scramble move by move to apply base karn
1032
1034
  let s = alg.split(" ").filter(Boolean);
1033
1035
  for (let i = 0; i < s.length; i++) {
1034
- if (i === 0 && !startsSlice) continue;
1035
- if (i === s.length - 1 && !endsSlice) break;
1036
+ if (i === 0 && !startsSlice) {
1037
+ // even if it's in base karn, we can't karnify
1038
+ s[i] = s[i].replace(",", "");
1039
+ continue;
1040
+ }
1041
+ if (i === s.length - 1 && !endsSlice) {
1042
+ // even if it's in base karn, we can't karnify
1043
+ s[i] = s[i].replace(",", "");
1044
+ break;
1045
+ }
1036
1046
  // good to replace
1037
- s[i] = SquanLib.wcaToBaseKarn[s[i]] ? SquanLib.wcaToBaseKarn[s[i]] : s[i].replace(",", "");
1047
+ let inBaseKarn = s[i] in SquanLib.wcaToBaseKarn;
1048
+ s[i] = inBaseKarn ? SquanLib.wcaToBaseKarn[s[i]] : s[i].replace(",", "");
1049
+ // prevent an additional leading slice for first move karn
1050
+ if (inBaseKarn && i === 0) startingSlice = startingSlice.replace("/", "");
1051
+ if (inBaseKarn && i === s.length - 1) endingSlice = "";
1038
1052
  }
1039
1053
 
1040
1054
  alg = startingSlice + s.join(" ") + endingSlice;
@@ -1359,16 +1373,32 @@ export default class SquanLib {
1359
1373
  rated = true;
1360
1374
 
1361
1375
  if (rated && ["/", "\\", "|"].includes(sliceStart)) {
1362
- // Replace the first '/' in the alg-only portion of the display line.
1363
- const slashPos = line.indexOf('/');
1364
- if (slashPos >= 0)
1365
- result.alg = line.slice(0, slashPos) + sliceStart + line.slice(slashPos + 1);
1376
+ result.alg = this.injectSliceStart(line, sliceStart);
1366
1377
  }
1367
1378
 
1368
1379
  return result;
1369
1380
  }).sort((a, b) => b.score - a.score);
1370
1381
  }
1371
1382
 
1383
+ /**
1384
+ * injectSliceStart: injects the slice start into an alg
1385
+ *
1386
+ * @param {string} alg the alg. no extra spaces allowed
1387
+ * @param {string} sliceStart " " | "/" | "\\" | "|"
1388
+ * @returns {string} the alg with slice start injected at the first slice
1389
+ */
1390
+ injectSliceStart(alg, sliceStart) {
1391
+ let moreThan1 = /[/\\| ]/.test(alg); // is there ANY slice chars?
1392
+ let firstMove = moreThan1 ? alg.match(/^([^/\\| ]*)[/\\| ]/)?.[1] : alg;
1393
+ // only tests if it's a karn
1394
+ if (firstMove in SquanLib.karnToWCA) return sliceStart + alg;
1395
+ if (!moreThan1) return alg; // no slice to inject to
1396
+
1397
+ // guaranteed to have a slice
1398
+ const slashPos = alg.search(/[/\\| ]/);
1399
+ return alg.slice(0, slashPos) + sliceStart + alg.slice(slashPos + 1);
1400
+ }
1401
+
1372
1402
  // =========================================================================
1373
1403
  // SECTION 8: ALG TRANSFORM
1374
1404
  // =========================================================================
@@ -1389,28 +1419,38 @@ export default class SquanLib {
1389
1419
  /**
1390
1420
  * compl: get the complement of a move
1391
1421
  *
1392
- * @param {string} a a move without commas, e.g. "-12"
1393
- * @returns {string} the complement move
1394
- * @example "-12" → "5-4"
1422
+ * @param {string} a a move
1423
+ * @returns {string} the complement move with commas
1424
+ * @example "-12" → "5,-4"; "-1,2" → "5,-4"
1395
1425
  */
1396
1426
  compl(a) {
1397
1427
  if (!a) return a;
1398
- const inx = this.sepIndex(a);
1399
- return String(this.legalMove(6 + parseInt(a.slice(0, inx), 10))) +
1400
- String(this.legalMove(6 + parseInt(a.slice(inx), 10)));
1428
+ let u, d;
1429
+ if (a.includes(',')) [u, d] = a.split(",");
1430
+ else {
1431
+ const inx = this.sepIndex(a);
1432
+ [u, d] = [a.slice(0, inx), a.slice(inx)];
1433
+ }
1434
+ return String(this.legalMove(6 + parseInt(u, 10))) + "," +
1435
+ String(this.legalMove(6 + parseInt(d, 10)));
1401
1436
  }
1402
1437
 
1403
1438
  /**
1404
1439
  * lf: get the layer flip of a move
1405
1440
  *
1406
- * @param {string} a a move without commas, e.g. "-12"
1441
+ * @param {string} a a move
1407
1442
  * @returns {string} the layer flip move
1408
- * @example "-12" → "2-1"
1443
+ * @example "-12" → "2,-1"; "-1,2" → "2,-1"
1409
1444
  */
1410
1445
  lf(a) {
1411
1446
  if (!a) return a;
1412
- const inx = this.sepIndex(a);
1413
- return a.slice(inx) + a.slice(0, inx);
1447
+ let u, d;
1448
+ if (a.includes(',')) [u, d] = a.split(",");
1449
+ else {
1450
+ const inx = this.sepIndex(a);
1451
+ [u, d] = [a.slice(0, inx), a.slice(inx)];
1452
+ }
1453
+ return d + "," + u;
1414
1454
  }
1415
1455
 
1416
1456
  /**
@@ -1423,11 +1463,11 @@ export default class SquanLib {
1423
1463
  compact(algIn) {
1424
1464
  let alg = algIn
1425
1465
  .replace(/\[.*?\]/g, "")
1426
- .replace(/[()]/g, "")
1427
- .replaceAll(" ", "").trim();
1466
+ .replace(/[()]/g, "").trim();
1428
1467
  if (this.isKarn(alg)) {
1429
1468
  const numeric = this.unkarnify(alg);
1430
- return numeric.split("/").filter(Boolean).map(m => {
1469
+ return numeric.split("/").map(m => {
1470
+ if (!m) return m;
1431
1471
  if (!m.includes(","))
1432
1472
  throw new Error(
1433
1473
  `algToInternal: m doesn't have commas post karnifying: ${m}`
@@ -1437,7 +1477,7 @@ export default class SquanLib {
1437
1477
  String(this.legalMove(parseInt(d, 10)));
1438
1478
  }).join(" ");
1439
1479
  }
1440
- alg = alg.trim();
1480
+ alg = alg.replaceAll(" ", "");
1441
1481
  if (alg.includes("/")) {
1442
1482
  return alg.split("/").filter(Boolean).map(m => {
1443
1483
  if (!m.includes(",")) m = this.addCommas(m);
@@ -1466,7 +1506,8 @@ export default class SquanLib {
1466
1506
  * @returns {number} how many positions the alg can y2 at
1467
1507
  */
1468
1508
  countY2Positions(algIn) {
1469
- const segs = this.compact(algIn).split(" ").filter(p => p);
1509
+ // spaces ARE slices, cannot trim or do anything like that
1510
+ const segs = this.compact(algIn).split(" ");
1470
1511
  return Math.max(0, segs.length - 3);
1471
1512
  }
1472
1513
 
@@ -1618,7 +1659,7 @@ export default class SquanLib {
1618
1659
  isOBLCase(l, target) {
1619
1660
  const targetPattern = Object.entries(SquanLib.OBLToEnglish)
1620
1661
  .find(([, v]) => v === target
1621
- )?.[0];
1662
+ )?.[0];
1622
1663
  if (!targetPattern) return false;
1623
1664
  // to corner first
1624
1665
  if (l[0] !== l[0].toUpperCase()) l = this.shift(l, -1);