Skip to main content

advent_of_code/year2016/
day09.rs

1use crate::input::Input;
2
3fn uncompressed_size(text: &[u8], recursive: bool) -> Result<u64, String> {
4    let error_mapper_uf8 = |_| "Invalid input";
5    let error_mapper_parse = |_| "Invalid input";
6    let mut start_parenthesis_idx = None;
7    let mut uncompressed_len = 0_u64;
8
9    let mut i = 0;
10    while i < text.len() {
11        let c = text[i];
12        if c == b'(' {
13            start_parenthesis_idx = Some(i);
14        } else if c == b')' {
15            if let Some(from) = start_parenthesis_idx {
16                let inside_parenthesis = &text[from + 1..i];
17                let parts = inside_parenthesis
18                    .split(|&c| c == b'x')
19                    .collect::<Vec<&[u8]>>();
20                if parts.len() != 2 {
21                    return Err("Invalid input".into());
22                }
23                let chars_to_take = std::str::from_utf8(parts[0])
24                    .map_err(error_mapper_uf8)?
25                    .parse::<u64>()
26                    .map_err(error_mapper_parse)?;
27                let repetitions = std::str::from_utf8(parts[1])
28                    .map_err(error_mapper_uf8)?
29                    .parse::<u64>()
30                    .map_err(error_mapper_parse)?;
31                uncompressed_len += repetitions
32                    * if recursive {
33                        uncompressed_size(&text[i + 1..i + 1 + chars_to_take as usize], true)?
34                    } else {
35                        chars_to_take
36                    };
37                i += chars_to_take as usize;
38                start_parenthesis_idx = None;
39            }
40        } else if start_parenthesis_idx.is_none() {
41            uncompressed_len += 1;
42        }
43        i += 1;
44    }
45
46    Ok(uncompressed_len)
47}
48
49pub fn solve(input: &Input) -> Result<u64, String> {
50    let text = input.text.as_bytes();
51    uncompressed_size(text, input.is_part_two())
52}
53
54#[test]
55pub fn tests() {
56    test_part_one!("ADVENT" => 6);
57    test_part_one!("A(1x5)BC" => 7);
58    test_part_one!("(3x3)XYZ" => 9);
59    test_part_one!("A(2x2)BCD(2x2)EFG" => 11);
60
61    test_part_two!("(3x3)XYZ" => 9);
62    test_part_two!("X(8x2)(3x3)ABCY" => 20);
63
64    let real_input = include_str!("day09_input.txt");
65    test_part_one!(real_input => 183_269);
66    test_part_two!(real_input => 11_317_278_863);
67}