diff --git a/.gitignore b/.gitignore index 6631e2e..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ /target -*.rle diff --git a/Cargo.toml b/Cargo.toml index b28847f..f4ed9ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" rand = "0.8.5" [[bench]] -name = "main" +name = "large_grid" harness = false [dev-dependencies] diff --git a/benches/large_grid.rs b/benches/large_grid.rs new file mode 100644 index 0000000..60a771d --- /dev/null +++ b/benches/large_grid.rs @@ -0,0 +1,17 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use gol_bitwise::region::Region; + +fn large_grid(c: &mut Criterion) { + const SIZE: usize = 2048 / gol_bitwise::tile::WIDTH; // same number of cells regardless of tile size + let mut region = black_box(Region::new(SIZE, SIZE)); + region.randomise(); + + c.bench_function("large grid", |b| { + b.iter(|| { + region.step(); + }) + }); +} + +criterion_group!(benches, large_grid); +criterion_main!(benches); diff --git a/benches/main.rs b/benches/main.rs deleted file mode 100644 index 8ae3c42..0000000 --- a/benches/main.rs +++ /dev/null @@ -1,33 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use gol_bitwise::{ - region::Region, - tile::{self, Tile}, -}; - -fn large_grid(c: &mut Criterion) { - const SIZE: usize = 2048 / tile::WIDTH; // same number of cells regardless of tile size - let mut region = black_box(Region::new(SIZE, SIZE)); - region.randomise(); - - c.bench_function("large grid", |b| { - b.iter(|| { - region.step(); - }) - }); -} - -fn growing(c: &mut Criterion) { - c.bench_function("growing", |b| { - b.iter(|| { - let mut region = black_box(Region::new(1, 1)); - region.set_tile(Tile::gliders(), 0, 0); - for _ in 0..1024 { - region.step(); - region.auto_grow(); - } - }) - }); -} - -criterion_group!(benches, large_grid, growing); -criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index 106cec6..dae266f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,2 @@ pub mod region; -pub mod rle; pub mod tile; diff --git a/src/main.rs b/src/main.rs index a71f106..664dad8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,13 @@ -use std::env; - -use gol_bitwise::{region::Region, rle}; +use gol_bitwise::region::Region; fn main() { - let mut region = if let Some(file) = env::args().nth(1) { - Region::from_bools(rle::parse(&file).unwrap()) - } else { - let mut r = Region::new(1, 1); - r.randomise(); - r - }; - region.auto_grow(); + let mut region = Region::new(1, 1); + region.randomise(); + print!("\x1B[2J"); // clear screen loop { - print!("\x1B[2J"); // clear screen print!("\x1B[u"); // reset cursor - region.print_all(false); + region.print_all(true); region.step(); region.auto_grow(); { diff --git a/src/region.rs b/src/region.rs index 48f3d5e..f20ab26 100644 --- a/src/region.rs +++ b/src/region.rs @@ -1,4 +1,4 @@ -use crate::tile::{Edges, Row, Tile, WIDTH}; +use crate::tile::{Edges, Tile, WIDTH}; pub struct Region { /// rows of tiles @@ -11,35 +11,6 @@ impl Region { Self { tiles } } - pub fn from_bools(board: Vec>) -> Self { - let height = board.len() / WIDTH + 1; - let width = board[0].len() / WIDTH + 1; - let mut tiles = vec![vec![Tile::new(); width]; height]; - - for tile_y in 0..height { - for tile_x in 0..width { - let tile = &mut tiles[tile_y][tile_x]; - for y in 0..WIDTH { - let by = tile_y * WIDTH + y; - if by >= board.len() { - break; - } - let mut row = 0; - for x in 0..WIDTH { - let bx = tile_x * WIDTH + x; - if bx >= board[by].len() { - break; - } - row |= (board[by][bx] as Row) << (WIDTH - x - 1) as Row; - } - tile.rows[y] = row; - } - } - } - - Self { tiles } - } - pub fn randomise(&mut self) { for row in self.tiles.iter_mut() { for tile in row { @@ -48,10 +19,6 @@ impl Region { } } - pub fn set_tile(&mut self, tile: Tile, x: usize, y: usize) { - self.tiles[y][x] = tile; - } - pub fn height(&self) -> usize { self.tiles.len() } @@ -80,13 +47,10 @@ impl Region { } } - fn get_tile_rel(&self, x: usize, y: usize, relx: isize, rely: isize) -> &Tile { - let (Some(x), Some(y)) = (x.checked_add_signed(relx), y.checked_add_signed(rely)) - else { return &Tile::EMPTY; }; + fn get_tile_relative(&self, x: usize, y: usize, relx: isize, rely: isize) -> Option<&Tile> { self.tiles - .get(y) - .and_then(|row| row.get(x)) - .unwrap_or(&Tile::EMPTY) + .get(y.checked_add_signed(rely)?) + .and_then(|row| row.get(x.checked_add_signed(relx)?)) } pub fn step(&mut self) { @@ -95,14 +59,14 @@ impl Region { for y in 0..self.height() { let mut row = Vec::with_capacity(self.width()); for x in 0..self.width() { - let n = self.get_tile_rel(x, y, 0, -1); - let s = self.get_tile_rel(x, y, 0, 1); - let e = self.get_tile_rel(x, y, 1, 0); - let w = self.get_tile_rel(x, y, -1, 0); - let ne = self.get_tile_rel(x, y, 1, -1); - let nw = self.get_tile_rel(x, y, -1, -1); - let se = self.get_tile_rel(x, y, 1, 1); - let sw = self.get_tile_rel(x, y, -1, 1); + let n = self.get_tile_relative(x, y, 0, -1).unwrap_or(&Tile::EMPTY); + let s = self.get_tile_relative(x, y, 0, 1).unwrap_or(&Tile::EMPTY); + let e = self.get_tile_relative(x, y, 1, 0).unwrap_or(&Tile::EMPTY); + let w = self.get_tile_relative(x, y, -1, 0).unwrap_or(&Tile::EMPTY); + let ne = self.get_tile_relative(x, y, 1, -1).unwrap_or(&Tile::EMPTY); + let nw = self.get_tile_relative(x, y, -1, -1).unwrap_or(&Tile::EMPTY); + let se = self.get_tile_relative(x, y, 1, 1).unwrap_or(&Tile::EMPTY); + let sw = self.get_tile_relative(x, y, -1, 1).unwrap_or(&Tile::EMPTY); let edge = Edges::new(n, s, e, w, ne, nw, se, sw); row.push(edge); diff --git a/src/rle.rs b/src/rle.rs deleted file mode 100644 index 0f079ef..0000000 --- a/src/rle.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::fs; - -// one of the shittest RLE parsers in existence :) - -pub fn parse(filename: &str) -> Option>> { - let file = fs::read_to_string(filename).ok()?; - let mut meta = None; - let mut rle = String::new(); - for line in file.lines() { - if line.starts_with('#') { - continue; - } - if meta.is_none() { - meta = Some(line.to_owned()); - continue; - } - rle.push_str(line); - } - let meta = meta?; - - let properties = meta.split(", ").collect::>(); - let width: usize = properties.get(0)?.split('=').nth(1)?.trim().parse().ok()?; - let height: usize = properties.get(1)?.split('=').nth(1)?.trim().parse().ok()?; - - let mut board = vec![vec![false; width]; height]; - - let mut x = 0; - let mut y = 0; - let mut run_count = 0; - - for char in rle.chars() { - match char { - 'b' => { - run_count = run_count.max(1); - x += run_count; - run_count = 0; - } - 'o' => { - run_count = run_count.max(1); - for rx in x..(x + run_count) { - board[y][rx] = true; - } - x += run_count; - run_count = 0; - } - '$' => { - run_count = run_count.max(1); - y += run_count; - run_count = 0; - x = 0; - } - '0'..='9' => { - run_count *= 10; - run_count += ((char as u8) - b'0') as usize; - } - '!' => break, - '\n' => (), - other => println!("Unknown token {other} in RLE"), - } - } - Some(board) -} diff --git a/src/tile.rs b/src/tile.rs index 778029f..ed6f5c6 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,4 +1,4 @@ -pub type Row = u16; +type Row = u16; pub const WIDTH: usize = Row::BITS as usize; const LAST: usize = WIDTH - 1; @@ -15,7 +15,7 @@ pub struct Edges { se: bool, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Tile { pub rows: [Row; WIDTH], } @@ -27,17 +27,6 @@ impl Tile { Self::EMPTY } - pub fn gliders() -> Self { - let mut t = Self::EMPTY; - t.rows[1] = 0b1110000; - t.rows[2] = 0b1000000; - t.rows[3] = 0b0100000; - t.rows[WIDTH - 4] = 0b0100; - t.rows[WIDTH - 3] = 0b0010; - t.rows[WIDTH - 2] = 0b1110; - t - } - pub fn edge_east(&self) -> Row { let mut edge = 0; for n in 0..WIDTH {