Compare commits
No commits in common. "b37fb0bfd9272484c5fa93e2826ee3433eeedda6" and "366c78766d75e535dde6b6d223b549d0469c72cc" have entirely different histories.
b37fb0bfd9
...
366c78766d
9 changed files with 37 additions and 172 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
/target
|
/target
|
||||||
*.rle
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ edition = "2021"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "main"
|
name = "large_grid"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
17
benches/large_grid.rs
Normal file
17
benches/large_grid.rs
Normal file
|
@ -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);
|
|
@ -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);
|
|
|
@ -1,3 +1,2 @@
|
||||||
pub mod region;
|
pub mod region;
|
||||||
pub mod rle;
|
|
||||||
pub mod tile;
|
pub mod tile;
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -1,21 +1,13 @@
|
||||||
use std::env;
|
use gol_bitwise::region::Region;
|
||||||
|
|
||||||
use gol_bitwise::{region::Region, rle};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut region = if let Some(file) = env::args().nth(1) {
|
let mut region = Region::new(1, 1);
|
||||||
Region::from_bools(rle::parse(&file).unwrap())
|
region.randomise();
|
||||||
} else {
|
print!("\x1B[2J"); // clear screen
|
||||||
let mut r = Region::new(1, 1);
|
|
||||||
r.randomise();
|
|
||||||
r
|
|
||||||
};
|
|
||||||
region.auto_grow();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("\x1B[2J"); // clear screen
|
|
||||||
print!("\x1B[u"); // reset cursor
|
print!("\x1B[u"); // reset cursor
|
||||||
region.print_all(false);
|
region.print_all(true);
|
||||||
region.step();
|
region.step();
|
||||||
region.auto_grow();
|
region.auto_grow();
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::tile::{Edges, Row, Tile, WIDTH};
|
use crate::tile::{Edges, Tile, WIDTH};
|
||||||
|
|
||||||
pub struct Region {
|
pub struct Region {
|
||||||
/// rows of tiles
|
/// rows of tiles
|
||||||
|
@ -11,35 +11,6 @@ impl Region {
|
||||||
Self { tiles }
|
Self { tiles }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bools(board: Vec<Vec<bool>>) -> 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) {
|
pub fn randomise(&mut self) {
|
||||||
for row in self.tiles.iter_mut() {
|
for row in self.tiles.iter_mut() {
|
||||||
for tile in row {
|
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 {
|
pub fn height(&self) -> usize {
|
||||||
self.tiles.len()
|
self.tiles.len()
|
||||||
}
|
}
|
||||||
|
@ -80,13 +47,10 @@ impl Region {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tile_rel(&self, x: usize, y: usize, relx: isize, rely: isize) -> &Tile {
|
fn get_tile_relative(&self, x: usize, y: usize, relx: isize, rely: isize) -> Option<&Tile> {
|
||||||
let (Some(x), Some(y)) = (x.checked_add_signed(relx), y.checked_add_signed(rely))
|
|
||||||
else { return &Tile::EMPTY; };
|
|
||||||
self.tiles
|
self.tiles
|
||||||
.get(y)
|
.get(y.checked_add_signed(rely)?)
|
||||||
.and_then(|row| row.get(x))
|
.and_then(|row| row.get(x.checked_add_signed(relx)?))
|
||||||
.unwrap_or(&Tile::EMPTY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self) {
|
pub fn step(&mut self) {
|
||||||
|
@ -95,14 +59,14 @@ impl Region {
|
||||||
for y in 0..self.height() {
|
for y in 0..self.height() {
|
||||||
let mut row = Vec::with_capacity(self.width());
|
let mut row = Vec::with_capacity(self.width());
|
||||||
for x in 0..self.width() {
|
for x in 0..self.width() {
|
||||||
let n = self.get_tile_rel(x, y, 0, -1);
|
let n = self.get_tile_relative(x, y, 0, -1).unwrap_or(&Tile::EMPTY);
|
||||||
let s = self.get_tile_rel(x, y, 0, 1);
|
let s = self.get_tile_relative(x, y, 0, 1).unwrap_or(&Tile::EMPTY);
|
||||||
let e = self.get_tile_rel(x, y, 1, 0);
|
let e = self.get_tile_relative(x, y, 1, 0).unwrap_or(&Tile::EMPTY);
|
||||||
let w = self.get_tile_rel(x, y, -1, 0);
|
let w = self.get_tile_relative(x, y, -1, 0).unwrap_or(&Tile::EMPTY);
|
||||||
let ne = self.get_tile_rel(x, y, 1, -1);
|
let ne = self.get_tile_relative(x, y, 1, -1).unwrap_or(&Tile::EMPTY);
|
||||||
let nw = self.get_tile_rel(x, y, -1, -1);
|
let nw = self.get_tile_relative(x, y, -1, -1).unwrap_or(&Tile::EMPTY);
|
||||||
let se = self.get_tile_rel(x, y, 1, 1);
|
let se = self.get_tile_relative(x, y, 1, 1).unwrap_or(&Tile::EMPTY);
|
||||||
let sw = self.get_tile_rel(x, y, -1, 1);
|
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);
|
let edge = Edges::new(n, s, e, w, ne, nw, se, sw);
|
||||||
row.push(edge);
|
row.push(edge);
|
||||||
|
|
62
src/rle.rs
62
src/rle.rs
|
@ -1,62 +0,0 @@
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// one of the shittest RLE parsers in existence :)
|
|
||||||
|
|
||||||
pub fn parse(filename: &str) -> Option<Vec<Vec<bool>>> {
|
|
||||||
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::<Vec<_>>();
|
|
||||||
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)
|
|
||||||
}
|
|
15
src/tile.rs
15
src/tile.rs
|
@ -1,4 +1,4 @@
|
||||||
pub type Row = u16;
|
type Row = u16;
|
||||||
|
|
||||||
pub const WIDTH: usize = Row::BITS as usize;
|
pub const WIDTH: usize = Row::BITS as usize;
|
||||||
const LAST: usize = WIDTH - 1;
|
const LAST: usize = WIDTH - 1;
|
||||||
|
@ -15,7 +15,7 @@ pub struct Edges {
|
||||||
se: bool,
|
se: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub rows: [Row; WIDTH],
|
pub rows: [Row; WIDTH],
|
||||||
}
|
}
|
||||||
|
@ -27,17 +27,6 @@ impl Tile {
|
||||||
Self::EMPTY
|
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 {
|
pub fn edge_east(&self) -> Row {
|
||||||
let mut edge = 0;
|
let mut edge = 0;
|
||||||
for n in 0..WIDTH {
|
for n in 0..WIDTH {
|
||||||
|
|
Loading…
Reference in a new issue