mod utils; extern crate js_sys; extern crate fixedbitset; use std::fmt; use wasm_bindgen::prelude::*; use fixedbitset::FixedBitSet; // 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; #[wasm_bindgen] extern { fn alert(s: &str); } #[wasm_bindgen] pub fn greet(name: &str) { alert(&format!("Hello, {name}!", name=name)) } #[wasm_bindgen] pub struct Universe { width: u32, height: u32, cells: FixedBitSet, } 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_col in [self.width -1, 0, 1].iter().cloned() { if delta_row == 0 && delta_col == 0 { continue; } let neighbor_row = (row + delta_row) % self.height; let neighbor_col = (column + delta_col) % self.width; let i = self.get_index(neighbor_row, neighbor_col); count += self.cells[i] as u8; } } count } fn regenerate_cells(&mut self) { let size = (self.width * self.height) as usize; self.cells = FixedBitSet::with_capacity(size); for i in 0..size { self.cells.set(i, false); } } pub fn get_cells(&self) -> &FixedBitSet { &self.cells } pub fn set_cells(&mut self, cells: &[(u32, u32)]) { for (row, col) in cells.iter().cloned() { let i = self.get_index(row, col); self.cells.set(i, true); } } } #[wasm_bindgen] impl Universe { pub fn tick(&mut self) { let mut next = self.cells.clone(); for row in 0..self.height{ for col in 0..self.width{ let i = self.get_index(row, col); let cell = self.cells[i]; let live_neighbor = self.live_neighbor_count(row, col); next.set(i, match (cell, live_neighbor){ (true, x) if x < 2 => false, (true, 2) | (true, 3) => true, (true, x) if x > 3 => false, (false, 3) => true, (other, _) => other, }); } } self.cells = next; } pub fn set_width(&mut self, width: u32) { self.width = width; self.regenerate_cells(); } pub fn set_height(&mut self, height: u32) { self.height = height; self.regenerate_cells(); } pub fn new() -> Universe { let width = 64; let height = 64; let size = (width * height) as usize; let mut cells = FixedBitSet::with_capacity(size); for i in 0..size { cells.set(i, false); } Universe { width, height, cells, } } pub fn new_modulo() -> Universe { let width = 64; let height = 64; let size = (width * height) as usize; let mut cells = FixedBitSet::with_capacity(size); for i in 0..size { cells.set(i, i % 2 == 0 || i % 7 == 0); } Universe { width, height, cells, } } pub fn new_random() -> Universe { let width = 64; let height = 64; let size = (width * height) as usize; let mut cells = FixedBitSet::with_capacity(size); for i in 0..size { cells.set(i, js_sys::Math::random() < 0.5); } Universe { width, height, cells, } } pub fn new_space_ship() -> Universe { let mut univese = Universe::new(); const X0: u32 = 32; const Y0: u32 = 32; let cells = &( [(0, 2), (1, 0), (1, 2), (2, 1), (2, 2)] .iter() .map(|(x, y)| (X0+x, Y0+y)) .collect::>() ); univese.set_cells(cells); univese } pub fn render(&self) -> String { self.to_string() } pub fn width(&self) -> u32 { self.width } pub fn height(&self) -> u32 { self.height } pub fn cells(&self) -> *const u32 { self.cells.as_slice().as_ptr() } } impl fmt::Display for Universe { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for row in 0..self.height { for col in 0..self.width { let i = self.get_index(row, col); let symbole = if self.cells[i] { '◻' } else { '◼' }; write!(f, "{}", symbole)?; } write!(f, "\n")?; } Ok(()) } }