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