diff options
Diffstat (limited to 'wasm-game-of-life/src')
-rw-r--r-- | wasm-game-of-life/src/lib.rs | 132 | ||||
-rw-r--r-- | wasm-game-of-life/src/utils.rs | 10 |
2 files changed, 142 insertions, 0 deletions
diff --git a/wasm-game-of-life/src/lib.rs b/wasm-game-of-life/src/lib.rs new file mode 100644 index 0000000..fe82d2c --- /dev/null +++ b/wasm-game-of-life/src/lib.rs @@ -0,0 +1,132 @@ +mod utils; + +use wasm_bindgen::prelude::*; +use wasm_bindgen::__rt::core::fmt::Alignment::Center; +use wasm_bindgen::__rt::core::fmt::Formatter; + +// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global +// allocator. +#[cfg(feature = "wee_alloc")] +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +fn main() { + #[wasm_bindgen] + #[repr(u8)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum Cell { + Dead = 0, + Alive = 1, + } + + #[wasm_bindgen] + pub struct Universe { + width: u32, + height: u32, + cells: Vec<Cell>, + } + + #[wasm_bindgen] + impl Universe { + fn get_index(&self, row: u32, column: u32) -> usize { + (row * self.width + column) as usize + } + + fn live_neighbor_count(&self, row: u32, column: u32) -> u8 { + let mut count = 0; + for delta_row in [self.height - 1, 0, 1].iter().cloned() { + for delta_column in [self.width - 1, 0, 1].iter().cloned() { + if delta_row == 0 && delta_column == 0 { + continue; + } + + let neighbor_row = (row + delta_row) % self.height; + let neighbor_column = (column + delta_column) % self.width; + let idx = self.get_index(neighbor_row, neighbor_column); + count += self.cells[idx] as u8; + } + } + count + } + pub fn new() -> Universe { + let width = 64; + let height = 64; + + let cells = (0..width * height) + .map(|x| { + if x % 2 == 0 || x % 7 == 0 { + Cell::Alive + } else { + Cell::Dead + } + }) + .collect(); + + Universe { + width, + height, + cells, + } + } + + pub fn render(&self) -> String { + self.to_string() + } + + pub fn tick(&mut self) { + let mut next = self.cells.clone(); + + for row in 0..self.height { + for col in 0..self.width { + let idx = self.get_index(row, col); + let cell = self.cells[idx]; + let live_neighbors = self.live_neighbor_count(row, col); + + let next_cell = match (cell, live_neighbors) { + // 1. Underpopulation + (Cell::Alive, x) if x < 2 => Cell::Dead, + // 2. OK + (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive, + // 3. Overpopulation + (Cell::Alive, x) if x > 3 => Cell::Dead, + // 4. Reproduction + (Cell::Dead, 3) => Cell::Alive, + (otherwise, _) => otherwise, + }; + + next[idx] = next_cell; + } + } + + self.cells = next; + } + + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } + + pub fn cells(&self) -> *const Cell { + self.cells.as_ptr() + } + } + + use std::fmt; + + impl fmt::Display for Universe { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for line in self.cells.as_slice().chunks(self.width as usize) { + for &cell in line { + let symbol = if cell == Cell::Dead { '◻' } else { '◼' }; + write!(f, "{}", symbol)?; + } + write!(f, "\n")?; + } + + Ok(()) + } + } +} diff --git a/wasm-game-of-life/src/utils.rs b/wasm-game-of-life/src/utils.rs new file mode 100644 index 0000000..b1d7929 --- /dev/null +++ b/wasm-game-of-life/src/utils.rs @@ -0,0 +1,10 @@ +pub fn set_panic_hook() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); +} |