demo-race.rs
3.6 kB · rust · 127 lines
1use mrlycore::errors::Result;2use mrlycore::Rng;3use mrlyfig::{ink, save, Board, Color, Frame, Grid};4use mrlymath::two;56const NUMBER: usize = 3;7const BASE: usize = 3;8const LEVEL: usize = 4;9const SIDE: usize = 81;10const WALKERS: usize = 300;11const STEPS: usize = 1200;12const SEED: u64 = 7;1314struct Swarm {15 filled: Vec<bool>,16 home: usize,17 at: Vec<usize>,18}1920impl Swarm {21 fn spread(&self) -> f64 {22 let (hr, hc) = ((self.home / SIDE) as f64, (self.home % SIDE) as f64);23 let total: f64 = self24 .at25 .iter()26 .map(|&flat| {27 let (r, c) = ((flat / SIDE) as f64 - hr, (flat % SIDE) as f64 - hc);28 r * r + c * c29 })30 .sum();31 (total / self.at.len() as f64).sqrt()32 }33}3435fn race(code: u128, seed: u64) -> Result<Swarm> {36 let cell = two::create(code, NUMBER, LEVEL, 0, BASE)?;37 let types = cell.types();38 let filled: Vec<bool> = (0..SIDE * SIDE)39 .map(|flat| types.get(&[flat / SIDE, flat % SIDE]) != 0)40 .collect();41 let centre = ((SIDE - 1) / 2) as i64;42 let home = (0..SIDE * SIDE)43 .filter(|&flat| filled[flat])44 .min_by_key(|&flat| {45 let (r, c) = ((flat / SIDE) as i64 - centre, (flat % SIDE) as i64 - centre);46 r * r + c * c47 })48 .expect("a filled site");49 let mut rng = Rng::new(seed);50 let mut at = vec![home; WALKERS];51 for _ in 0..STEPS {52 for walker in at.iter_mut() {53 let (r, c) = (*walker / SIDE, *walker % SIDE);54 let (nr, nc) = match rng.below(4) {55 0 => (r + 1, c),56 1 => (r.wrapping_sub(1), c),57 2 => (r, c + 1),58 _ => (r, c.wrapping_sub(1)),59 };60 if nr < SIDE && nc < SIDE && filled[nr * SIDE + nc] {61 *walker = nr * SIDE + nc;62 }63 }64 }65 Ok(Swarm { filled, home, at })66}6768fn team(board: &mut Board, frame: Frame, swarm: &Swarm, tint: Color) {69 let grid = Grid::new(frame, SIDE, SIDE, 0.0);70 for flat in 0..SIDE * SIDE {71 if swarm.filled[flat] {72 grid.fill(73 board,74 flat % SIDE,75 flat / SIDE,76 ink::mix(ink::line(), ink::dim(), 0.35),77 );78 }79 }80 let unit = frame.w / SIDE as f64;81 let spot = |flat: usize| {82 (83 frame.x + (flat % SIDE) as f64 * unit + unit / 2.0,84 frame.y + (flat / SIDE) as f64 * unit + unit / 2.0,85 )86 };87 let (hx, hy) = spot(swarm.home);88 board.ring(hx, hy, swarm.spread() * unit, unit * 0.5, tint);89 for &walker in &swarm.at {90 let (x, y) = spot(walker);91 board.disc(x, y, unit * 0.62, tint);92 }93}9495fn main() -> Result<()> {96 let mut board = Board::square();97 let frame = board.frame(0.08);98 let fast = race(127, SEED)?;99 let slow = race(239, SEED + 777)?;100 for swarm in [&fast, &slow] {101 assert_eq!(swarm.filled.len(), 6561);102 assert_eq!(swarm.filled.iter().filter(|on| **on).count(), 2401);103 assert_eq!(swarm.at.len(), WALKERS);104 assert!(swarm.at.iter().all(|&flat| swarm.filled[flat]));105 }106 assert!(fast.spread() > slow.spread());107 let side = frame.w * 0.55;108 team(109 &mut board,110 Frame::new(frame.x, frame.y, side, side),111 &fast,112 ink::blue(),113 );114 team(115 &mut board,116 Frame::new(117 frame.x + frame.w - side,118 frame.y + frame.h - side,119 side,120 side,121 ),122 &slow,123 ink::orange(),124 );125 save("demo-race", &board)?;126 Ok(())127}