wiki-random-walk.rs

2.5 kB · rust · 79 lines

1use mrlycore::errors::Result;2use mrlycore::Rng;3use mrlyfig::{ink, save, Board};45const SIDE: i64 = 64;6const STEPS: usize = 1024;7const HOME: i64 = SIDE / 2;89fn walk(seed: u64) -> Vec<(i64, i64)> {10    let mut rng = Rng::new(seed);11    let mut at = (HOME, HOME);12    let mut trace = Vec::with_capacity(STEPS + 1);13    trace.push(at);14    for _ in 0..STEPS {15        let next = match rng.below(4) {16            0 => (at.0 + 1, at.1),17            1 => (at.0 - 1, at.1),18            2 => (at.0, at.1 + 1),19            _ => (at.0, at.1 - 1),20        };21        at = next;22        trace.push(at);23    }24    trace25}2627fn inside(trace: &[(i64, i64)]) -> bool {28    trace29        .iter()30        .all(|&(x, y)| x >= 0 && x < SIDE && y >= 0 && y < SIDE)31}3233fn reach(trace: &[(i64, i64)]) -> f64 {34    let last = trace[trace.len() - 1];35    let (dx, dy) = ((last.0 - HOME) as f64, (last.1 - HOME) as f64);36    dx.hypot(dy)37}3839fn main() -> Result<()> {40    let typical = (STEPS as f64).sqrt();41    let mut seed = 1u64;42    let mut trace = walk(seed);43    while !inside(&trace) || (reach(&trace) - typical).abs() > 0.08 * typical {44        seed += 1;45        assert!(seed < 20000);46        trace = walk(seed);47    }48    assert_eq!(trace.len(), STEPS + 1);49    assert_eq!(typical, 32.0);50    let visited: std::collections::HashSet<(i64, i64)> = trace.iter().copied().collect();51    assert!(visited.len() > 300 && visited.len() < STEPS);5253    let mut board = Board::square();54    let frame = board.frame(0.08);55    let unit = frame.w / SIDE as f64;56    let spot = |x: i64, y: i64| {57        (58            frame.x + (x as f64 + 0.5) * unit,59            frame.y + (y as f64 + 0.5) * unit,60        )61    };62    for k in 0..=SIDE {63        let at = frame.x + k as f64 * unit;64        let down = frame.y + k as f64 * unit;65        let faint = ink::fade(ink::line(), 0.30);66        board.segment((at, frame.y), (at, frame.y + frame.h), 1.0, faint);67        board.segment((frame.x, down), (frame.x + frame.w, down), 1.0, faint);68    }69    let (hx, hy) = spot(HOME, HOME);70    board.ring(hx, hy, typical * unit, unit * 0.22, ink::fade(ink::dim(), 0.9));71    let pts: Vec<(f64, f64)> = trace.iter().map(|&(x, y)| spot(x, y)).collect();72    board.polyline(&pts, unit * 0.34, ink::fade(ink::blue(), 0.85));73    board.disc(hx, hy, unit * 0.9, ink::yellow());74    let last = trace[trace.len() - 1];75    let (ex, ey) = spot(last.0, last.1);76    board.disc(ex, ey, unit * 0.9, ink::orange());77    save("wiki-random-walk", &board)?;78    Ok(())79}