RosettaCodeData/Task/Wireworld/Rust/wireworld-1.rust

99 lines
2.7 KiB
Plaintext

use std::str::FromStr;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum State {
Empty,
Conductor,
ElectronTail,
ElectronHead,
}
impl State {
fn next(&self, e_nearby: usize) -> State {
match self {
State::Empty => State::Empty,
State::Conductor => {
if e_nearby == 1 || e_nearby == 2 {
State::ElectronHead
} else {
State::Conductor
}
}
State::ElectronTail => State::Conductor,
State::ElectronHead => State::ElectronTail,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WireWorld {
pub width: usize,
pub height: usize,
pub data: Vec<State>,
}
impl WireWorld {
pub fn new(width: usize, height: usize) -> Self {
WireWorld {
width,
height,
data: vec![State::Empty; width * height],
}
}
pub fn get(&self, x: usize, y: usize) -> Option<State> {
if x >= self.width || y >= self.height {
None
} else {
self.data.get(y * self.width + x).copied()
}
}
pub fn set(&mut self, x: usize, y: usize, state: State) {
self.data[y * self.width + x] = state;
}
fn neighbors<F>(&self, x: usize, y: usize, mut f: F) -> usize
where F: FnMut(State) -> bool
{
let (x, y) = (x as i32, y as i32);
let neighbors = [(x-1,y-1),(x-1,y),(x-1,y+1),(x,y-1),(x,y+1),(x+1,y-1),(x+1,y),(x+1,y+1)];
neighbors.iter().filter_map(|&(x, y)| self.get(x as usize, y as usize)).filter(|&s| f(s)).count()
}
pub fn next(&mut self) {
let mut next_state = vec![];
for y in 0..self.height {
for x in 0..self.width {
let e_count = self.neighbors(x, y, |e| e == State::ElectronHead);
next_state.push(self.get(x, y).unwrap().next(e_count));
}
}
self.data = next_state;
}
}
impl FromStr for WireWorld {
type Err = ();
fn from_str(s: &str) -> Result<WireWorld, ()> {
let s = s.trim();
let height = s.lines().count();
let width = s.lines().map(|l| l.trim_end().len()).max().unwrap_or(0);
let mut world = WireWorld::new(width, height);
for (y, line) in s.lines().enumerate() {
for (x, ch) in line.trim_end().chars().enumerate() {
let state = match ch {
'.' => State::Conductor,
't' => State::ElectronTail,
'H' => State::ElectronHead,
_ => State::Empty,
};
world.set(x, y, state);
}
}
Ok(world)
}
}