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}