Last active
June 21, 2016 19:23
-
-
Save amcoder/c78f997bcf17018dabab7d7cc1dae754 to your computer and use it in GitHub Desktop.
Life
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod life { | |
use std::usize; | |
#[derive(Debug)] | |
#[derive(PartialEq)] | |
#[derive(Copy)] | |
#[derive(Clone)] | |
pub enum Cell { | |
Alive, | |
Dead, | |
} | |
#[derive(Debug)] | |
#[derive(PartialEq)] | |
pub enum Error { | |
ParseError, | |
} | |
#[derive(Debug)] | |
#[derive(PartialEq)] | |
#[derive(Clone)] | |
pub struct World { | |
size: usize, | |
data: Vec<Cell>, | |
} | |
impl World { | |
pub fn new(size: usize) -> World { | |
World{size: size, data: vec![Cell::Dead; size * size]} | |
} | |
pub fn tick(&self) -> World { | |
let mut data = vec![Cell::Dead; self.size * self.size]; | |
for i in 0..self.size { | |
for j in 0..self.size { | |
data[i * self.size + j] = self.tick_cell(i, j); | |
} | |
} | |
World{size: self.size, data: data} | |
} | |
fn tick_cell(&self, i: usize, j: usize) -> Cell { | |
match self.population_at(i, j) { | |
3 => Cell::Alive, | |
4 => self.data[i * self.size + j], | |
_ => Cell::Dead, | |
} | |
} | |
pub fn get(&self, i: usize, j: usize) -> Cell { | |
if i >= self.size || j >= self.size { | |
Cell::Dead | |
} else { | |
self.data[i * self.size + j] | |
} | |
} | |
fn population_at(&self, i: usize, j: usize) -> i32 { | |
let mut result = 0; | |
let min_i = i.checked_sub(1).unwrap_or(0); | |
let min_j = j.checked_sub(1).unwrap_or(0); | |
for i in min_i..i+2 { | |
for j in min_j..j+2 { | |
if self.get(i, j) == Cell::Alive { | |
result += 1; | |
} | |
} | |
} | |
result | |
} | |
} | |
impl ::std::str::FromStr for World { | |
type Err = Error; | |
fn from_str(s: &str) -> Result<World, Error> { | |
let size = s.lines().count(); | |
if size == 0 || s.lines().nth(0).unwrap().len() != size { | |
return Err(Error::ParseError); | |
} | |
let mut data = vec![]; | |
for line in s.lines() { | |
if line.len() != size { | |
return Err(Error::ParseError); | |
} | |
for c in line.chars() { | |
let state = match c { | |
'.' => Cell::Dead, | |
'*' => Cell::Alive, | |
_ => return Err(Error::ParseError), | |
}; | |
data.push(state); | |
} | |
} | |
Ok(World{size: size, data: data}) | |
} | |
} | |
impl ::std::fmt::Display for World { | |
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | |
for i in 0..self.size { | |
let row = i * self.size; | |
let line: String = self.data[row..row + self.size].into_iter(). | |
map(|c| { | |
match *c { | |
Cell::Dead => " ", | |
Cell::Alive => "()", | |
} | |
}).collect(); | |
try!(write!(f, "{}\n", line)); | |
} | |
Ok(()) | |
} | |
} | |
pub struct WorldIterator { | |
world: World | |
} | |
impl<'a> IntoIterator for &'a World { | |
type Item = &'a World; | |
type IntoIter = WorldIterator; | |
fn into_iter(self) -> Self::IntoIter { | |
WorldIterator{world: self.clone()} | |
} | |
} | |
impl<'a> Iterator for WorldIterator { | |
type Item = &'a World; | |
fn next<'b>(&'b mut self) -> Option<Self::Item> { | |
// I realize this is wrong, but I don't know where to go from here. | |
let old = self.world; | |
self world = old.tick(); | |
Some(old) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm trying to implement an iterator for the world, but I'm getting lifetime errors. I've been playing with lifetimes for a while and I get different variations on lifetime issues.