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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
use std::fs;
fn decompress(input: &str, recurse: bool) -> String {
let mut output = String::new();
let mut i = 0;
let chars: Vec<char> = input.chars().collect();
while i < chars.len() {
// If we find a compression marker "(LENGTHxREPETITIONS)"
if chars[i] == '(' {
i += 1;
let mut marker = String::new();
while chars[i] != ')' {
marker.push(chars[i]);
i += 1;
}
i += 1; // i -> first char after ')'
// Read info from the compression marker...
let parsed: Vec<&str> = marker.split('x').collect();
let len: usize = parsed[0].parse().unwrap();
let rep: usize = parsed[1].parse().unwrap();
// ... and decompress the next `len' characters accordingly
let replacement = if recurse {
// Part 2: markers within decompressed data are also handled
decompress(&input[i..i + len], true)
} else {
// Part 1: markers within decompressed data are ignored
String::from(&input[i..i + len])
};
for _n in 0..rep {
output.push_str(&replacement);
}
i += len;
} else {
// This part isn't compressed, copy it verbatim
output.push(chars[i]);
i += 1;
}
}
output
}
fn main() {
// Read my initial data from input text file
let input = fs::read_to_string("input.txt").unwrap();
let compr = input.trim_end();
// Part 1 gives 110346 for me
println!("Part 1 solution: {}", decompress(compr, false).len());
// Part 2 gives 10774309173 for me. Watch that RAM!
println!("Part 2 solution: {}", decompress(compr, true).len());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example1() {
let input = "ADVENT";
assert_eq!(decompress(input, false).len(), 6);
}
#[test]
fn part1_example2() {
let input = "A(1x5)BC";
assert_eq!(decompress(input, false).len(), 7);
}
#[test]
fn part1_example3() {
let input = "(3x3)XYZ";
assert_eq!(decompress(input, false).len(), 9);
}
#[test]
fn part1_example4() {
let input = "A(2x2)BCD(2x2)EFG";
assert_eq!(decompress(input, false).len(), 11);
}
#[test]
fn part1_example5() {
let input = "(6x1)(1x3)A";
assert_eq!(decompress(input, false).len(), 6);
}
#[test]
fn part1_example6() {
let input = "X(8x2)(3x3)ABCY";
assert_eq!(decompress(input, false).len(), 18);
}
#[test]
fn part2_example1() {
let input = "(3x3)XYZ";
assert_eq!(decompress(input, true).len(), 9);
}
#[test]
fn part2_example2() {
let input = "X(8x2)(3x3)ABCY";
assert_eq!(decompress(input, true).len(), 20);
}
#[test]
fn part2_example3() {
let input = "(27x12)(20x12)(13x14)(7x10)(1x12)A";
assert_eq!(decompress(input, true).len(), 241920);
}
#[test]
fn part2_example4() {
let input = "(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN";
assert_eq!(decompress(input, true).len(), 445);
}
}
|