/** * Copyright (C) 2023 Shuang Chen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ----------------------------------------------------------------------- Modified by Isaac Vega */ import { acycle, coord, fillFacelet, rn, Solver } from "../lib/mathlib"; import { regScrambler } from "./scramble"; /** 1 2 U 0 LFRB 3 4 D */ //centers: U R F B L D //twstcor: URF ULB DRB DLF //fixedco: UBR UFL DFR DBL const fixedCorn = [ [4, 16, 7], // U4 B1 R2 [1, 11, 22], // U1 F1 L2 [26, 14, 8], // D1 F4 R3 [29, 19, 23], // D4 B4 L3 ]; const twstCorn = [ [3, 6, 12], // U3 R1 F2 [2, 21, 17], // U2 L1 B2 [27, 9, 18], // D2 R4 B3 [28, 24, 13], // D3 L4 F3 ]; function checkNoBar(perm: number, _twst: number) { const corner = cpcord.set([], perm % 12); const center = ctcord.set([], ~~(perm / 12)); const fixedtwst = ftcord.set([], _twst % 81); const twst = twcord.set([], ~~(_twst / 81)); const f = []; for (let i = 0; i < 6; i++) { f[i * 5] = center[i]; } fillFacelet(fixedCorn, f, [0, 1, 2, 3], fixedtwst, 5); fillFacelet(twstCorn, f, corner, twst, 5); for (let i = 0; i < 30; i += 5) { for (let j = 1; j < 5; j++) { if (f[i] == f[i + j]) { return false; } } } return true; } const moveCenters = [ [0, 3, 1], [0, 2, 4], [1, 5, 2], [3, 4, 5], ]; const moveCorners = [ [0, 1, 2], [0, 3, 1], [0, 2, 3], [1, 3, 2], ]; const ctcord = new coord("p", 6, -1); const cpcord = new coord("p", 4, -1); const ftcord = new coord("o", 4, 3); const twcord = new coord("o", 4, -3); function ctcpMove(idx: number, m: any) { const corner = cpcord.set([], idx % 12); const center = ctcord.set([], ~~(idx / 12)); acycle(center, moveCenters[m]); acycle(corner, moveCorners[m]); return ctcord.get(center) * 12 + cpcord.get(corner); } function twstMove(idx: number, move: any) { const fixedtwst = ftcord.set([], idx % 81); const twst = twcord.set([], ~~(idx / 81)); fixedtwst[move]++; acycle(twst, moveCorners[move], 1, [0, 2, 1, 3]); return twcord.get(twst) * 81 + ftcord.get(fixedtwst); } const solv = new Solver(4, 2, [ [0, ctcpMove, 4320], [0, twstMove, 2187], ]); const solvivy = new Solver(4, 2, [ [ 0, function (idx: number, m: any) { return ~~(ctcpMove(idx * 12, m) / 12); }, 360, ], [ 0, function (idx: number, m: any) { return twstMove(idx, m) % 81; }, 81, ], ]); function sol2str(sol: any) { const ret = []; const move2str: any = ["L", "R", "B", "U"]; //RLDB (in jaap's notation) rotated by z2 for (let i = 0; i < sol.length; i++) { const axis = sol[i][0]; const pow = 1 - sol[i][1]; if (axis == 2) { //step two. acycle(move2str, [0, 3, 1], pow + 1); } ret.push(move2str[axis] + (pow == 1 ? "'" : "")); } return ret.join(" "); } const ori = [0, 1, 2, 0, 2, 1, 1, 2, 0, 2, 1, 0]; export function getScramble(type: string) { let perm, twst; const lim = type == "skbso" ? 6 : 2; const minl = type == "skbo" ? 0 : 8; do { perm = rn(4320); twst = rn(2187); } while ( (perm == 0 && twst == 0) || ori[perm % 12] != (twst + ~~(twst / 3) + ~~(twst / 9) + ~~(twst / 27)) % 3 || solv.search([perm, twst], 0, lim) != null || (type == "skbnb" && !checkNoBar(perm, twst)) ); return sol2str(solv.search([perm, twst], minl)!.reverse()); } function getScrambleIvy(type: string) { let perm, twst, lim = 1, maxl = type == "ivyso" ? 6 : 0; do { perm = rn(360); twst = rn(81); } while ((perm == 0 && twst == 0) || solvivy.search([perm, twst], 0, lim) != null); return solvivy.toStr(solvivy.search([perm, twst], maxl)!.reverse(), "RLDB", "' "); } regScrambler(["skbo", "skbso", "skbnb"], getScramble)(["ivyo", "ivyso"], getScrambleIvy);