use std::fs; fn decompress(input: &str, recurse: bool) -> String { let mut output = String::new(); let mut i = 0; let chars: Vec = 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); } }