research-spin.rs

2.4 kB · rust · 73 lines

1use mrlycore::errors::Result;2use mrlyfig::board::Board;3use mrlyfig::ink::Ramp;4use mrlyfig::{ink, save};5use mrlymath::two;6use mrlynum::spin;78const LEVEL: usize = 5;9const SIDE: usize = 243;10const RINGS: usize = 1600;1112fn mirror(cell: &two::Cell2d) -> Vec<f32> {13    let span = 2 * SIDE;14    let types = cell.types();15    let mut out = vec![0f32; span * span];16    for row in 0..span {17        let y = if row < SIDE {18            SIDE - 1 - row19        } else {20            row - SIDE21        };22        for col in 0..span {23            let x = if col < SIDE {24                SIDE - 1 - col25            } else {26                col - SIDE27            };28            out[row * span + col] = types.get(&[y, x]) as f32;29        }30    }31    out32}3334fn main() -> Result<()> {35    let carpet = two::designs::create(495, 3, LEVEL, 0, 3)?;36    assert_eq!(carpet.width(), SIDE);37    assert_eq!(carpet.types().sum(), 8u64.pow(LEVEL as u32));38    let span = 2 * SIDE;39    let board_data = mirror(&carpet);40    let profile: Vec<f64> = (0..=RINGS)41        .map(|k| spin::ring(&board_data, span, SIDE as f64 * k as f64 / RINGS as f64))42        .collect();43    assert!((profile[0] - 1.0).abs() < 1e-9);44    let lo = profile.iter().copied().fold(f64::MAX, f64::min);45    let hi = profile.iter().copied().fold(f64::MIN, f64::max);46    assert!(hi - lo > 0.5);4748    let ramp = Ramp::new(vec![ink::ground(), ink::blue(), ink::yellow()]);49    let mut board = Board::square();50    let frame = board.frame(0.08);51    let (cx, cy) = frame.center();52    let reach = frame.radius();53    let x0 = (cx - reach - 1.0).max(0.0) as usize;54    let y0 = (cy - reach - 1.0).max(0.0) as usize;55    let x1 = ((cx + reach + 1.0) as usize).min(board.width);56    let y1 = ((cy + reach + 1.0) as usize).min(board.height);57    for py in y0..y1 {58        for px in x0..x1 {59            let d = ((px as f64 + 0.5 - cx).powi(2) + (py as f64 + 0.5 - cy).powi(2)).sqrt();60            let cover = (reach + 0.5 - d).clamp(0.0, 1.0);61            if cover <= 0.0 {62                continue;63            }64            let t = (d / reach) * RINGS as f64;65            let i = (t.floor() as usize).min(RINGS - 1);66            let f = t - i as f64;67            let value = profile[i] * (1.0 - f) + profile[i + 1] * f;68            board.blend(px, py, ramp.at((value - lo) / (hi - lo)), cover);69        }70    }71    save("research-spin", &board)?;72    Ok(())73}