1use utils::prelude::*;
2
3#[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]);