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}