diff --git a/2018/rust/src/bin/day_12.rs b/2018/rust/src/bin/day_12.rs new file mode 100644 index 0000000..960c8a9 --- /dev/null +++ b/2018/rust/src/bin/day_12.rs @@ -0,0 +1,161 @@ +use std::collections::HashMap; +use std::error::Error; +use std::fmt; +use std::str::FromStr; + +use regex::Regex; + +use advent_of_code::main; + +main!(); + +fn solve(input: &str) -> Result> { + let mut generation: Generation = input.parse()?; + for _ in 0..19 { + generation.next(); + } + + let pots = generation.next().unwrap(); + let indices: Vec<_> = pots.iter().filter(|(_,&v)| v).map(|(&k,_)| k).collect(); + let output: isize = indices.iter().sum(); + + Ok(output.to_string()) +} + +#[test] +fn test_solve() { + let input = r" +initial state: #..#.#..##......###...### + +...## => # +..#.. => # +.#... => # +.#.#. => # +.#.## => # +.##.. => # +.#### => # +#.#.# => # +#.### => # +##.#. => # +##.## => # +###.. => # +###.# => # +####. => # + "; + + assert_eq!(solve(&input).unwrap(), 325.to_string()); +} + +struct Generation { + pots: HashMap, + notes: HashMap, +} + +impl fmt::Display for Generation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let plants: Vec<_> = self + .pots + .iter() + .filter(|(_, &v)| v) + .map(|(&k, _)| k) + .collect(); + let min = *plants.iter().min().unwrap(); + let max = *plants.iter().max().unwrap(); + let s: String = (min..=max) + .map(|x| self.pots.get(&x).unwrap_or_else(|| &false)) + .map(|&x| if x { '#' } else { '.' }) + .collect(); + write!(f, "{}", s) + } +} + +impl Iterator for Generation { + type Item = HashMap; + + fn next(&mut self) -> Option { + let plants: Vec<_> = self + .pots + .iter() + .filter(|(_, &v)| v) + .map(|(&k, _)| k) + .collect(); + let min = *plants.iter().min().unwrap() - 2; + let max = *plants.iter().max().unwrap() + 2; + self.pots = (min..=max) + .map(|i| { + let key: String = ((i - 2)..=(i + 2)) + .map(|x| self.pots.get(&x).unwrap_or_else(|| &false)) + .map(|&x| if x { '#' } else { '.' }) + .collect(); + let value = *self.notes.get(&key).unwrap_or_else(|| &false); + (i, value) + }) + .collect(); + + Some(self.pots.clone()) + } +} + +#[test] +fn test_generation() { + let input = r" +initial state: #..#.#..##......###...### + +...## => # +..#.. => # +.#... => # +.#.#. => # +.#.## => # +.##.. => # +.#### => # +#.#.# => # +#.### => # +##.#. => # +##.## => # +###.. => # +###.# => # +####. => # + "; + let mut generation: Generation = input.parse().unwrap(); + let pots = generation.pots.clone(); + assert!(pots.get(&0).unwrap()); + assert!(pots.get(&3).unwrap()); + assert!(!pots.get(&4).unwrap()); + + let pots = generation.next().unwrap(); + assert!(pots.get(&0).unwrap()); + assert!(!pots.get(&3).unwrap()); + assert!(pots.get(&4).unwrap()); +} + +impl FromStr for Generation { + type Err = Box; + + fn from_str(s: &str) -> Result { + let mut lines = s.trim().lines(); + + let initial_state = lines.next().unwrap(); + let pots = Regex::new(r"[.#]+") + .ok() + .and_then(|re| re.find(initial_state)) + .unwrap() + .as_str() + .chars() + .enumerate() + .map(|(i, c)| (i as isize, c == '#')) + .collect(); + + lines.next(); // skip blank line + + let notes = lines + .map(|line| { + let mut note = line.split(" => "); + let key = note.next().unwrap(); + let value = note.next().unwrap() == "#"; + (key.into(), value) + }) + .collect(); + + Ok(Generation { pots, notes }) + } +}