cell-automata-1d 0.1.2

Look Stephen Wolfram's cellular automata: https://www.wolframscience.com/nks/p170--cellular-automata/
Documentation
use crate::rule::*;

pub struct CellAutomata1D {
    state: Vec<bool>,
    rule: Rule
}

impl CellAutomata1D {
    pub fn new(init_state: &str, rule_num: u8) -> Self {
        CellAutomata1D { 
            state: Self::str_state_to_vec(init_state), 
            rule: Rule::new(rule_num) 
        }
    }

    pub fn with_rule(rule_num: u8) -> Self {
        CellAutomata1D { 
            state: Vec::new(), 
            rule: Rule::new(rule_num) 
        }
    }

    pub fn set_state(&mut self, state: &str) {
        self.state = Self::str_state_to_vec(state);
    }

    pub fn set_rule(&mut self, number: u8) {
        self.rule = Rule::new(number);
    }

    pub fn next(&mut self) {
        let mut next_state: Vec<bool> = Vec::with_capacity(self.state.len());
        next_state.resize(self.state.len(), false);
        for i in 0..self.state.len() {
            let triad = self.triad_for(i);
            next_state[i] = self.rule.result_of(triad);
        }
        self.state = next_state;
    }

    pub fn string_state(&self) -> String {
        let mut state_str = String::with_capacity(self.state.len());
        for cell in self.state.iter() {
            state_str.push(if *cell {'#'} else {' '});
        }
        state_str
    }

    pub fn get_state(&self) -> Vec<bool> {
        self.state.clone()
    }

    fn triad_for(&self, ind: usize) -> [bool; 3] {
        let ind = ind as isize;
        let mut triad = [false; 3];
        let mut bit_ind = 0;
        for i in ind-1..=ind+1 {
            triad[bit_ind] = self.cycle_at(i);
            bit_ind += 1;
        }
        triad
    }

    fn cycle_at(&self, ind: isize) -> bool {
        if ind >= self.state.len() as isize {
            self.state[0]
        } else if ind < 0 {
            *self.state.last().unwrap()
        } else {
            self.state[ind as usize]
        }
    }

    fn str_state_to_vec(str: &str) -> Vec<bool> {
        let mut vec: Vec<bool> = Vec::with_capacity(str.len());
        for ch in str.chars() {
            vec.push(if ch != '0' {true} else {false});
        }
        vec
    }
}

#[cfg(test)]
mod tests {
    use crate::cellauto::*;

    #[test]
    fn automata_work() {
        let mut automata = CellAutomata1D::new("00001001", 2);
        automata.next();
        assert_eq!(automata.string_state(), "   #  # ");
        automata.next();
        assert_eq!(automata.string_state(), "  #  #  ");
    }

    #[test]
    fn setting_state_works() {
        let mut automata = CellAutomata1D::new("00001001", 2);
        automata.next();
        assert_eq!(automata.string_state(), "   #  # ");
        automata.set_state("10000100");
        automata.next();
        assert_eq!(automata.string_state(), "    #  #");

        let mut automata = CellAutomata1D::with_rule(18);
        automata.set_state("00010000");
        automata.next();
        assert_eq!(automata.string_state(), "  # #   ");
    }

    #[test]
    fn printing_state() {
        let automata = CellAutomata1D::new("11100101", 0b00000100);
        assert_eq!(automata.string_state(), "###  # #");
    }

    #[test]
    fn triad_creating() {
        let automata = CellAutomata1D::new("10000101", 0xff);
        assert_eq!(automata.triad_for(0), [true, true, false]);
        assert_eq!(automata.triad_for(7), [false, true, true]);
        assert_eq!(automata.triad_for(4), [false, false, true]);
    }

    #[test]
    fn cycle_state_indexing() {
        let automata = CellAutomata1D::new("00000101", 0xff);
        assert_eq!(automata.cycle_at(-1), true);
        assert_eq!(automata.cycle_at(8), false);
        assert_eq!(automata.cycle_at(5), true);
        assert_eq!(automata.cycle_at(4), false);
    }

    #[test]
    fn reading_state_from_str() {
        let readed = CellAutomata1D::str_state_to_vec("11100101");
        assert_eq!(readed, vec![true, true, true, false, false, true, false, true]);
    }
}