arraysrustconways-game-of-liferust-wasm

Conways game of Life with 1D array


Right now I'm doing this tutorial for WebAssembly with Rust. The task is to implement Conways Game of Life in Rust. Writing a low-level language like Rust is new for me, but with my prior experience in coding I understand most of the syntax.

The problem I'm having is about the logic of this function:

    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 idx = self.get_index(neighbor_row, neighbor_col);
                count += self.cells[idx] as u8;
            }
        }
        count
    }

In this implementation of Conways Game of Life the grid of cells is represented as an one-dimensional array. The task of this function is now to take coordinates (row and column) and iterate around the neighbours of this coordinates. Because the array is only one-dimensional, the tasks requires delta_row and delta_col which iterate over a array to calculate the neighbors.

My problem is now to understand why these arrays [self.height - 1, 0, 1] and [self.height - 1, 0, 1] are choosen to be iterated over.

I already tried to print out the iterated values and draw the grid on a pieces of paper to visualize the process. Right now I also try to implement a self-written function to understand the choices of the above function better.

Maybe you have already solved this or a similar problem and can give me a hints what's going on.

Thank you for reading and have a nice weekend!


Solution

  • It ends up looking a bit odd because of the constraint of unsigned integers (u32). What we want to write is

    for delta_row in [-1, 0, 1]
    

    which gives every row within 1 of our original, but we can't use -1 because it has a sign. Notice later that we

    let neighbor_row = (row + delta_row) % self.height;
    

    so really we're effectively working in the integers modulo self.height. In this case, -1 = self.height - 1, so we are free to substitute the latter (which is legal for a u32).

    An easy way to see this is to substitute it in later. On the iteration when delta_row = self.height - 1, we are doing

    let neighbor_row = (row + self.height - 1) % self.height;
                     = (row - 1) % self.height - self.height % self.height;
                     = (row - 1) % self.height;
    

    which is the row before row (with wrapping at the edge).