research-spectra.ts
2.0 kB · typescript · 49 lines
1import * as math from "mrlyjs/math";2import { hex } from "mrlyjs/view";3import type { Ink, Pen } from "mrlyjs/view";45export const units = { math };67const BASE = 5;8const LEVEL = 2;9const SIDE = 25;10const MIDDLE = (3 * (SIDE - 1)) / 2;1112type Slice = ReturnType<typeof math.six.cut>;1314let memo: { all: Slice; middle: Slice } | undefined;1516function slices() {17 if (memo) return memo;18 const carpet = math.three.carpet(BASE, LEVEL);19 const types = new Uint8Array(carpet.types.length);20 for (const [x, y, z] of math.three.diagonal_slice(math.bang.levels_code(3, 2, [0, 1]), BASE, LEVEL, 2, MIDDLE)) {21 const i = (x * SIDE + y) * SIDE + z;22 if (carpet.types[i] !== 1) throw new Error(`research-spectra: the middle plane cell ${x},${y},${z} is not in the carpet`);23 types[i] = 1;24 }25 memo = { all: math.six.cut(carpet), middle: math.six.cut({ shape: carpet.shape, types }) };26 return memo;27}2829function at(slice: Slice, row: number, col: number) {30 const width = slice.cell.shape[1];31 return slice.cell.types[row * width + col + (width - hex.row_len(SIDE, row)) / 2];32}3334export default function draw(pen: Pen, ink: Ink) {35 const { all, middle } = slices();36 const FILL = math.six.FILL();37 if (math.six.height(all) !== 2 * SIDE) throw new Error(`research-spectra: the cut is ${math.six.height(all)} rows, want ${2 * SIDE}`);38 let drawn = 0;39 for (let row = 0; row < 2 * SIDE; row++) {40 for (let col = 0; col < hex.row_len(SIDE, row); col++) {41 if (at(all, row, col) === FILL) drawn++;42 else if (at(middle, row, col) === FILL) throw new Error(`research-spectra: a middle triangle at ${row},${col} is not a fill`);43 }44 }45 if (drawn !== math.six.fills(all)) throw new Error(`research-spectra: the hexagon holds ${drawn} of ${math.six.fills(all)} fills`);46 const frame = pen.frame(0.08);47 hex.hexagon(pen, frame, SIDE, 0, (row, col) => (at(middle, row, col) === FILL ? ink.yellow : null));48 hex.hexagon(pen, frame, SIDE, 1.2, (row, col) => (at(all, row, col) === FILL && at(middle, row, col) !== FILL ? ink.blue : null));49}