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}