1use wasm_bindgen::prelude::*;
2
3#[cfg(feature = "wee_alloc")]
6#[global_allocator]
7static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
8
9#[wasm_bindgen]
10pub struct Lattice {
11 width: u32,
12 height: u32,
13 cells: Vec<u8>,
14 modulus: u8,
15}
16
17#[wasm_bindgen]
18impl Lattice {
19 #[wasm_bindgen(constructor)]
20 pub fn new(width: u32, height: u32, modulus: u8) -> Lattice {
21 let cells = vec![0; (width * height) as usize];
23 Lattice {
24 width,
25 height,
26 cells,
27 modulus,
28 }
29 }
30
31 pub fn width(&self) -> u32 {
32 self.width
33 }
34
35 pub fn height(&self) -> u32 {
36 self.height
37 }
38
39 pub fn modulus(&self) -> u8 {
40 self.modulus
41 }
42
43 pub fn cells_ptr(&self) -> *const u8 {
45 self.cells.as_ptr()
46 }
47
48 pub fn get(&self, row: u32, col: u32) -> u8 {
49 self.cells[(row * self.width + col) as usize]
50 }
51
52 pub fn set(&mut self, row: u32, col: u32, value: u8) {
53 self.cells[(row * self.width + col) as usize] = value % self.modulus;
54 }
55
56 pub fn evolve(&mut self) {
61 let width = self.width;
62 let modulus = self.modulus as u16; for r in (0..width).step_by(2) {
66 for c in (0..width).step_by(2) {
67 self.apply_block(r, c, modulus);
68 }
69 }
70
71 for r in (1..width).step_by(2) {
73 for c in (1..width).step_by(2) {
74 self.apply_block(r, c, modulus);
75 }
76 }
77 }
78
79 #[inline(always)]
80 fn apply_block(&mut self, r: u32, c: u32, modulus: u16) {
81 let w = self.width;
82
83 let r1 = (r + 1) % w;
85 let c1 = (c + 1) % w;
86
87 let i_a = (r * w + c) as usize;
89 let i_b = (r * w + c1) as usize;
90 let i_c = (r1 * w + c) as usize;
91 let i_d = (r1 * w + c1) as usize;
92
93 let a = self.cells[i_a] as u16;
95 let b = self.cells[i_b] as u16;
96 let cc = self.cells[i_c] as u16; let d = self.cells[i_d] as u16;
98
99 self.cells[i_a] = ((2 * a + b) % modulus) as u8;
104 self.cells[i_b] = ((a + b) % modulus) as u8;
105 self.cells[i_c] = ((2 * cc + d) % modulus) as u8;
106 self.cells[i_d] = ((cc + d) % modulus) as u8;
107 }
108}