auto_worlds 0.1.0

Worlds implementing different rules for cellular automata
Documentation
pub mod cell {
    use auto_cellular::cell::BasicCell;
    use rand::Rng;

    use crate::PROPORTION;

    #[derive(Clone, Copy, Debug)]
    pub enum Direction {
        Left,
        Right,
        Up,
        Down,
    }

    impl Direction {
        pub fn cw(&self) -> Self {
            match *self {
                Direction::Left => Direction::Up,
                Direction::Right => Direction::Down,
                Direction::Up => Direction::Right,
                Direction::Down => Direction::Left,
            }
        }

        pub fn ccw(&self) -> Self {
            match *self {
                Direction::Left => Direction::Down,
                Direction::Right => Direction::Up,
                Direction::Up => Direction::Left,
                Direction::Down => Direction::Right,
            }
        }
    }

    #[derive(Clone, Copy, Debug)]
    pub enum CellType {
        CW,
        CCW,
    }

    #[derive(Clone, Copy, Debug)]
    pub struct Color {
        pub cell_type: CellType,
        pub value: usize,
    }

    impl Color {
        pub fn next(&self) -> Self {
            Self {
                cell_type: self.cell_type,
                value: self.value + 1,
            }
        }
    }

    #[derive(Clone, Copy, Debug)]
    pub enum Cell {
        Color(Color),
        Ant(Direction, Color),
    }

    impl Cell {
        pub fn to_ant(&self) -> Self {
            match *self {
                s @ Self::Ant(_, _) => s,
                Self::Color(c) => Self::Ant(Direction::Left, c),
            }
        }

        pub fn to_color(&self) -> Self {
            match *self {
                s @ Self::Color(_) => s,
                Self::Ant(_, c) => Self::Color(c),
            }
        }
    }

    impl Default for Cell {
        fn default() -> Self {
            Self::Color(Color {
                value: 0,
                cell_type: CellType::CW,
            })
        }
    }

    impl BasicCell for Cell {
        fn next_state(&self) -> Self {
            match *self {
                Self::Ant(d, c) => {
                    if matches!(d, Direction::Down) {
                        self.to_color()
                    } else {
                        Self::Ant(d.cw(), c)
                    }
                }
                Self::Color(c) => Self::Color(c.next()),
            }
        }

        fn random<R: Rng + ?Sized>(rng: &mut R) -> Self {
            if rng.gen_bool(PROPORTION) {
                Cell::Color(Color {
                    cell_type: if rng.gen_bool(0.5) {
                        CellType::CW
                    } else {
                        CellType::CCW
                    },
                    value: 0,
                })
            } else {
                Cell::Color(Color {
                    cell_type: if rng.gen_bool(0.5) {
                        CellType::CW
                    } else {
                        CellType::CCW
                    },
                    value: 1,
                })
            }
        }
    }

    impl Cell {
        pub fn random_with_pattern<R: Rng + ?Sized>(rng: &mut R, pattern: &Vec<CellType>) -> Self {
            let v = rng.gen_range(0..pattern.len());
            Self::Color(Color {
                value: v,
                cell_type: pattern[v],
            })
        }
    }
}

pub mod world {
    use auto_cellular::{
        common::{linearize, Dimensions, DoubleVec, Index},
        world::BasicWorld,
    };
    use rand::Rng;

    use super::cell::{Cell, CellType, Color, Direction};

    pub struct World {
        cells: DoubleVec<Cell>,
        dimensions: Dimensions,
        delta: Vec<(Index, Cell)>,
        ant_pos: Index,
        pub pattern: Vec<CellType>,
    }

    impl BasicWorld<Cell> for World {
        fn new(mut cells: DoubleVec<Cell>, dimensions: Dimensions) -> Self {
            let mut ant_pos = None;
            'outer: for (j, row) in cells.iter().enumerate() {
                for (i, c) in row.iter().enumerate() {
                    if matches!(c, Cell::Ant(_, _),) {
                        ant_pos = Some((i, j));
                        break 'outer;
                    }
                }
            }

            if ant_pos.is_none() {
                ant_pos = Some((dimensions.0 / 2, dimensions.1 / 2));
                let ant_pos = ant_pos.unwrap();
                let c = &mut cells[ant_pos.1][ant_pos.0];
                *c = c.to_ant();
            }

            let delta = linearize(cells.clone());

            Self {
                cells,
                dimensions,
                delta,
                ant_pos: ant_pos.unwrap(),
                pattern: vec![CellType::CW, CellType::CCW],
            }
        }

        fn cells(&self) -> &DoubleVec<Cell> {
            &self.cells
        }

        fn cells_mut(&mut self) -> &mut DoubleVec<Cell> {
            &mut self.cells
        }

        fn changes(&self) -> Vec<(Index, Cell)> {
            let mut delta = Vec::with_capacity(2);
            let ant = self.cells()[self.ant_pos.1][self.ant_pos.0];
            if let Cell::Ant(d, c) = ant {
                let value = (c.value + 1) % self.pattern.len();
                delta.push((
                    self.ant_pos,
                    Cell::Color(Color {
                        value,
                        cell_type: self.pattern[value],
                    }),
                ));
                let new_direction = match self.pattern[c.value] {
                    CellType::CW => d.cw(),
                    CellType::CCW => d.ccw(),
                };

                let new_ant_pos = match new_direction {
                    Direction::Right => {
                        ((self.ant_pos.0 + 1) % self.dimensions().0, self.ant_pos.1)
                    }
                    Direction::Down => (self.ant_pos.0, (self.ant_pos.1 + 1) % self.dimensions().1),
                    Direction::Left => (
                        if self.ant_pos.0 == 0 {
                            self.dimensions().0 - 1
                        } else {
                            self.ant_pos.0 - 1
                        },
                        self.ant_pos.1,
                    ),
                    Direction::Up => (
                        self.ant_pos.0,
                        if self.ant_pos.1 == 0 {
                            self.dimensions().1 - 1
                        } else {
                            self.ant_pos.1 - 1
                        },
                    ),
                };

                let color: Color;
                if let Cell::Color(new_c) = self.cells()[new_ant_pos.1][new_ant_pos.0] {
                    color = new_c
                } else {
                    panic!("Should always be a color.");
                }

                delta.push((new_ant_pos, Cell::Ant(new_direction, color)))
            } else {
                panic!("This should always be an ant.");
            }

            delta
        }

        fn delta(&self) -> &Vec<(Index, Cell)> {
            &self.delta
        }

        fn delta_mut(&mut self) -> &mut Vec<(Index, Cell)> {
            &mut self.delta
        }

        fn dimensions(&self) -> Dimensions {
            self.dimensions
        }

        fn tick(&mut self) {
            let delta = self.changes();
            assert_eq!(delta.len(), 2);
            let color = delta[0];
            let ant = delta[1];
            self.ant_pos = ant.0;
            self.cells_mut()[color.0 .1][color.0 .0] = color.1;
            self.cells_mut()[ant.0 .1][ant.0 .0] = ant.1;

            *self.delta_mut() = delta;
        }

        fn blank(&self) -> Self {
            let default = Cell::Color(Color {
                value: 0,
                cell_type: self.pattern[0],
            });
            Self::new_with_pattern(
                vec![vec![default; self.dimensions().0]; self.dimensions().1],
                self.dimensions(),
                self.pattern.clone(),
            )
        }

        fn random<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Self {
            let cells = vec![vec![(); self.dimensions().0]; self.dimensions().1]
                .into_iter()
                .map(|row| {
                    row.into_iter()
                        .map(|_| Cell::random_with_pattern(rng, &self.pattern))
                        .collect()
                })
                .collect();

            Self::new_with_pattern(cells, self.dimensions(), self.pattern.clone())
        }
    }

    impl World {
        pub fn new_with_pattern(
            cells: DoubleVec<Cell>,
            dimensions: Dimensions,
            pattern: Vec<CellType>,
        ) -> Self {
            let mut w = Self::new(cells, dimensions);
            w.pattern = pattern;
            w
        }

        pub fn random_with_pattern_of_length<R: Rng + ?Sized>(
            rng: &mut R,
            dimensions: Dimensions,
            n: usize,
        ) -> Self {
            let mut pattern = Vec::with_capacity(n);
            for _ in 0..n {
                let f: f64 = rng.gen();
                if f < 0.5 {
                    pattern.push(CellType::CW)
                } else {
                    pattern.push(CellType::CCW)
                }
            }

            Self::random_with_pattern_of(rng, dimensions, pattern)
        }

        pub fn random_with_pattern_of<R: Rng + ?Sized>(
            rng: &mut R,
            dimensions: Dimensions,
            pattern: Vec<CellType>,
        ) -> Self {
            let mut cells = Vec::with_capacity(dimensions.1);
            for _ in 0..dimensions.1 {
                let mut row = Vec::with_capacity(dimensions.0);
                for _ in 0..dimensions.0 {
                    let v = rng.gen_range(0..pattern.len());
                    row.push(Cell::Color(Color {
                        value: v,
                        cell_type: pattern[v],
                    }))
                }
                cells.push(row);
            }

            Self::new_with_pattern(cells, dimensions, pattern)
        }
    }
}