--- /dev/null
+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]
+ )
+ }
+}
pub mod day04;
pub mod day05;
pub mod day06;
-// pub mod day07;
+pub mod day07;
// pub mod day08;
// pub mod day09;
// pub mod day10;
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()),