Skip to content

Instantly share code, notes, and snippets.

@hmarr
Last active August 29, 2015 14:03
Show Gist options
  • Save hmarr/85be0a3c4ad10eeb17e0 to your computer and use it in GitHub Desktop.
Save hmarr/85be0a3c4ad10eeb17e0 to your computer and use it in GitHub Desktop.
Conway's Game of Life in Rust
use std::io::{print};
use std::cmp::{min,max};
use std::time::Duration;
#[deriving(Clone,Show,PartialEq)]
enum Cell {
Alive,
Dead,
}
struct Board {
cells: Vec<Cell>,
size: uint,
}
impl Board {
fn new(cells: Vec<Cell>) -> Board {
let size = (cells.len() as f64).sqrt() as uint;
Board {
cells: cells,
size: size,
}
}
fn from_str(layout: &str) -> Board {
let mut cells = Vec::new();
for word in layout.words() {
match word {
"-" => cells.push(Dead),
"X" => cells.push(Alive),
_ => (),
}
}
Board::new(cells)
}
fn tick(&mut self) {
let new_cells = Vec::from_fn(self.size * self.size, |i| -> Cell {
let cell = self.cell(i);
match cell {
Alive => self.handle_live_cell(i),
Dead => self.handle_dead_cell(i),
}
});
self.cells = new_cells;
}
fn cell(&self, i: uint) -> Cell {
self.cells[i]
}
fn handle_live_cell(&self, cell_index: uint) -> Cell {
match self.num_neighbours(cell_index) {
0...1 => Dead,
2...3 => Alive,
_ => Dead,
}
}
fn handle_dead_cell(&self, cell_index: uint) -> Cell {
match self.num_neighbours(cell_index) {
3 => Alive,
_ => Dead,
}
}
fn num_neighbours(&self, cell_index: uint) -> uint {
let cell_x: int = (cell_index % self.size) as int;
let cell_y: int = (cell_index / self.size) as int;
let mut neighbours = 0;
for y in range(max(cell_y - 1, 0), min(cell_y + 2, self.size as int)) {
for x in range(max(cell_x - 1, 0), min(cell_x + 2, self.size as int)) {
let neighbour_index: int = y * (self.size as int) + x;
if neighbour_index != cell_index as int {
neighbours += match self.cells[neighbour_index as uint] {
Alive => 1,
Dead => 0,
}
}
}
}
neighbours
}
fn render(&self) {
for y in range(0, self.size) {
for x in range(0, self.size) {
match self.cell(x + y * self.size) {
Alive => print("◉ "),
Dead => print("◯ "),
}
}
print("\n")
}
}
}
static BLINKER: &'static str = "
- - - - -
- - X - -
- - X - -
- - X - -
- - - - -
";
static TOAD: &'static str = "
- - - - - -
- - - - - -
- - X X X -
- X X X - -
- - - - - -
- - - - - -
";
static R_PENTAMINO: &'static str = "
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - X X - - - -
- - - X X - - - - -
- - - - X - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - -
";
fn main() {
let args = std::os::args();
let mut template_name = String::from_str("blinker");
if args.len() > 1 {
template_name = args[1].clone();
}
let template = match template_name.as_slice() {
"blinker" => BLINKER,
"toad" => TOAD,
"r-pentamino" => R_PENTAMINO,
_ => {
println!("invalid template '{}'", template_name);
std::os::set_exit_status(1);
return;
}
};
let mut board = Board::from_str(template);
loop {
board.render();
board.tick();
std::io::timer::sleep(Duration::milliseconds(100));
// Move cursor back up <board.size> lines
print!("{}[{}A", '\x1B', board.size);
}
}
#[test]
fn underpopulation_causes_death() {
let mut board = Board::new(vec![
Dead, Alive,
Dead, Alive,
]);
board.tick();
assert_eq!(board.cells, Vec::from_elem(4, Dead));
}
#[test]
fn two_neighbours_lives_on() {
let mut board = Board::new(vec![
Alive, Alive,
Dead, Alive,
]);
board.tick();
assert_eq!(board.cell(1), Alive)
}
#[test]
fn three_neighbours_lives_on() {
let mut board = Board::new(vec![
Dead, Dead, Alive,
Dead, Alive, Alive,
Dead, Dead, Alive,
]);
board.tick();
assert_eq!(board.cell(5), Alive)
}
#[test]
fn overcrowding_causes_death() {
let mut board = Board::new(vec![
Dead, Alive, Alive,
Dead, Alive, Alive,
Dead, Alive, Alive,
]);
board.tick();
assert_eq!(board.cell(4), Dead)
assert_eq!(board.cell(5), Dead)
}
#[test]
fn two_neighbours_stays_dead() {
let mut board = Board::new(vec![
Alive, Dead,
Dead, Alive,
]);
board.tick();
assert_eq!(board.cell(1), Dead)
}
#[test]
fn three_neighbours_becomes_alive() {
let mut board = Board::new(vec![
Dead, Dead, Alive,
Dead, Alive, Dead,
Dead, Dead, Alive,
]);
board.tick();
assert_eq!(board.cell(5), Alive)
}
#[test]
fn four_neighbours_stays_dead() {
let mut board = Board::new(vec![
Dead, Alive, Alive,
Dead, Alive, Dead,
Dead, Dead, Alive,
]);
board.tick();
assert_eq!(board.cell(5), Dead)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment