]> localhost Git - adventofcode2024.git/commitdiff
Complete day 7
authorJack Kinsey <j.jameskinsey@gmail.com>
Sat, 7 Dec 2024 21:41:50 +0000 (16:41 -0500)
committerJack Kinsey <j.jameskinsey@gmail.com>
Sat, 7 Dec 2024 21:41:50 +0000 (16:41 -0500)
src/day07.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day07.rs b/src/day07.rs
new file mode 100644 (file)
index 0000000..63cd0d4
--- /dev/null
@@ -0,0 +1,218 @@
+fn input() -> &'static str {
+    include_str!("../input/day07.txt")
+}
+
+fn parse(input: &str) -> Vec<(u64, Vec<u64>)> {
+    input
+        .split_terminator("\n")
+        .map(|l| {
+            let [lhs, rhs] = l.split(":").collect::<Vec<_>>()[..] else {
+                panic!()
+            };
+            (
+                lhs.parse().unwrap(),
+                rhs.split_whitespace().map(|n| n.parse().unwrap()).collect(),
+            )
+        })
+        .collect()
+}
+
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+enum Op {
+    Add,
+    Mul,
+    Cat,
+}
+
+#[derive(Debug, Eq, PartialEq, Clone)]
+struct OpString {
+    len: usize,
+    ops: Vec<Op>,
+    item: Vec<Op>,
+}
+
+impl OpString {
+    fn new(len: usize) -> Self {
+        OpString {
+            len,
+            ops: vec![Op::Add, Op::Mul],
+            item: vec![],
+        }
+    }
+
+    fn new_with_cat(len: usize) -> Self {
+        OpString {
+            len,
+            ops: vec![Op::Add, Op::Mul, Op::Cat],
+            item: vec![],
+        }
+    }
+}
+
+impl Iterator for OpString {
+    type Item = Vec<Op>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.item.is_empty() {
+            self.item = vec![self.ops[0]; self.len];
+            Some(self.item.clone())
+        } else if self.item.iter().all(|&o| o == self.ops[self.ops.len() - 1]) {
+            None
+        } else {
+            let mut carry = true;
+            let mut digit: usize = self.len;
+            let opn = self.ops.len() - 1;
+            while carry {
+                digit -= 1;
+                for (i, op) in self.ops.iter().enumerate() {
+                    if self.item[digit] == *op {
+                        if i == opn {
+                            self.item[digit] = self.ops[0];
+                        } else {
+                            self.item[digit] = self.ops[i + 1];
+                            carry = false;
+                        }
+                        break;
+                    }
+                }
+            }
+            Some(self.item.clone())
+        }
+    }
+}
+
+fn op_eval(num: &[u64], op: &[Op]) -> u64 {
+    num.iter()
+        .skip(1)
+        .zip(op.iter())
+        .fold(num[0], |a, (b, x)| match x {
+            Op::Add => a + b,
+            Op::Mul => a * b,
+            Op::Cat => a * 10u64.pow(b.ilog10() + 1) + b,
+        })
+}
+
+fn check_ops(&(lhs, rhs): &&(u64, Vec<u64>)) -> bool {
+    OpString::new(rhs.len()).any(|ops| *lhs == op_eval(rhs, &ops))
+}
+
+fn check_ops_with_cat(&(lhs, rhs): &&(u64, Vec<u64>)) -> bool {
+    OpString::new_with_cat(rhs.len()).any(|ops| *lhs == op_eval(rhs, &ops))
+}
+
+pub fn part1() {
+    let n: u64 = parse(input())
+        .iter()
+        .filter(check_ops)
+        .map(|&(lhs, _)| lhs)
+        .sum();
+    println!("Day 7 Part 1: {}", n);
+}
+
+pub fn part2() {
+    let n: u64 = parse(input())
+        .iter()
+        .filter(check_ops_with_cat)
+        .map(|&(lhs, _)| lhs)
+        .sum();
+    println!("Day 7 Part 2: {}", n);
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    const INPUT_STR: &str = concat!(
+        "190: 10 19\n",
+        "3267: 81 40 27\n",
+        "83: 17 5\n",
+        "156: 15 6\n",
+        "7290: 6 8 6 15\n",
+        "161011: 16 10 13\n",
+        "192: 17 8 14\n",
+        "21037: 9 7 18 13\n",
+        "292: 11 6 16 20\n",
+    );
+
+    #[test]
+    fn test_parse() {
+        assert_eq!(
+            parse(INPUT_STR),
+            [
+                (190, vec![10, 19]),
+                (3267, vec![81, 40, 27]),
+                (83, vec![17, 5]),
+                (156, vec![15, 6]),
+                (7290, vec![6, 8, 6, 15]),
+                (161011, vec![16, 10, 13]),
+                (192, vec![17, 8, 14]),
+                (21037, vec![9, 7, 18, 13]),
+                (292, vec![11, 6, 16, 20])
+            ]
+        )
+    }
+
+    #[test]
+    fn test_op_eval() {
+        assert_eq!(op_eval(&[1, 2, 3], &[Op::Add, Op::Mul]), 9)
+    }
+
+    #[test]
+    fn test_opstring() {
+        use Op::*;
+        assert_eq!(
+            OpString::new(2).collect::<Vec<_>>(),
+            [[Add, Add], [Add, Mul], [Mul, Add], [Mul, Mul]]
+        )
+    }
+
+    #[test]
+    fn test_opstring_with_cat() {
+        use Op::*;
+        assert_eq!(
+            OpString::new_with_cat(2).collect::<Vec<_>>(),
+            [
+                [Add, Add],
+                [Add, Mul],
+                [Add, Cat],
+                [Mul, Add],
+                [Mul, Mul],
+                [Mul, Cat],
+                [Cat, Add],
+                [Cat, Mul],
+                [Cat, Cat],
+            ]
+        )
+    }
+
+    #[test]
+    fn test_check_op_eval() {
+        assert_eq!(op_eval(&[1, 1], &[Op::Add]), 2);
+        assert_eq!(op_eval(&[1, 1], &[Op::Mul]), 1);
+        assert_eq!(op_eval(&[1, 1], &[Op::Cat]), 11);
+    }
+
+    #[test]
+    fn test_check_ops() {
+        assert_eq!(
+            parse(INPUT_STR)
+                .iter()
+                .filter(check_ops)
+                .map(|&(lhs, _)| lhs)
+                .collect::<Vec<_>>(),
+            [190, 3267, 292]
+        )
+    }
+
+    #[test]
+    fn test_check_ops_with_cat() {
+        assert_eq!(
+            parse(INPUT_STR)
+                .iter()
+                .filter(check_ops_with_cat)
+                .map(|&(lhs, _)| lhs)
+                .collect::<Vec<_>>(),
+            [190, 3267, 156, 7290, 192, 292]
+        )
+    }
+}
index b4be4178b3f85c459c4c156bba15694369dc0752..2b2032d26f20781a9b4f73ce4d054f0523ad806f 100644 (file)
@@ -4,7 +4,7 @@ pub mod day03;
 pub mod day04;
 pub mod day05;
 pub mod day06;
-// pub mod day07;
+pub mod day07;
 // pub mod day08;
 // pub mod day09;
 // pub mod day10;
@@ -26,14 +26,14 @@ pub mod day06;
 
 type Part = fn();
 
-const DAYS: [(Part, Part); 6] = [
+const DAYS: [(Part, Part); 7] = [
     (day01::part1 as fn(), day01::part2 as fn()),
     (day02::part1 as fn(), day02::part2 as fn()),
     (day03::part1 as fn(), day03::part2 as fn()),
     (day04::part1 as fn(), day04::part2 as fn()),
     (day05::part1 as fn(), day05::part2 as fn()),
     (day06::part1 as fn(), day06::part2 as fn()),
-    // (day07::part1 as fn(), day07::part2 as fn()),
+    (day07::part1 as fn(), day07::part2 as fn()),
     // (day08::part1 as fn(), day08::part2 as fn()),
     // (day09::part1 as fn(), day09::part2 as fn()),
     // (day10::part1 as fn(), day10::part2 as fn()),