summary refs log tree commit diff homepage
path: root/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/day09.rs68
1 files changed, 59 insertions, 9 deletions
diff --git a/src/bin/day09.rs b/src/bin/day09.rs
index 0c6ca98..f559b47 100644
--- a/src/bin/day09.rs
+++ b/src/bin/day09.rs
@@ -3,13 +3,15 @@ use std::io::{self, Read};
 enum Chunk<'a> {
     Literal(&'a str),
     Repeat(u32, &'a str),
+    Recursive(u32, Vec<Chunk<'a>>),
 }
 
 impl<'a> Chunk<'a> {
     fn len(&self) -> usize {
         match *self {
             Chunk::Literal(s) => s.len(),
-            Chunk::Repeat(n, s) => s.len() * n as usize,
+            Chunk::Repeat(n, s) => n as usize * s.len(),
+            Chunk::Recursive(n, ref cs) => n as usize * cs.iter().map(Chunk::len).sum::<usize>(),
         }
     }
 
@@ -27,6 +29,28 @@ impl<'a> Chunk<'a> {
             Ok((Chunk::Literal(&s[..paren]), &s[paren..]))
         }
     }
+
+    fn parse_v2(s: &'a str) -> Result<(Self, &'a str), ()> {
+        if s.starts_with('(') {
+            let mut iter = s[1..].splitn(3, |ch| ch == 'x' || ch == ')');
+
+            let len = iter.next().ok_or(())?.parse().map_err(|_| ())?;
+            let repeat = iter.next().ok_or(())?.parse().map_err(|_| ())?;
+            let (mut data, rest) = iter.next().ok_or(())?.split_at(len);
+
+            let mut chunks = Vec::new();
+            while !data.is_empty() {
+                let (chunk, data_rest) = Chunk::parse_v2(data)?;
+                chunks.push(chunk);
+                data = data_rest;
+            }
+
+            Ok((Chunk::Recursive(repeat, chunks), rest))
+        } else {
+            let paren = s.find('(').unwrap_or(s.len());
+            Ok((Chunk::Literal(&s[..paren]), &s[paren..]))
+        }
+    }
 }
 
 struct File<'a> {
@@ -49,26 +73,52 @@ impl<'a> File<'a> {
 
         Ok(File { chunks: chunks })
     }
+
+    fn parse_v2(mut s: &'a str) -> Result<Self, ()> {
+        let mut chunks = Vec::new();
+
+        while !s.is_empty() {
+            let (chunk, rest) = Chunk::parse_v2(s)?;
+            chunks.push(chunk);
+            s = rest;
+        }
+
+        Ok(File { chunks: chunks })
+    }
 }
 
-fn solve(input: &str) -> usize {
+fn solve1(input: &str) -> usize {
     let file = File::parse(input).unwrap();
     file.len()
 }
 
+fn solve2(input: &str) -> usize {
+    let file = File::parse_v2(input).unwrap();
+    file.len()
+}
+
 fn main() {
     let mut input = String::new();
     io::stdin().read_to_string(&mut input).unwrap();
 
-    println!("Part 1: {}", solve(&input));
+    println!("Part 1: {}", solve1(&input));
+    println!("Part 2: {}", solve2(&input));
 }
 
 #[test]
 fn part1() {
-    assert_eq!(6, solve("ADVENT"));
-    assert_eq!(7, solve("A(1x5)BC"));
-    assert_eq!(9, solve("(3x3)XYZ"));
-    assert_eq!(11, solve("A(2x2)BCD(2x2)EFG"));
-    assert_eq!(6, solve("(6x1)(1x3)A"));
-    assert_eq!(18, solve("X(8x2)(3x3)ABCY"));
+    assert_eq!(6, solve1("ADVENT"));
+    assert_eq!(7, solve1("A(1x5)BC"));
+    assert_eq!(9, solve1("(3x3)XYZ"));
+    assert_eq!(11, solve1("A(2x2)BCD(2x2)EFG"));
+    assert_eq!(6, solve1("(6x1)(1x3)A"));
+    assert_eq!(18, solve1("X(8x2)(3x3)ABCY"));
+}
+
+#[test]
+fn part2() {
+    assert_eq!(9, solve2("(3x3)XYZ"));
+    assert_eq!(20, solve2("X(8x2)(3x3)ABCY"));
+    assert_eq!(241920, solve2("(27x12)(20x12)(13x14)(7x10)(1x12)A"));
+    assert_eq!(445, solve2("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN"));
 }