My Rust Implementation of Conway’s Game of Life

My Rust Implementation of Conway’s Game of Life

(This post was generated by an LLM with direction from a human.)


This project has been updated!


Today, I’m excited to share a simple Rust implementation of Conway’s Game of Life, which I’ve been working on. You can check out the full code on my GitHub repository.

Prerequisites

Before diving in, ensure Rust is installed on your system. If not, head over to rust-lang.org and follow the installation instructions.

Cloning the Repository

Start by cloning the repository to your local machine:

git clone https://github.com/drewwalton19216801/gameoflife
cd gameoflife

Running the Game

Execute the game with:

cargo run

Project Structure

Cargo.toml

The Cargo.toml file specifies the dependencies for the project:

[dependencies]
rand = "0.8.5"
termsize = "0.1.8"

Source Code

The main logic is contained within the src directory. Let’s break down some key parts of the implementation.

main.rs

This file is the entry point of the program. It initializes the game grid and controls the game loop.

Grid Initialization

A random grid is generated using the rand crate:

// Create a random number generator.
let mut rng = rand::thread_rng();

// Create a 2D vector with the correct dimensions
// and initialize all cells to `false`.
let mut grid = vec![vec![false; size.cols as usize]; size.rows as usize];

// Set randomly generated live cells in the grid.
for i in 0..size.cols as usize {
    for j in 0..size.rows as usize {
        grid[j][i] = rng.gen_bool(0.5);
    }
}

Game Loop

The game loop is responsible for updating the grid based on Conway’s rules:

loop {
    // Clear the screen before displaying the next frame.
    print!("\x1B[2J\x1B[1;1H");

    // Display the current state of the grid to the console.
    display_grid(&grid);

    // Update the grid by applying the Game of Life rules.
    grid = update_grid(&mut grid, &console_size);

    // Sleep for a short duration to control the speed of the simulation.
    thread::sleep(Duration::from_millis(100));
}

Grid Update Logic

The update_grid function calculates the next state for each cell:

for i in 0..size.rows {
    for j in 0..size.cols {
        // Calculate the number of live neighbors of the cell.
        let live_neighbors = live_neighbors(grid, j, i);

        // Apply the Game of Life rules to determine the next state of the cell.
        if grid[i][j] {
            // If the cell is alive:
            // - If it has 2 or 3 live neighbors, it remains alive.
            // - Otherwise, it dies.
            new_grid[i][j] = live_neighbors == 2 || live_neighbors == 3;
        } else {
            // If the cell is dead:
            // - If it has exactly 3 live neighbors, it becomes alive.
            // - Otherwise, it remains dead.
            new_grid[i][j] = live_neighbors == 3;
        }
    }
}

Counting Live Neighbors

The live_neighbors function is crucial for implementing the rules of the Game of Life. It counts the number of live neighbors around a given cell:

for i in -1..=1 {
    for j in -1..=1 {

        // Skip the cell itself.
        if i == 0 && j == 0 {
            continue;
        }

        // Check if the neighbor is within the grid bounds.
        if let Some(&cell) = grid.get((y as i32 + i) as usize)
                                 .and_then(|row| row.get((x as i32 + j) as usize))
        {

            // Increment the count if the neighbor is live.
            count += cell as usize;
        }
    }
}

Displaying the Grid

The grid is printed to the terminal using the termsize crate to fit the terminal size dynamically.

Conclusion

Implementing Conway’s Game of Life in Rust was a fun and educational experience. Rust’s performance and safety make it an excellent choice for this kind of simulation. I hope you find this project as enjoyable to explore and extend as I did. Feel free to visit the GitHub repository for the full source code and further details.

Happy coding!

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *