simple conway thing
init
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.toml | 17 | ||||
| -rw-r--r-- | LICENSE | 21 | ||||
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | src/main.rs | 133 | ||||
| -rw-r--r-- | src/seed.png | bin | 0 -> 124 bytes |
6 files changed, 183 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..166bd4f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cgol" +version = "0.1.0" +edition = "2021" +author = ["bendn <[email protected]>"] +description = "simple finite cgol, takes seed from a image, outputs to the terminal" +repository = "https://github.com/bend-n/cgol.git" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +image = { version = "0.24.7", features = ["png"], default-features = false } + +[profile.release] +debug = true +lto = "thin" @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 bendn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2131b34 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# conways game of life implementation + +- finite board +- terminal output +- image input +- simple impl + +## demonstration + +https://github.com/bend-n/cgol/assets/70787919/d8848785-d4dc-4bca-ad82-c451a62e7520
\ No newline at end of file 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); + } +} diff --git a/src/seed.png b/src/seed.png Binary files differnew file mode 100644 index 0000000..3825726 --- /dev/null +++ b/src/seed.png |