Skip to main content

I recently picked up Rust, and was making a CLI for Conway's Game of Life. I got it working, but, looking back at it, there are places it could be improved. The main one is the function that generates the next board, and specifically. Specifically, the part of that function which calculates the amount of alive neighbours a cell has.

fn next_step(game_array: [[bool; WIDTH]; HEIGHT]) -> [[bool; WIDTH]; HEIGHT] {
    let mut next_state = [[false; WIDTH]; HEIGHT];
    let mut neighbours: u8; // Will never be above 8
    const HEIGHT_I: isize = HEIGHT as isize;
    const WIDTH_I: isize = WIDTH as isize;
    const NEIGHBOUR_LIST: [[isize; 2]; 8] = [[-1, -1], [-1, 0], [-1, 1],
                                             [ 0, -1],          [ 0, 1],
                                             [ 1, -1], [ 1, 0], [ 1, 1]];
    for rownum in 0..HEIGHT {
        for cellnum in 0..WIDTH {


            // FROM HERE
            neighbours = 0;
            for [j, k] in NEIGHBOUR_LIST {
                // This will break if width and height are set to larger than isize::MAX
                if game_array[(((rownum as isize + j % HEIGHT_I) + HEIGHT_I) % HEIGHT_I) as usize]
                    [(((cellnum as isize + k % WIDTH_I) + WIDTH_I) % WIDTH_I) as usize] {
                        neighbours += 1;
                    }
            }
            // TO HERE


            // This is the cleanest way I could find to implement Life rules
            if neighbours == 3 || (game_array[rownum][cellnum] && neighbours == 2) {
                next_state[rownum][cellnum] = true;
            }
        }
    }
    next_state
}
fn next_step(game_array: [[bool; WIDTH]; HEIGHT]) -> [[bool; WIDTH]; HEIGHT] {
    let mut next_state = [[false; WIDTH]; HEIGHT];
    let mut neighbours: u8; // Will never be above 8
    const HEIGHT_I: isize = HEIGHT as isize;
    const WIDTH_I: isize = WIDTH as isize;
    const NEIGHBOUR_LIST: [[isize; 2]; 8] = [[-1, -1], [-1, 0], [-1, 1],
                                             [ 0, -1],          [ 0, 1],
                                             [ 1, -1], [ 1, 0], [ 1, 1]];
    for rownum in 0..HEIGHT {
        for cellnum in 0..WIDTH {


            // FROM HERE
            neighbours = 0;
            for [j, k] in NEIGHBOUR_LIST {
                // This will break if width and height are set to larger than isize::MAX
                if game_array[(((rownum as isize + j % HEIGHT_I) + HEIGHT_I) % HEIGHT_I) as usize]
                    [(((cellnum as isize + k % WIDTH_I) + WIDTH_I) % WIDTH_I) as usize] {
                        neighbours += 1;
                    }
            }
            // TO HERE


            // This is the cleanest way I could find to implement Life rules
            if neighbours == 3 || (game_array[rownum][cellnum] && neighbours == 2) {
                next_state[rownum][cellnum] = true;
            }
        }
    }
    next_state
}

I wanted the edges of the board to loop, and this is the best way I could find of checkingto check the neighbours of a cell. However, it is verbose and hard to read. Is there anya better way that I am missing?

HEIGHT and WIDTH are the height and width of the board, and will never be above isize::MAX.

I recently picked up Rust, and was making a CLI Conway's Game of Life. I got it working, but looking back at it, there are places it could be improved. The main one is the function that generates the next board, and specifically, the part of that function which calculates the amount of alive neighbours a cell has.

fn next_step(game_array: [[bool; WIDTH]; HEIGHT]) -> [[bool; WIDTH]; HEIGHT] {
    let mut next_state = [[false; WIDTH]; HEIGHT];
    let mut neighbours: u8; // Will never be above 8
    const HEIGHT_I: isize = HEIGHT as isize;
    const WIDTH_I: isize = WIDTH as isize;
    const NEIGHBOUR_LIST: [[isize; 2]; 8] = [[-1, -1], [-1, 0], [-1, 1],
                                             [ 0, -1],          [ 0, 1],
                                             [ 1, -1], [ 1, 0], [ 1, 1]];
    for rownum in 0..HEIGHT {
        for cellnum in 0..WIDTH {


            // FROM HERE
            neighbours = 0;
            for [j, k] in NEIGHBOUR_LIST {
                // This will break if width and height are set to larger than isize::MAX
                if game_array[(((rownum as isize + j % HEIGHT_I) + HEIGHT_I) % HEIGHT_I) as usize]
                    [(((cellnum as isize + k % WIDTH_I) + WIDTH_I) % WIDTH_I) as usize] {
                        neighbours += 1;
                    }
            }
            // TO HERE


            // This is the cleanest way I could find to implement Life rules
            if neighbours == 3 || (game_array[rownum][cellnum] && neighbours == 2) {
                next_state[rownum][cellnum] = true;
            }
        }
    }
    next_state
}

I wanted the edges of the board to loop, and this is the best way I could find of checking the neighbours of a cell. However, it is verbose and hard to read. Is there any better way that I am missing?

HEIGHT and WIDTH are the height and width of the board, and will never be above isize::MAX.

I recently picked up Rust and was making a CLI for Conway's Game of Life. I got it working but, looking back at it, there are places it could be improved. The main one is the function that generates the next board. Specifically, the part of that function which calculates the amount of alive neighbours a cell has.

fn next_step(game_array: [[bool; WIDTH]; HEIGHT]) -> [[bool; WIDTH]; HEIGHT] {
    let mut next_state = [[false; WIDTH]; HEIGHT];
    let mut neighbours: u8; // Will never be above 8
    const HEIGHT_I: isize = HEIGHT as isize;
    const WIDTH_I: isize = WIDTH as isize;
    const NEIGHBOUR_LIST: [[isize; 2]; 8] = [[-1, -1], [-1, 0], [-1, 1],
                                             [ 0, -1],          [ 0, 1],
                                             [ 1, -1], [ 1, 0], [ 1, 1]];
    for rownum in 0..HEIGHT {
        for cellnum in 0..WIDTH {


            // FROM HERE
            neighbours = 0;
            for [j, k] in NEIGHBOUR_LIST {
                // This will break if width and height are set to larger than isize::MAX
                if game_array[(((rownum as isize + j % HEIGHT_I) + HEIGHT_I) % HEIGHT_I) as usize]
                    [(((cellnum as isize + k % WIDTH_I) + WIDTH_I) % WIDTH_I) as usize] {
                        neighbours += 1;
                    }
            }
            // TO HERE


            // This is the cleanest way I could find to implement Life rules
            if neighbours == 3 || (game_array[rownum][cellnum] && neighbours == 2) {
                next_state[rownum][cellnum] = true;
            }
        }
    }
    next_state
}

I wanted the edges of the board to loop and this is the best way I could find to check the neighbours of a cell. However, it is verbose and hard to read. Is there a better way that I am missing?

HEIGHT and WIDTH are the height and width of the board and will never be above isize::MAX.

Tweeted twitter.com/StackCodeReview/status/1555705291920084992
Source Link

Optimise Game of Life in Rust

I recently picked up Rust, and was making a CLI Conway's Game of Life. I got it working, but looking back at it, there are places it could be improved. The main one is the function that generates the next board, and specifically, the part of that function which calculates the amount of alive neighbours a cell has.

fn next_step(game_array: [[bool; WIDTH]; HEIGHT]) -> [[bool; WIDTH]; HEIGHT] {
    let mut next_state = [[false; WIDTH]; HEIGHT];
    let mut neighbours: u8; // Will never be above 8
    const HEIGHT_I: isize = HEIGHT as isize;
    const WIDTH_I: isize = WIDTH as isize;
    const NEIGHBOUR_LIST: [[isize; 2]; 8] = [[-1, -1], [-1, 0], [-1, 1],
                                             [ 0, -1],          [ 0, 1],
                                             [ 1, -1], [ 1, 0], [ 1, 1]];
    for rownum in 0..HEIGHT {
        for cellnum in 0..WIDTH {


            // FROM HERE
            neighbours = 0;
            for [j, k] in NEIGHBOUR_LIST {
                // This will break if width and height are set to larger than isize::MAX
                if game_array[(((rownum as isize + j % HEIGHT_I) + HEIGHT_I) % HEIGHT_I) as usize]
                    [(((cellnum as isize + k % WIDTH_I) + WIDTH_I) % WIDTH_I) as usize] {
                        neighbours += 1;
                    }
            }
            // TO HERE


            // This is the cleanest way I could find to implement Life rules
            if neighbours == 3 || (game_array[rownum][cellnum] && neighbours == 2) {
                next_state[rownum][cellnum] = true;
            }
        }
    }
    next_state
}

I wanted the edges of the board to loop, and this is the best way I could find of checking the neighbours of a cell. However, it is verbose and hard to read. Is there any better way that I am missing?

HEIGHT and WIDTH are the height and width of the board, and will never be above isize::MAX.