paper-gasket-ray-machine.rs

2.3 kB · rust · 76 lines

1use mrlycore::errors::Result;2use mrlyfig::{ink, save, Board};3use mrlymath::two::designs;4use mrlynum::classics::{fibonacci, gcd};5use std::collections::HashMap;67const LEVEL: usize = 5;89fn main() -> Result<()> {10    let cell = designs::from_corners(&[vec![0, 0], vec![1, 0], vec![0, 1]], 3, LEVEL, 0, 3)?;11    let side = cell.width();12    let types = cell.types();13    let mut points = Vec::new();14    for row in 0..side {15        for col in 0..side {16            if types.get(&[row, col]) != 0 {17                points.push((row, col));18            }19        }20    }21    assert_eq!(side, 3usize.pow(LEVEL as u32));22    assert_eq!(points.len(), 3usize.pow(LEVEL as u32));2324    let mut rays: HashMap<(usize, usize), Vec<(usize, usize)>> = HashMap::new();25    for point in &points {26        if *point == (0, 0) {27            continue;28        }29        let step = gcd(point.0 as u128, point.1 as u128) as usize;30        rays.entry((point.0 / step, point.1 / step))31            .or_default()32            .push(*point);33    }34    let ladder = fibonacci(1000);35    let shift = rays[&(1, 3)].len();36    assert_eq!(shift, ladder[LEVEL] - 1);37    assert_eq!(rays[&(3, 1)].len(), shift);3839    let mut board = Board::square();40    let frame = board.frame(0.08);41    let reach = points42        .iter()43        .map(|point| point.0.max(point.1))44        .max()45        .expect("the gasket holds a point") as f64;46    let step = frame.w / reach;47    let at = |point: &(usize, usize)| {48        (49            frame.x + point.1 as f64 * step,50            frame.y + frame.h - point.0 as f64 * step,51        )52    };53    let origin = at(&(0, 0));54    let mut order: Vec<_> = rays.iter().collect();55    order.sort_by_key(|(ray, on)| (on.len(), **ray));56    for (ray, on) in order {57        let far = on58            .iter()59            .max_by_key(|point| point.0 + point.1)60            .expect("a ray holds a point");61        let mass = on.len() as f64;62        let gold = *ray == (1, 3) || *ray == (3, 1);63        let color = if gold {64            ink::yellow()65        } else {66            ink::fade(ink::blue(), (0.16 + 0.13 * (mass - 1.0)).min(1.0))67        };68        board.segment(origin, at(far), if gold { 3.0 } else { 1.6 }, color);69    }70    for point in &points {71        let (x, y) = at(point);72        board.disc(x, y, 2.8, ink::fg());73    }74    save("paper-gasket-ray-machine", &board)?;75    Ok(())76}