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
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(())
|
|
}
|
|
}
|