You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
4.9 KiB
Rust

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::<Vec<(u32, u32)>>()
);
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(())
}
}