demo-weights.rs
2.7 kB · rust · 89 lines
1use mrlycore::errors::Result;2use mrlyfig::board::{Board, Frame};3use mrlyfig::ink::Ramp;4use mrlyfig::{field, ink, save};5use mrlymath::two;67const CODE: u128 = 495;8const SIDE: usize = 3;9const LEVEL: usize = 5;10const SPAN: usize = 243;11const MARGIN: f64 = 0.08;12const GAMMA: f64 = 0.12;13const SHARES: [f64; 8] = [5.0, 4.0, 3.0, 4.0, 2.0, 3.0, 2.0, 1.0];14const WHOLE: f64 = 24.0;1516fn corners() -> 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 mass(corners: &[(usize, usize)]) -> Vec<f64> {26 let mut wide = 1usize;27 let mut field = vec![1.0f64];28 for _ in 0..LEVEL {29 let next = wide * SIDE;30 let mut grown = vec![0.0f64; next * next];31 for row in 0..wide {32 for col in 0..wide {33 let held = field[row * wide + col];34 if held == 0.0 {35 continue;36 }37 for (at, &(a, b)) in corners.iter().enumerate() {38 grown[(row * SIDE + a) * next + col * SIDE + b] = held * SHARES[at] / WHOLE;39 }40 }41 }42 field = grown;43 wide = next;44 }45 field46}4748fn main() -> Result<()> {49 let corners = corners()?;50 assert_eq!(51 corners,52 vec![53 (0, 0),54 (0, 1),55 (0, 2),56 (1, 0),57 (1, 2),58 (2, 0),59 (2, 1),60 (2, 2)61 ]62 );63 let field = mass(&corners);64 assert_eq!(field.len(), SPAN * SPAN);65 assert_eq!(field.iter().filter(|&&m| m > 0.0).count(), 32768);66 assert!((field.iter().sum::<f64>() - 1.0).abs() < 1e-12);67 let peak = field.iter().copied().fold(f64::MIN, f64::max);68 let least = field69 .iter()70 .copied()71 .filter(|&m| m > 0.0)72 .fold(f64::MAX, f64::min);73 assert!((peak - (5.0f64 / WHOLE).powi(LEVEL as i32)).abs() < 1e-15);74 assert!((least - (1.0f64 / WHOLE).powi(LEVEL as i32)).abs() < 1e-15);75 assert!((peak / least - 3125.0).abs() < 1e-9);76 let reads: Vec<f64> = field77 .iter()78 .map(|&m| if m > 0.0 { (m / peak).powf(GAMMA) } else { 0.0 })79 .collect();8081 let ramp = Ramp::new(vec![ink::ground(), ink::blue(), ink::yellow()]);82 let mut board = Board::square();83 let edge = (board.width as f64 * MARGIN).round();84 let plate = board.width as f64 - 2.0 * edge;85 let frame = Frame::new(edge, edge, plate, plate);86 field::draw_range(&mut board, frame, SPAN, SPAN, &reads, (0.0, 1.0), &ramp);87 save("demo-weights", &board)?;88 Ok(())89}