import { PuzzleInterface, STANDARD_PALETTE } from "./constants"; import { randomCSSId } from "./strings"; export function PYRAMINX(): PuzzleInterface { const pyra: PuzzleInterface = { palette: STANDARD_PALETTE, move: () => true, }; const ID = randomCSSId(); type FaceName = "F" | "R" | "L" | "D"; const faces: Record = { F: ["F", "F", "F", "F", "F", "F", "F", "F", "F"], R: ["R", "R", "R", "R", "R", "R", "R", "R", "R"], L: ["L", "L", "L", "L", "L", "L", "L", "L", "L"], D: ["D", "D", "D", "D", "D", "D", "D", "D", "D"], }; function update( NF: FaceName[], NR: FaceName[], NL: FaceName[], ND: FaceName[], ) { faces.F = NF; faces.R = NR; faces.L = NL; faces.D = ND; } // URLB const cycles = { U: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = [0, -1, -1, 3, -1, 5, 6, -1, -1].map((v, p) => v < 0 ? faces.F[p] : faces.R[v], ); const NR = [1, -1, -1, 4, -1, 3, 7, -1, -1].map((v, p) => v < 0 ? faces.R[p] : faces.L[v], ); const NL = [-1, 0, -1, 5, 3, -1, -1, 6, -1].map((v, p) => v < 0 ? faces.L[p] : faces.F[v], ); const ND = [...faces.D]; update(NF, NR, NL, ND); } }, R: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = [-1, -1, 0, -1, 5, 3, -1, -1, 6].map((v, p) => v < 0 ? faces.F[p] : faces.D[v], ); const NR = [-1, 2, -1, 4, 5, -1, -1, 8, -1].map((v, p) => v < 0 ? faces.R[p] : faces.F[v], ); const NL = [...faces.L]; const ND = [1, -1, -1, 4, -1, 3, 7, -1, -1].map((v, p) => v < 0 ? faces.D[p] : faces.R[v], ); update(NF, NR, NL, ND); } }, L: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = [-1, 0, -1, 5, 3, -1, -1, 6, -1].map((v, p) => v < 0 ? faces.F[p] : faces.L[v], ); const NR = [...faces.R]; const NL = [1, -1, -1, 4, -1, 3, 7, -1, -1].map((v, p) => v < 0 ? faces.L[p] : faces.D[v], ); const ND = [-1, 1, -1, 3, 4, -1, -1, 7, -1].map((v, p) => v < 0 ? faces.D[p] : faces.F[v], ); update(NF, NR, NL, ND); } }, B: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = [...faces.F]; const NR = [-1, -1, 2, -1, 4, 5, -1, -1, 8].map((v, p) => v < 0 ? faces.R[p] : faces.D[v], ); const NL = [-1, -1, 2, -1, 4, 5, -1, -1, 8].map((v, p) => v < 0 ? faces.L[p] : faces.R[v], ); const ND = [-1, -1, 2, -1, 4, 5, -1, -1, 8].map((v, p) => v < 0 ? faces.D[p] : faces.L[v], ); update(NF, NR, NL, ND); } }, u: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = faces.F.map((v, p) => (p === 0 ? faces.R[0] : v)); const NR = faces.R.map((v, p) => (p === 0 ? faces.L[1] : v)); const NL = faces.L.map((v, p) => (p === 1 ? faces.F[0] : v)); const ND = [...faces.D]; update(NF, NR, NL, ND); } }, r: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = faces.F.map((v, p) => (p === 2 ? faces.D[0] : v)); const NR = faces.R.map((v, p) => (p === 1 ? faces.F[2] : v)); const NL = [...faces.L]; const ND = faces.D.map((v, p) => (p === 0 ? faces.R[1] : v)); update(NF, NR, NL, ND); } }, l: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = faces.F.map((v, p) => (p === 1 ? faces.L[0] : v)); const NR = [...faces.R]; const NL = faces.L.map((v, p) => (p === 0 ? faces.D[1] : v)); const ND = faces.D.map((v, p) => (p === 1 ? faces.F[1] : v)); update(NF, NR, NL, ND); } }, b: (count: number) => { const times = ((count % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NF = [...faces.F]; const NR = faces.R.map((v, p) => (p === 2 ? faces.D[2] : v)); const NL = faces.L.map((v, p) => (p === 2 ? faces.R[2] : v)); const ND = faces.D.map((v, p) => (p === 2 ? faces.L[2] : v)); update(NF, NR, NL, ND); } }, }; pyra.move = (moves: any[]) => { moves.forEach((mv) => { if (mv[0] === 0) { (mv[2] === 2 ? cycles.U : cycles.u)(-mv[1]); } else if (mv[0] === 1) { (mv[2] === 2 ? cycles.R : cycles.r)(-mv[1]); } else if (mv[0] === 2) { (mv[2] === 2 ? cycles.L : cycles.l)(-mv[1]); } else if (mv[0] === 3) { (mv[2] === 2 ? cycles.B : cycles.b)(-mv[1]); } }); }; const lookup: Record = { F: 0, D: 1, L: 2, R: 3, }; function getClass(fc: FaceName) { return "c" + lookup[fc]; } pyra.getImage = () => { const classMap: Map = new Map(); const paths = [ [ getClass(faces.F[0]), ``, ], [ getClass(faces.F[1]), ``, ], [ getClass(faces.F[2]), ``, ], [ getClass(faces.F[3]), ``, ], [ getClass(faces.F[4]), ``, ], [ getClass(faces.F[5]), ``, ], [ getClass(faces.F[6]), ``, ], [ getClass(faces.F[7]), ``, ], [ getClass(faces.F[8]), ``, ], [ getClass(faces.D[0]), ``, ], [ getClass(faces.D[1]), ``, ], [ getClass(faces.D[2]), ``, ], [ getClass(faces.D[3]), ``, ], [ getClass(faces.D[4]), ``, ], [ getClass(faces.D[5]), ``, ], [ getClass(faces.D[6]), ``, ], [ getClass(faces.D[7]), ``, ], [ getClass(faces.D[8]), ``, ], [ getClass(faces.L[0]), ``, ], [ getClass(faces.L[1]), ``, ], [ getClass(faces.L[2]), ``, ], [ getClass(faces.L[3]), ``, ], [ getClass(faces.L[4]), ``, ], [ getClass(faces.L[5]), ``, ], [ getClass(faces.L[6]), ``, ], [ getClass(faces.L[7]), ``, ], [ getClass(faces.L[8]), ``, ], [ getClass(faces.R[0]), ``, ], [ getClass(faces.R[1]), ``, ], [ getClass(faces.R[2]), ``, ], [ getClass(faces.R[3]), ``, ], [ getClass(faces.R[4]), ``, ], [ getClass(faces.R[5]), ``, ], [ getClass(faces.R[6]), ``, ], [ getClass(faces.R[7]), ``, ], [ getClass(faces.R[8]), ``, ], ]; paths.forEach((path) => { const val = path[1].replace(/(\d+(\.\d+)?)/g, (match) => { const num = parseFloat(match) / 10; return num.toFixed(2); }); if (classMap.has(path[0])) { classMap.get(path[0])!.push(val); } else { classMap.set(path[0], [val]); } }); return [ ``, ``, ``, ...Array.from(classMap.entries()).map(([cls, path]) => { return `${path.join("")}`; }), ``, ].join(""); }; return pyra; }