year2016/
day09.rs

1use utils::parser::ParseError;
2use utils::prelude::*;
3
4/// Calculating decompressed length.
5#[derive(Clone, Debug)]
6pub struct Day09 {
7    part1: u64,
8    part2: u64,
9}
10
11impl Day09 {
12    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13        Ok(Self {
14            part1: Self::decompressed_length(input.as_bytes(), false).map_with_input(input)?,
15            part2: Self::decompressed_length(input.as_bytes(), true).map_with_input(input)?,
16        })
17    }
18
19    fn decompressed_length(mut input: &[u8], recursive: bool) -> Result<u64, (ParseError, &[u8])> {
20        let mut len = 0;
21
22        while !input.is_empty() {
23            if input[0] == b'(' {
24                let (characters, repeats);
25                (characters, input) = parser::u32().parse(&input[1..])?;
26                (_, input) = b'x'.parse(input)?;
27                (repeats, input) = parser::u32().parse(input)?;
28                (_, input) = b')'.parse(input)?;
29
30                if input.len() < characters as usize {
31                    return Err((
32                        ParseError::Custom("insufficient characters after marker"),
33                        input,
34                    ));
35                }
36
37                let repeated_len = if recursive {
38                    Self::decompressed_length(&input[..characters as usize], true)?
39                } else {
40                    characters as u64
41                };
42
43                len += repeated_len * repeats as u64;
44                input = &input[characters as usize..];
45            } else {
46                len += 1;
47                input = &input[1..];
48            }
49        }
50
51        Ok(len)
52    }
53
54    #[must_use]
55    pub fn part1(&self) -> u64 {
56        self.part1
57    }
58
59    #[must_use]
60    pub fn part2(&self) -> u64 {
61        self.part2
62    }
63}
64
65examples!(Day09 -> (u64, u64) [
66    {input: "ADVENT", part1: 6},
67    {input: "A(1x5)BC", part1: 7},
68    {input: "(3x3)XYZ", part1: 9, part2: 9},
69    {input: "A(2x2)BCD(2x2)EFG", part1: 11},
70    {input: "(6x1)(1x3)A", part1: 6},
71    {input: "X(8x2)(3x3)ABCY", part1: 18, part2: 20},
72    {input: "(27x12)(20x12)(13x14)(7x10)(1x12)A", part2: 241920},
73    {input: "(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN", part2: 445},
74]);