summaryrefslogtreecommitdiff
path: root/wasm-game-of-life/src
diff options
context:
space:
mode:
Diffstat (limited to 'wasm-game-of-life/src')
-rw-r--r--wasm-game-of-life/src/lib.rs132
-rw-r--r--wasm-game-of-life/src/utils.rs10
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();
+}