Skip to content

Instantly share code, notes, and snippets.

@bn3t
Created August 15, 2018 12:17
Show Gist options
  • Save bn3t/fbb68a7046eae63c501a86a83c0e8036 to your computer and use it in GitHub Desktop.
Save bn3t/fbb68a7046eae63c501a86a83c0e8036 to your computer and use it in GitHub Desktop.
wasm_game_of_life optimisation
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use std::mem;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
#[wasm_bindgen(js_namespace = console)]
fn time(name: &str);
#[wasm_bindgen(js_namespace = console)]
fn timeEnd(name: &str);
}
pub struct Timer<'a> {
name: &'a str,
}
impl<'a> Timer<'a> {
pub fn new(name: &'a str) -> Timer<'a> {
time(name);
Timer { name }
}
}
impl<'a> Drop for Timer<'a> {
fn drop(&mut self) {
timeEnd(self.name);
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
Dead = 0,
Alive = 1,
}
impl Cell {
fn toggle(&mut self) {
*self = match *self {
Cell::Dead => Cell::Alive,
Cell::Alive => Cell::Dead,
};
}
}
#[wasm_bindgen]
pub struct Universe {
width: u32,
height: u32,
cells: (Vec<Cell>, Vec<Cell>),
}
/// Public methods, exported to JavaScript.
#[wasm_bindgen]
impl Universe {
pub fn new() -> Universe {
let width = 128;
let height = 128;
let cells0 = (0..width * height)
.map(|i| {
if i % 2 == 0 || i % 7 == 0 {
Cell::Alive
} else {
Cell::Dead
}
})
.collect();
let cells1 = (0..width * height)
.map(|_| {
Cell::Dead
})
.collect();
Universe {
width,
height,
cells: (cells0, cells1),
}
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn cells(&self) -> *const Cell {
self.cells.0.as_ptr()
}
pub fn tick(&mut self) {
// let _timer = Timer::new("Universe::tick");
// swap the cell buffer
{
// let next = &mut self.cells.1;
// let current = &self.cells.0;
// let _timer = Timer::new("new generation");
for row in 0..self.height {
for col in 0..self.width {
let idx = self.get_index(row, col);
let cell = self.cells.0[idx];
let live_neighbors = self.live_neighbor_count(row, col);
let next_cell = match (cell, live_neighbors) {
// Rule 1: Any live cell with fewer than two live neighbours
// dies, as if caused by underpopulation.
(Cell::Alive, x) if x < 2 => Cell::Dead,
// Rule 2: Any live cell with two or three live neighbours
// lives on to the next generation.
(Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
// Rule 3: Any live cell with more than three live
// neighbours dies, as if by overpopulation.
(Cell::Alive, x) if x > 3 => Cell::Dead,
// Rule 4: Any dead cell with exactly three live neighbours
// becomes a live cell, as if by reproduction.
(Cell::Dead, 3) => Cell::Alive,
// All other cells remain in the same state.
(otherwise, _) => otherwise,
};
self.cells.1[idx] = next_cell;
}
}
}
mem::swap(&mut self.cells.0, &mut self.cells.1);
// let cells0 = &self.cells.0;
// let cells1 = &self.cells.1;
// self.cells = (*cells1, *cells0);
// let _timer = Timer::new("free old cells");
//self.cells = next;
}
pub fn toggle_cell(&mut self, row: u32, column: u32) {
let idx = self.get_index(row, column);
self.cells.0[idx].toggle();
}
}
/// Private methods.
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;
let north = if row == 0 {
self.height - 1
} else {
row - 1
};
let south = if row == self.height - 1 {
0
} else {
row + 1
};
let west = if column == 0 {
self.width - 1
} else {
column - 1
};
let east = if column == self.width - 1 {
0
} else {
column + 1
};
let nw = self.get_index(north, west);
count += self.cells.0[nw] as u8;
let n = self.get_index(north, column);
count += self.cells.0[n] as u8;
let ne = self.get_index(north, east);
count += self.cells.0[ne] as u8;
let w = self.get_index(row, west);
count += self.cells.0[w] as u8;
let e = self.get_index(row, east);
count += self.cells.0[e] as u8;
let sw = self.get_index(south, west);
count += self.cells.0[sw] as u8;
let s = self.get_index(south, column);
count += self.cells.0[s] as u8;
let se = self.get_index(south, east);
count += self.cells.0[se] as u8;
count
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment