Skip to content

Instantly share code, notes, and snippets.

@bynect
Last active August 24, 2021 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bynect/91f0f2a7b1cb2adc6b3cb71827c1ea6f to your computer and use it in GitHub Desktop.
Save bynect/91f0f2a7b1cb2adc6b3cb71827c1ea6f to your computer and use it in GitHub Desktop.
Game of Life implementation in Rust. Depends on the rand crate for generating random grids.
use std::thread::sleep;
use std::time::Duration;
// Add rand in the dependencies section of Cargo.toml
use rand::Rng;
#[derive(Debug, Copy, Clone)]
enum Cell {
Dead = 0,
Live = 1,
}
impl Cell {
fn dead(self) -> bool {
match self {
Cell::Dead => true,
Cell::Live => false,
}
}
fn live(self) -> bool {
!self.dead()
}
}
#[derive(Debug)]
struct Grid {
height: usize,
width: usize,
grid: Vec<Cell>,
}
impl Grid {
fn new(height: usize, width: usize) -> Self {
Self {
height,
width,
grid: {
let len = height * width;
let mut grid = Vec::with_capacity(len);
for _ in 0..len {
grid.push(Cell::Dead);
}
grid
},
}
}
fn new_rand<F: FnMut() -> Cell>(height: usize, width: usize, mut rand: F) -> Self {
Self {
height,
width,
grid: {
let len = height * width;
let mut grid = Vec::with_capacity(len);
for _ in 0..len {
grid.push(rand());
}
grid
},
}
}
fn at(&self, x: usize, y: usize) -> &Cell {
&self.grid[y * self.height + x]
}
fn neighbours(&self, x: usize, y: usize) -> usize {
let top = if x == 0 { self.height - 1 } else { x - 1 };
let bottom = if x + 1 == self.height { 0 } else { x + 1 };
let left = if y == 0 { self.width - 1 } else { y - 1 };
let right = if y + 1 == self.width { 0 } else { y + 1 };
self.at(top, left).live() as usize
+ self.at(top, y).live() as usize
+ self.at(top, right).live() as usize
+ self.at(x, left).live() as usize
+ self.at(x, right).live() as usize
+ self.at(bottom, left).live() as usize
+ self.at(bottom, y).live() as usize
+ self.at(bottom, right).live() as usize
}
fn evolve(&mut self) -> bool {
let mut grid = Vec::with_capacity(self.grid.len());
let mut live = false;
for i in 0..self.height {
for j in 0..self.width {
if self.at(i, j).dead() {
let neighbours = self.neighbours(i, j);
if neighbours == 3 {
grid.push(Cell::Live);
live = true;
} else {
grid.push(Cell::Dead)
}
} else {
let neighbours = self.neighbours(i, j);
if neighbours == 2 || neighbours == 3 {
grid.push(Cell::Live);
live = true;
} else {
grid.push(Cell::Dead)
}
}
}
}
self.grid = grid;
live
}
fn show(&self) {
print!("\x1b[2J");
for i in 0..self.height {
for j in 0..self.width {
if self.at(i, j).dead() {
print!("[ ] ");
} else {
print!("[X] ")
}
}
print!("\n")
}
}
}
fn main() {
let mut rng = rand::thread_rng();
let mut grid = Grid::new_rand(20, 25, move || {
if rng.gen::<bool>() {
Cell::Dead
} else {
Cell::Live
}
});
let mut gen = 0;
loop {
gen += 1;
let live = grid.evolve();
grid.show();
if live || break {
sleep(Duration::from_millis(500));
}
}
println!("Lasted {} generations", gen)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment