Monday, April 1, 2019

Rust language - WASM - WebGL - Game Of Life demo

Today I would shortly describe my first journey to Rust language. I combined multiple examples from Rust WASM documentation, WebGL. Whole code is here it was fun.

The implementation of Game Of Life is in functional style. The previous generation is list of cell coordinates. I learned about Rust itertools


const OFFSETS_AROUND: [[i32; 2]; 9] = [
  [-1, -1],[0, -1],[1, -1],
  [-1,  0],[0,  0],[1,  0],
  [-1,  1],[0,  1],[1,  1],
];

pub fn cells_around(current: &Cell) -> BoolCells {
    OFFSETS_AROUND.iter()
        .map(|o| {
            (
                o[0] == 0 && o[1] == 0,
                Cell {
                    x: (current.x + o[0]),
                    y: (current.y + o[1]),
                },
            )
        })
        .collect::<BoolCells>()
}

fn should_live<I>(group: I) -> bool where I: IntoIterator<Item = BoolCell> {
    let (was_alive, count) = group.into_iter()
            .fold((false, 0), |acc, candidate| match candidate.0 {
                true => (true, acc.1),
                false => (acc.0, acc.1 + 1),
            });
    count == 3 || (count == 2 && was_alive)
}

pub fn next_gen(generation: &Cells) -> Cells {
    let candidates_with_duplicates = generation.iter()
        .map(cells_around)
        .flatten();
    
    let grouped_by_location = candidates_with_duplicates
        .sorted_by(|candidate_a, candidate_b| candidate_a.1.cmp(&candidate_b.1))
        .group_by(|candidate| candidate.1.clone());
    
    grouped_by_location.into_iter()
        .map(|(key, group)| {
            let alive = should_live(group.into_iter());
            let cell =key.clone();
            (alive, cell)
        })
        .filter(|c| c.0)
        .map(|c| c.1)
        .collect::<Cells>()
}

I stolen most of my WebGl code from this demo. I learned how to move code to modules and how to work with namespaces. For each live cell I tell WebGL to render 2 triangles. There is Z axis of the vertice, which I do not use, but have to pass it. So in total I'm passing single array of float[18*live-cells] to WebGL for rendering in single call. I guess it's much faster than using canvas API with call per cell.

All is integrated into WASM library all the plumbing is again stolen from wasm-bindgen documentation.

Here is the demo. If it doesn't render for you, check your adblock settings, maybe it's blocking all .wasm files to prevent crypto-currerncy mining.