commit 47ff50be5f9ed0cf3f5f31992f97f14d9aa81624 Author: CrispyPin Date: Thu Jul 20 14:36:42 2023 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ee38ade --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "gol-bitwise" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a2340f6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "gol-bitwise" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ad0d71d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,125 @@ +mod tile; +use tile::*; + +fn main() { + let mut tile = EMPTY_TILE; + let mut tile2 = EMPTY_TILE; + let mut tile3 = EMPTY_TILE; + let mut tile4 = EMPTY_TILE; + // tile[WIDTH - 8] = (0b_1111_1111_1100_0000 as Row).reverse_bits(); + tile[WIDTH - 8] = 0b_00100000; + tile[WIDTH - 7] = 0b_00010000; + tile[WIDTH - 6] = 0b_01110000; + + tile[WIDTH - 3] = 0b_0010; + tile[WIDTH - 2] = 0b_0001; + tile[WIDTH - 1] = 0b_0111; + loop { + let edges = Edges::full( + &EMPTY_TILE, + &tile3, + &tile2, + &EMPTY_TILE, + &EMPTY_TILE, + &EMPTY_TILE, + &tile4, + &EMPTY_TILE, + ); + let edges2 = Edges::full( + &EMPTY_TILE, + &tile4, + &EMPTY_TILE, + &tile, + &EMPTY_TILE, + &EMPTY_TILE, + &EMPTY_TILE, + &tile3, + ); + let edges3 = Edges::full( + &tile, + &EMPTY_TILE, + &tile4, + &EMPTY_TILE, + &tile2, + &EMPTY_TILE, + &EMPTY_TILE, + &EMPTY_TILE, + ); + let edges4 = Edges::full( + &tile2, + &EMPTY_TILE, + &EMPTY_TILE, + &tile3, + &EMPTY_TILE, + &tile, + &EMPTY_TILE, + &EMPTY_TILE, + ); + println!(); + println!("\n{:#> bit) & 1, (bot >> bit) & 1); +// row.push(match states { +// (0, 0) => ' ', +// (1, 0) => '▀', +// (0, 1) => '▄', +// (1, 1) => '█', +// _ => unreachable!(), +// }); +// } +// println!("{row}"); +// } +// } + +fn blocks(top: Row, bottom: Row, bit: usize) -> char { + let states = ((top >> bit) & 1, (bottom >> bit) & 1); + match states { + (0, 0) => ' ', + (1, 0) => '▀', + (0, 1) => '▄', + (1, 1) => '█', + _ => unreachable!(), + } +} + +fn print_tiles(left: &TileArr, right: &TileArr) { + for y in 0..(WIDTH / 2) { + let a = left[y * 2]; + let b = left[y * 2 + 1]; + let mut row = String::with_capacity(WIDTH * 2 + 1); + for bit in (0..WIDTH).rev() { + row.push(blocks(a, b, bit)); + } + row.push('|'); + let a = right[y * 2]; + let b = right[y * 2 + 1]; + for bit in (0..WIDTH).rev() { + row.push(blocks(a, b, bit)); + } + println!("{row}"); + } +} diff --git a/src/tile.rs b/src/tile.rs new file mode 100644 index 0000000..1232ff5 --- /dev/null +++ b/src/tile.rs @@ -0,0 +1,162 @@ +pub type Row = u32; +pub type TileArr = [Row; WIDTH]; +pub const EMPTY_TILE: TileArr = [0; WIDTH]; + +pub const WIDTH: usize = Row::BITS as usize; +const LAST: usize = WIDTH - 1; + +pub struct Edges { + n: Row, + s: Row, + e: Row, + w: Row, + nw: bool, + ne: bool, + sw: bool, + se: bool, +} + +pub fn step(tile: &mut TileArr, edges: &Edges) { + fn step_row(state: &mut Row, a0: Row, a1: Row, b0: Row, b1: Row, c0: Row, c1: Row) { + // simulates addition of [WIDTH] groups of 3 2-bit numbers using bitwise operations + + // partial sum (first and second number/row) + let t0 = a0 ^ b0; + let t1 = (a0 & b0) ^ (a1 ^ b1); + let t2 = (a0 & b0 & (a1 ^ b1)) | (a1 & b1); + + // total neighbor count (incl. center cell) + let n0 = t0 ^ c0; + let n1 = (t0 & c0) ^ (t1 ^ c1); + let n2 = t2 ^ ((t0 & c0 & (t1 ^ c1)) | (t1 & c1)); + + // count == 3 || (old_state && count == 4) + *state = (!n2 & n1 & n0) | (*state & n2 & !(n0 | n1)); + } + + let mut partial_sums_1 = EMPTY_TILE; + let mut partial_sums_2 = EMPTY_TILE; + + for (y, row) in tile.iter().enumerate() { + let left = (row >> 1) | edges.west_bit(y); + let right = (row << 1) | edges.east_bit(y); + partial_sums_1[y] = row ^ left ^ right; + partial_sums_2[y] = (left & right) | ((left ^ right) & row); + } + + for y in 1..LAST { + step_row( + &mut tile[y], + partial_sums_1[y - 1], + partial_sums_2[y - 1], + partial_sums_1[y], + partial_sums_2[y], + partial_sums_1[y + 1], + partial_sums_2[y + 1], + ); + } + + // top and bottom cases + let (partial_north_1, partial_north_2) = { + let row = edges.n; + let left = (row >> 1) | edges.nw_bit(); + let right = (row << 1) | edges.ne_bit(); + (row ^ left ^ right, (left & right) | ((left ^ right) & row)) + }; + step_row( + &mut tile[0], + partial_north_1, + partial_north_2, + partial_sums_1[0], + partial_sums_2[0], + partial_sums_1[1], + partial_sums_2[1], + ); + let (partial_south_1, partial_south_2) = { + let row = edges.s; + let left = (row >> 1) | edges.sw_bit(); + let right = (row << 1) | edges.se_bit(); + (row ^ left ^ right, (left & right) | ((left ^ right) & row)) + }; + step_row( + &mut tile[LAST], + partial_sums_1[WIDTH - 2], + partial_sums_2[WIDTH - 2], + partial_sums_1[LAST], + partial_sums_2[LAST], + partial_south_1, + partial_south_2, + ); +} + +impl Edges { + // pub const EMPTY: Self = Edges { + // n: 0, + // s: 0, + // e: 0, + // w: 0, + // ne: false, + // nw: false, + // se: false, + // sw: false, + // }; + + pub fn full( + n: &TileArr, + s: &TileArr, + e: &TileArr, + w: &TileArr, + ne: &TileArr, + nw: &TileArr, + se: &TileArr, + sw: &TileArr, + ) -> Self { + let mut east = 0; + let mut west = 0; + for n in 0..WIDTH { + east |= (e[n] >> LAST) << n; + west |= (w[n] & 1) << n; + } + Self { + n: n[LAST], + s: s[0], + e: east, + w: west, + nw: (nw[LAST] & 1) != 0, + ne: (ne[LAST] >> LAST) != 0, + sw: (sw[0] & 1) != 0, + se: (se[0] >> LAST) != 0, + } + } + + fn west_bit(&self, y: usize) -> Row { + ((self.w >> y) & 1) << LAST + } + + fn east_bit(&self, y: usize) -> Row { + (self.e >> y) & 1 + } + + fn nw_bit(&self) -> Row { + if self.nw { + 1 << LAST + } else { + 0 + } + } + + fn sw_bit(&self) -> Row { + if self.sw { + 1 << LAST + } else { + 0 + } + } + + fn ne_bit(&self) -> Row { + self.ne as Row + } + fn se_bit(&self) -> Row { + self.se as Row + } +}