use wasm_bindgen::prelude::*;
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
pub struct Lattice {
width: u32,
height: u32,
cells: Vec<u8>,
modulus: u8,
}
#[wasm_bindgen]
impl Lattice {
#[wasm_bindgen(constructor)]
pub fn new(width: u32, height: u32, modulus: u8) -> Lattice {
let cells = vec![0; (width * height) as usize];
Lattice {
width,
height,
cells,
modulus,
}
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn modulus(&self) -> u8 {
self.modulus
}
pub fn cells_ptr(&self) -> *const u8 {
self.cells.as_ptr()
}
pub fn get(&self, row: u32, col: u32) -> u8 {
self.cells[(row * self.width + col) as usize]
}
pub fn set(&mut self, row: u32, col: u32, value: u8) {
self.cells[(row * self.width + col) as usize] = value % self.modulus;
}
pub fn evolve(&mut self) {
let width = self.width;
let modulus = self.modulus as u16;
for r in (0..width).step_by(2) {
for c in (0..width).step_by(2) {
self.apply_block(r, c, modulus);
}
}
for r in (1..width).step_by(2) {
for c in (1..width).step_by(2) {
self.apply_block(r, c, modulus);
}
}
}
#[inline(always)]
fn apply_block(&mut self, r: u32, c: u32, modulus: u16) {
let w = self.width;
let r1 = (r + 1) % w;
let c1 = (c + 1) % w;
let i_a = (r * w + c) as usize;
let i_b = (r * w + c1) as usize;
let i_c = (r1 * w + c) as usize;
let i_d = (r1 * w + c1) as usize;
let a = self.cells[i_a] as u16;
let b = self.cells[i_b] as u16;
let cc = self.cells[i_c] as u16; let d = self.cells[i_d] as u16;
self.cells[i_a] = ((2 * a + b) % modulus) as u8;
self.cells[i_b] = ((a + b) % modulus) as u8;
self.cells[i_c] = ((2 * cc + d) % modulus) as u8;
self.cells[i_d] = ((cc + d) % modulus) as u8;
}
}