import { Color } from "./color"; import { PuzzleInterface, STANDARD_PALETTE } from "./constants"; import { randomCSSId } from "./strings"; import { getRoundedPath } from "./utils"; export function SKEWB(): PuzzleInterface { const skewb: PuzzleInterface = { palette: STANDARD_PALETTE, move: () => true, }; const ID = randomCSSId(); type FaceName = "U" | "R" | "F" | "D" | "L" | "B"; type FaceColor = keyof typeof STANDARD_PALETTE; const FACE_COLOR: Record = { U: "white", R: "red", F: "green", D: "yellow", L: "orange", B: "blue", }; const faces: Record = { U: ["U", "U", "U", "U", "U"], // C1, C2, C3, C4 (clockwise), CENTER R: ["R", "R", "R", "R", "R"], F: ["F", "F", "F", "F", "F"], D: ["D", "D", "D", "D", "D"], L: ["L", "L", "L", "L", "L"], B: ["B", "B", "B", "B", "B"], }; function update( NU: FaceName[], NR: FaceName[], NF: FaceName[], ND: FaceName[], NL: FaceName[], NB: FaceName[], ) { faces.U = NU; faces.R = NR; faces.F = NF; faces.D = ND; faces.L = NL; faces.B = NB; } function pick(arr: FaceName[], indexes: number[]): FaceName[] { return indexes.map((n) => arr[n]); } const cycles: Record void> = { R: (dir: number) => { const times = ((dir % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NU = [faces.U[0], faces.F[2], ...pick(faces.U, [2, 3, 4])]; const NR = [faces.R[0], ...faces.D.slice(1)]; const NF = faces.F.map((v, p) => (p === 2 ? faces.L[3] : v)); const ND = [faces.D[0], ...pick(faces.B, [2, 3, 0, 4])]; const NL = faces.L.map((v, p) => (p === 3 ? faces.U[1] : v)); const NB = pick(faces.R, [3, 0, 1, 2, 4]).map((v, p) => p === 1 ? faces.B[1] : v, ); update(NU, NR, NF, ND, NL, NB); } }, L: (dir: number) => { const times = ((dir % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NU = faces.U.map((v, p) => (p === 3 ? faces.B[2] : v)); const NR = faces.R.map((v, p) => (p === 3 ? faces.U[3] : v)); const NF = pick(faces.L, [3, 1, 1, 2, 4]).map((v, p) => p === 1 ? faces.F[1] : v, ); const ND = pick(faces.F, [3, 0, 1, 2, 4]).map((v, p) => p === 2 ? faces.D[2] : v, ); const NL = pick(faces.D, [0, 3, 0, 1, 4]).map((v, p) => p === 0 ? faces.L[0] : v, ); const NB = faces.B.map((v, p) => (p === 2 ? faces.R[3] : v)); update(NU, NR, NF, ND, NL, NB); } }, U: (dir: number) => { const times = ((dir % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NU = pick(faces.B, [1, 2, 0, 0, 4]).map((v, p) => p === 2 ? faces.U[2] : v, ); const NR = faces.R.map((v, p) => (p === 1 ? faces.D[3] : v)); const NF = faces.F.map((v, p) => (p === 0 ? faces.R[1] : v)); const ND = faces.D.map((v, p) => (p === 3 ? faces.F[0] : v)); const NL = faces.U.map((v, p) => (p === 2 ? faces.L[2] : v)); const NB = pick(faces.L, [3, 0, 1, 0, 4]).map((v, p) => p === 3 ? faces.B[3] : v, ); update(NU, NR, NF, ND, NL, NB); } }, B: (dir: number) => { const times = ((dir % 3) + 3) % 3; for (let i = 0; i < times; i += 1) { const NU = faces.U.map((v, p) => (p === 0 ? faces.R[2] : v)); const NR = faces.R.map((v, p) => (p === 2 ? faces.F[3] : v)); const NF = faces.F.map((v, p) => (p === 3 ? faces.U[0] : v)); const ND = faces.L.map((v, p) => (p === 1 ? faces.D[1] : v)); const NL = pick(faces.B, [3, 0, 1, 2, 4]).map((v, p) => p === 1 ? faces.L[1] : v, ); const NB = pick(faces.D, [0, 2, 3, 0, 4]).map((v, p) => p === 0 ? faces.B[0] : v, ); update(NU, NR, NF, ND, NL, NB); } }, }; const moveMap = "FURLBfrlbxyz"; skewb.move = function (moves: any[]) { moves.forEach((mv) => { cycles[moveMap[mv[0]]](mv[1]); }); }; skewb.getImage = () => { const BOX = 100; const W = BOX * 4; const H = BOX * 3; const BOX_FACTOR = 0.9; const BOX_OFFSET = (BOX * (1 - BOX_FACTOR)) / 2; const classMap: Map = new Map(); const drawFace = (bx: number, by: number, fn: FaceName[]) => { const rx = bx * BOX + BOX_OFFSET; const ry = by * BOX + BOX_OFFSET; const BX = BOX * BOX_FACTOR; const BX2 = BX / 2; // const cols = fn.map((c) => STANDARD_PALETTE[FACE_COLOR[c]]); [ [ fn[0], ``, ], [ fn[1], ``, ], [ fn[2], ``, ], [ fn[3], ``, ], [ fn[4], ``, ], ].forEach(([c, path]) => { if (!classMap.has(c)) { classMap.set(c, [path]); } else { classMap.get(c)!.push(path); } }); }; drawFace(1, 0, faces.U); drawFace(0, 1, faces.L); drawFace(1, 1, faces.F); drawFace(2, 1, faces.R); drawFace(3, 1, faces.B); drawFace(1, 2, faces.D); return [ ``, ``, ...Array.from(classMap.entries()).map(([c, paths]) => { return `${paths.join("")}`; }), ``, ].join(""); }; return skewb; }