Skip to content

Instantly share code, notes, and snippets.

@bynect
Created August 24, 2021 16:08
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/a0d0087e87271f8e1e02c735d46d63c1 to your computer and use it in GitHub Desktop.
Save bynect/a0d0087e87271f8e1e02c735d46d63c1 to your computer and use it in GitHub Desktop.
Standalone Game of Life implementation in Rust. Uses libc's rand and srand functions for generating random grids.
use std::thread::sleep;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[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")
}
}
}
extern "C" {
fn srand(seed: u32);
fn rand() -> i32;
}
const GRID_HEIGHT: usize = 20;
const GRID_WIDTH: usize = 25;
fn main() {
// Seed libc prng with the current time
let time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
unsafe {
srand(time as u32);
};
let mut grid = Grid::new_rand(GRID_HEIGHT, GRID_WIDTH, || {
if unsafe { rand() % 2 == 0 } {
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