demo-modes.rs

2.5 kB · rust · 76 lines

1use mrlycore::errors::Result;2use mrlyfig::board::{Board, Frame};3use mrlyfig::ink::Ramp;4use mrlyfig::{field, ink, save};5use mrlymath::two;6use std::f64::consts::TAU;78const CODE: u128 = 495;9const SIDE: usize = 3;10const LEVEL: usize = 5;11const SPAN: usize = 243;12const CELL: f64 = 3.0;13const FLOOR: f64 = 0.09;14const REACH: f64 = 0.60;1516fn digits() -> Result<Vec<(usize, usize)>> {17    let tile = two::designs::create(CODE, SIDE, 1, 0, SIDE)?;18    let types = tile.types();19    Ok((0..SIDE)20        .flat_map(|a| (0..SIDE).map(move |b| (a, b)))21        .filter(|&(a, b)| types.get(&[a, b]) != 0)22        .collect())23}2425fn modulus(digits: &[(usize, usize)], t1: usize, t2: usize) -> f64 {26    let (mut re, mut im) = (1.0, 0.0);27    let mut scale = 1usize;28    for _ in 0..LEVEL {29        let (mut fr, mut fi) = (0.0, 0.0);30        for &(a, b) in digits {31            let angle = TAU * (((a * t1 + b * t2) % SPAN) * scale % SPAN) as f64 / SPAN as f64;32            fr += angle.cos();33            fi += angle.sin();34        }35        let next = (re * fr - im * fi, re * fi + im * fr);36        re = next.0;37        im = next.1;38        scale = scale * SIDE % SPAN;39    }40    re.hypot(im)41}4243fn main() -> Result<()> {44    let digits = digits()?;45    assert_eq!(digits.len(), 8);46    let mass = (digits.len() as f64).powi(LEVEL as i32);47    assert_eq!(mass, 32768.0);48    let half = SPAN / 2;49    let mut ratios = Vec::with_capacity(SPAN * SPAN);50    for row in 0..SPAN {51        for col in 0..SPAN {52            let t1 = (row + SPAN - half) % SPAN;53            let t2 = (col + SPAN - half) % SPAN;54            ratios.push(modulus(&digits, t1, t2) / mass);55        }56    }57    assert_eq!(ratios.len(), 59049);58    assert!((ratios[half * SPAN + half] - 1.0).abs() < 1e-9);59    let mut sorted = ratios.clone();60    sorted.sort_by(|a, b| b.partial_cmp(a).expect("a field of finite ratios"));61    assert!((sorted[1] - 0.125).abs() < 1e-9);62    assert_eq!(ratios.iter().filter(|&&v| v >= 0.1).count(), 25);63    let reads: Vec<f64> = ratios64        .iter()65        .map(|v| ((v.powf(1.0 / LEVEL as f64) - FLOOR) / (REACH - FLOOR)).clamp(0.0, 1.0))66        .collect();6768    let ramp = Ramp::new(vec![ink::ground(), ink::blue(), ink::yellow()]);69    let mut board = Board::square();70    let plate = CELL * SPAN as f64;71    let edge = ((board.width as f64 - plate) / 2.0).floor();72    let frame = Frame::new(edge, edge, plate, plate);73    field::draw_range(&mut board, frame, SPAN, SPAN, &reads, (0.0, 1.0), &ramp);74    save("demo-modes", &board)?;75    Ok(())76}