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}