simple conway thing
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ae6773e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,133 @@ +use std::{ + io::{self, Write}, + time::Duration, +}; + +const WIDTH: usize = 50; +const HEIGHT: usize = 20; +pub struct Grid([[bool; HEIGHT + 2]; WIDTH + 2]); + +impl Default for Grid { + fn default() -> Self { + Self([[false; HEIGHT + 2]; WIDTH + 2]) + } +} + +impl Grid { + #[inline] + fn neighbors(&self, x: usize, y: usize) -> u8 { + let x = x + 1; + let y = y + 1; + macro_rules! n { + ($(($sx: tt $x: expr, $sy: tt $y: expr))+) => {{ + let mut n = 0; + $(if self.0[n!(@ $sx $x + x)][n!(@ $sy $y + y)] { + n += 1; + })+ + n + }}; + (@ -$n:literal + $v: ident) => { $v - $n }; + (@ +$n:literal + $v: ident) => { $v + $n }; + } + n![(-1, -1)(+0, -1)(+1, -1)(-1, +0)(+1, +0)(-1, +1)(+0, +1)(+1, +1)] + } + + #[inline] + fn kill(&mut self, x: usize, y: usize) { + self.set(x, y, false); + } + + #[inline] + fn spawn(&mut self, x: usize, y: usize) { + self.set(x, y, true); + } + + #[inline] + fn set(&mut self, x: usize, y: usize, to: bool) { + self.0[x + 1][y + 1] = to + } + + #[inline] + fn cell(&self, x: usize, y: usize) -> bool { + self.0[x + 1][y + 1] + } + + fn iterate(&mut self) { + let mut neighbors = [[0u8; HEIGHT + 2]; WIDTH + 2]; + + for x in 0..WIDTH { + for y in 0..HEIGHT { + neighbors[x + 1][y + 1] = self.neighbors(x, y); + } + } + + for x in 0..WIDTH { + for y in 0..HEIGHT { + let cell = self.cell(x, y); + let n = neighbors[x + 1][y + 1]; + match n { + 2 | 3 if cell => continue, + 3 if !cell => self.spawn(x, y), + _ => self.kill(x, y), + } + } + } + } + + fn dead(&mut self) -> bool { + for row in self.0 { + for col in row { + if col { + return false; + }; + } + } + true + } + + fn print(&self, mut w: impl Write) -> io::Result<()> { + let tab = ["░░", "██"]; + for y in 0..HEIGHT { + for x in 0..WIDTH { + w.write_all(tab[self.cell(x, y) as usize].as_bytes())?; + } + writeln!(w)?; + } + Ok(()) + } +} + +fn main() { + let mut grid = Grid::default(); + let img = image::open("src/seed.png").unwrap().to_luma8(); + assert!(img.width() == WIDTH as u32); + assert!(img.height() == HEIGHT as u32); + for x in 0..WIDTH { + for y in 0..HEIGHT { + let on = img.get_pixel(x as u32, y as u32)[0] <= 128; + grid.set(x, y, on); + } + } + + while !grid.dead() { + print!("[H[2J[3J"); + grid.print(std::io::stdout().lock()).unwrap(); + grid.iterate(); + std::thread::sleep(Duration::from_millis(100)); + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn neb() { + let mut g = Grid::default(); + assert_eq!(g.neighbors(0, 0), 0); + assert_eq!(g.neighbors(5, 5), 0); + g.spawn(5, 5); + assert_eq!(g.neighbors(4, 4), 1); + g.spawn(4, 5); + assert_eq!(g.neighbors(4, 4), 2); + } +} |