Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use image::ImageBuffer;
- use image::Rgb;
- use image::RgbImage;
- use std::fmt::Display;
- use std::fmt::Error;
- use std::fmt::Formatter;
- const RULE_110: u8 = 110;
- pub enum RowStartPosition {
- Left,
- Right,
- Center,
- }
- pub struct Generation {
- cells: Vec<bool>,
- }
- impl Display for Generation {
- fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
- let generation_as_string: String = self
- .cells
- .iter()
- .map(|cell_state| match *cell_state {
- true => '■',
- false => '□',
- })
- .collect();
- write!(f, "{}", generation_as_string)
- }
- }
- impl Generation {
- pub fn new(width: usize, start_position: RowStartPosition) -> Self {
- assert!(
- width > 0,
- "You can't create 0 width rows, please create something of width 1 or larger."
- );
- let start_point = match start_position {
- RowStartPosition::Left => 0,
- RowStartPosition::Right => width - 1,
- RowStartPosition::Center => width / 2,
- };
- Generation {
- cells: (0..width)
- .map(|index: usize| index == start_point)
- .collect(),
- }
- }
- pub fn get_cell_state(&self, cell_index: usize) -> Option<bool> {
- if cell_index + 1 >= self.cells.len() {
- return None;
- }
- Some(self.cells[cell_index])
- }
- pub fn get_next_generation(&self, rules: u8) -> Self {
- Generation {
- cells: self
- .cells
- .iter()
- .enumerate()
- .map(|(index, _)| self.get_next_cell_state(index, rules))
- .collect(),
- }
- }
- fn get_next_cell_state(&self, cell_index: usize, rules: u8) -> bool {
- let (left_neighbour, current_state, right_neighbour) =
- self.get_cell_and_neighbours(cell_index);
- get_next_cell_state(left_neighbour, current_state, right_neighbour, rules)
- }
- fn get_cell_and_neighbours(&self, cell_index: usize) -> (bool, bool, bool) {
- let left_neighbour_index: usize =
- get_left_neighbour_index_wrapping(cell_index, self.cells.len());
- let right_neighbour_index: usize =
- get_right_neighbour_index_wrapping(cell_index, self.cells.len());
- (
- self.cells[left_neighbour_index],
- self.cells[cell_index],
- self.cells[right_neighbour_index],
- )
- }
- }
- pub struct CellularAutomataSystem {
- generations: Vec<Generation>,
- width: usize,
- rules: u8,
- }
- impl Display for CellularAutomataSystem {
- fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
- let generations: Vec<String> = self
- .generations
- .iter()
- .map(|generation| generation.to_string())
- .collect();
- let generations_as_string = generations.join("\n");
- write!(f, "{}", generations_as_string)
- }
- }
- impl CellularAutomataSystem {
- pub fn from_rules(rules: u8) -> Self {
- let width = 30;
- CellularAutomataSystem {
- generations: vec![Generation::new(width, RowStartPosition::Center)],
- width,
- rules,
- }
- }
- pub fn update(&mut self) {
- let next_generation = self
- .get_next_generation()
- .expect("Failed to generate the next generation.");
- self.generations.push(next_generation);
- }
- pub fn as_image_buffer(&self) -> RgbImage {
- ImageBuffer::from_fn(
- self.width as u32,
- self.generations.len() as u32,
- |x, y| match self.generations[y as usize].get_cell_state(x as usize) {
- Some(true) => Rgb([255u8, 255u8, 255u8]),
- _ => Rgb([0u8, 0u8, 0u8]),
- },
- )
- }
- pub fn get_generations(&self) -> &Vec<Generation> {
- &self.generations
- }
- fn get_next_generation(&self) -> Option<Generation> {
- if let Some(current_generation) = self.generations.last() {
- return Some(current_generation.get_next_generation(self.rules));
- }
- None
- }
- }
- fn get_next_cell_state(
- left_neighbour: bool,
- current_state: bool,
- right_neighbour: bool,
- rules: u8,
- ) -> bool {
- match (left_neighbour, current_state, right_neighbour) {
- (true, true, true) => rules & 0b00000001u8 == rules,
- (true, true, false) => rules & 0b00000010u8 == rules,
- (true, false, true) => rules & 0b00000100u8 == rules,
- (true, false, false) => rules & 0b00001000u8 == rules,
- (false, true, true) => rules & 0b00010000u8 == rules,
- (false, true, false) => rules & 0b00100000u8 == rules,
- (false, false, true) => rules & 0b01000000u8 == rules,
- (false, false, false) => rules & 0b10000000u8 == rules,
- }
- }
- fn get_right_neighbour_index_wrapping(current_index: usize, collection_size: usize) -> usize {
- get_index_wrapping(
- current_index as isize + 1 as isize,
- collection_size as isize,
- ) as usize
- }
- fn get_left_neighbour_index_wrapping(current_index: usize, collection_size: usize) -> usize {
- get_index_wrapping(current_index as isize - 1, collection_size as isize) as usize
- }
- fn get_index_wrapping(index: isize, upper_bound: isize) -> isize {
- if index >= 0 {
- index % upper_bound
- } else {
- (index % upper_bound + upper_bound) % upper_bound
- }
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- #[test]
- fn test_get_index_wrapping() {
- assert_eq!(0, get_index_wrapping(0, 10));
- assert_eq!(0, get_index_wrapping(10, 10));
- assert_eq!(5, get_index_wrapping(5, 10));
- assert_eq!(9, get_index_wrapping(19, 10));
- assert_eq!(0, get_index_wrapping(-10, 10));
- }
- #[test]
- fn test_get_right_neighbour_index_wrapping() {
- assert_eq!(1, get_right_neighbour_index_wrapping(0, 4));
- assert_eq!(0, get_right_neighbour_index_wrapping(3, 4));
- }
- #[test]
- fn test_get_left_neighbour_index_wrapping() {
- assert_eq!(2, get_left_neighbour_index_wrapping(3, 4));
- assert_eq!(3, get_left_neighbour_index_wrapping(0, 4));
- }
- fn get_next_cell_state_rule_30(
- left_neighbour: bool,
- current_state: bool,
- right_neighbour: bool,
- ) -> bool {
- match (left_neighbour, current_state, right_neighbour) {
- (true, true, true) => false,
- (true, true, false) => false,
- (true, false, true) => false,
- (true, false, false) => true,
- (false, true, true) => true,
- (false, true, false) => true,
- (false, false, true) => true,
- (false, false, false) => false,
- }
- }
- #[test]
- fn test_get_next_cell_state() {
- assert_eq!(
- get_next_cell_state(true, true, true, 30),
- get_next_cell_state_rule_30(true, true, true)
- );
- assert_eq!(
- get_next_cell_state(true, true, false, 30),
- get_next_cell_state_rule_30(true, true, false)
- );
- assert_eq!(
- get_next_cell_state(true, false, true, 30),
- get_next_cell_state_rule_30(true, false, true)
- );
- assert_eq!(
- get_next_cell_state(true, false, false, 30),
- get_next_cell_state_rule_30(true, false, false)
- );
- assert_eq!(
- get_next_cell_state(false, true, true, 30),
- get_next_cell_state_rule_30(false, true, true)
- );
- assert_eq!(
- get_next_cell_state(true, true, false, 30),
- get_next_cell_state_rule_30(true, true, false)
- );
- assert_eq!(
- get_next_cell_state(false, false, true, 30),
- get_next_cell_state_rule_30(false, false, true)
- );
- assert_eq!(
- get_next_cell_state(false, false, false, 30),
- get_next_cell_state_rule_30(false, false, false)
- );
- }
- }
Add Comment
Please, Sign In to add comment