From 3b877bf4cc667eb8bcc787d145203600a4dba2d2 Mon Sep 17 00:00:00 2001
From: Prefetch
Date: Sat, 25 Feb 2023 11:41:27 +0100
Subject: Initial commit

---
 d09/src/main.rs | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)
 create mode 100644 d09/src/main.rs

(limited to 'd09/src')

diff --git a/d09/src/main.rs b/d09/src/main.rs
new file mode 100644
index 0000000..7b24487
--- /dev/null
+++ b/d09/src/main.rs
@@ -0,0 +1,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);
+    }
+}
-- 
cgit v1.2.3