year2018/
day05.rs

1use utils::prelude::*;
2
3/// Reducing the input by removing matching letter pairs.
4#[derive(Clone, Debug)]
5pub struct Day05 {
6    reacted: Vec<u8>,
7}
8
9impl Day05 {
10    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
11        if let Some(index) = input.find(|c: char| !c.is_ascii_alphabetic()) {
12            return Err(InputError::new(input, index, "expected ascii letter"));
13        }
14        if input.is_empty() {
15            return Err(InputError::new(input, 0, "expected at least one letter"));
16        }
17
18        Ok(Self {
19            reacted: Self::react(input.bytes()),
20        })
21    }
22
23    #[must_use]
24    pub fn part1(&self) -> usize {
25        self.reacted.len()
26    }
27
28    #[must_use]
29    pub fn part2(&self) -> usize {
30        (b'a'..=b'z')
31            .map(|l| Self::react(self.reacted.iter().copied().filter(|&b| b | 32 != l)).len())
32            .min()
33            .unwrap()
34    }
35
36    fn react(polymer: impl Iterator<Item = u8>) -> Vec<u8> {
37        let mut stack = Vec::with_capacity(polymer.size_hint().1.unwrap_or(0));
38        for b in polymer {
39            if let Some(last) = stack.last()
40                && last ^ b == 32
41            {
42                stack.pop();
43                continue;
44            }
45            stack.push(b);
46        }
47        stack
48    }
49}
50
51examples!(Day05 -> (usize, usize) [
52    {input: "aA", part1: 0},
53    {input: "abBA", part1: 0},
54    {input: "abAB", part1: 4},
55    {input: "aabAAB", part1: 6},
56    {input: "dabAcCaCBAcCcaDA", part1: 10, part2: 4},
57]);