diff --git a/README.md b/README.md index 7166d99..1255601 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 4](./src/bin/04.rs) | `81.9µs` | `51.3µs` | | [Day 5](./src/bin/05.rs) | `379.0µs` | `816.9µs` | | [Day 6](./src/bin/06.rs) | `331.5µs` | `311.0ms` | +| [Day 7](./src/bin/07.rs) | `900.4µs` | `2.8ms` | -**Total: 313.35ms** +**Total: 317.05ms** diff --git a/data/examples/07.txt b/data/examples/07.txt new file mode 100644 index 0000000..fc6e099 --- /dev/null +++ b/data/examples/07.txt @@ -0,0 +1,9 @@ +190: 10 19 +3267: 81 40 27 +83: 17 5 +156: 15 6 +7290: 6 8 6 15 +161011: 16 10 13 +192: 17 8 14 +21037: 9 7 18 13 +292: 11 6 16 20 diff --git a/src/bin/06.rs b/src/bin/06.rs index 1548009..4e85f66 100644 --- a/src/bin/06.rs +++ b/src/bin/06.rs @@ -278,6 +278,6 @@ mod tests { #[test] fn test_part_two() { let result = part_two(&advent_of_code::template::read_file("examples", DAY)); - assert_eq!(result, None); + assert_eq!(result, Some(6)); } } diff --git a/src/bin/07.rs b/src/bin/07.rs new file mode 100644 index 0000000..3fac213 --- /dev/null +++ b/src/bin/07.rs @@ -0,0 +1,227 @@ +use std::collections::{HashSet, VecDeque}; + +use itertools::Itertools; + +advent_of_code::solution!(7); + +#[derive(Debug, Eq, Hash, PartialEq, Clone)] +struct Equation { + target: i64, + numbers: Vec, +} + +pub fn part_one(input: &str) -> Option { + let equations = input + .lines() + .map(|line| { + let (target_str, numbers_str) = line.split_once(": ").unwrap(); + let numbers: Vec = numbers_str + .split(" ") + .map(|num_str| num_str.parse().unwrap()) + .collect_vec(); + Equation { + numbers, + target: target_str.parse().unwrap(), + } + }) + .collect_vec(); + + let result: i64 = equations.into_iter().fold(0, |acc, eq| { + if solve_equation(&eq).is_some() { + acc + eq.target + } else { + acc + } + }); + + Some(result) +} + +fn solve_equation(equation: &Equation) -> Option>> { + let mut solutions = HashSet::new(); + if equation.numbers.len() == 2 { + if equation.numbers[0] + equation.numbers[1] == equation.target { + solutions.insert(vec!['+'].into()); + }; + + if equation.numbers[0] * equation.numbers[1] == equation.target { + solutions.insert(vec!['*'].into()); + }; + + return if solutions.is_empty() { + None + } else { + Some(solutions) + }; + } + + let mut numbers_clone = equation.numbers.clone(); + let last = numbers_clone.pop().unwrap(); + + if last < equation.target { + let add_eq_target = equation.target - last; + let add_smaller_eq = Equation { + target: add_eq_target, + numbers: numbers_clone.clone(), + }; + let add_smaller_solutions = solve_equation(&add_smaller_eq); + if let Some(sols) = add_smaller_solutions { + for sol in sols { + let mut new_sol = sol.clone(); + new_sol.push_back('+'); + solutions.insert(new_sol); + } + } + } + + if equation.target % last == 0 { + let mult_eq_target = equation.target / last; + let mult_smaller_eq = Equation { + target: mult_eq_target, + numbers: numbers_clone.clone(), + }; + let mult_smaller_solutions = solve_equation(&mult_smaller_eq); + if let Some(sols) = mult_smaller_solutions { + for sol in sols { + let mut new_sol = sol.clone(); + new_sol.push_back('*'); + solutions.insert(new_sol); + } + }; + } + + if solutions.is_empty() { + None + } else { + Some(solutions) + } +} + +pub fn part_two(input: &str) -> Option { + let equations = input + .lines() + .map(|line| { + let (target_str, numbers_str) = line.split_once(": ").unwrap(); + let numbers: Vec = numbers_str + .split(" ") + .map(|num_str| num_str.parse().unwrap()) + .collect_vec(); + Equation { + numbers, + target: target_str.parse().unwrap(), + } + }) + .collect_vec(); + + let result: i64 = equations.into_iter().fold(0, |acc, eq| { + if solve_equation_2(&eq).is_some() { + acc + eq.target + } else { + acc + } + }); + + Some(result) +} + +fn solve_equation_2(equation: &Equation) -> Option>> { + let mut solutions = HashSet::new(); + if equation.numbers.len() == 2 { + if equation.numbers[0] + equation.numbers[1] == equation.target { + solutions.insert(vec!['+'].into()); + }; + + if equation.numbers[0] * equation.numbers[1] == equation.target { + solutions.insert(vec!['*'].into()); + }; + + let concat = format!("{}{}", equation.numbers[0], equation.numbers[1]) + .parse::() + .unwrap(); + if concat == equation.target { + solutions.insert(vec!['|'].into()); + }; + + return if solutions.is_empty() { + None + } else { + Some(solutions) + }; + } + + let mut numbers_clone = equation.numbers.clone(); + let last = numbers_clone.pop().unwrap(); + + if last < equation.target { + let add_eq_target = equation.target - last; + let add_smaller_eq = Equation { + target: add_eq_target, + numbers: numbers_clone.clone(), + }; + let add_smaller_solutions = solve_equation_2(&add_smaller_eq); + if let Some(sols) = add_smaller_solutions { + for sol in sols { + let mut new_sol = sol.clone(); + new_sol.push_back('+'); + solutions.insert(new_sol); + } + } + }; + + if equation.target % last == 0 { + let mult_eq_target = equation.target / last; + let mult_smaller_eq = Equation { + target: mult_eq_target, + numbers: numbers_clone.clone(), + }; + let mult_smaller_solutions = solve_equation_2(&mult_smaller_eq); + if let Some(sols) = mult_smaller_solutions { + for sol in sols { + let mut new_sol = sol.clone(); + new_sol.push_back('*'); + solutions.insert(new_sol); + } + }; + }; + + let target_as_str = equation.target.to_string(); + if target_as_str.ends_with(&last.to_string()) { + let new_target = &target_as_str[..target_as_str.len() - last.to_string().len()]; + if !new_target.is_empty() { + let concat_smaller_eq = Equation { + target: new_target.parse().unwrap(), + numbers: numbers_clone.clone(), + }; + let concat_smaller_solutions = solve_equation_2(&concat_smaller_eq); + if let Some(sols) = concat_smaller_solutions { + for sol in sols { + let mut new_sol = sol.clone(); + new_sol.push_back('|'); + solutions.insert(new_sol); + } + }; + }; + }; + if solutions.is_empty() { + None + } else { + Some(solutions) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(3749)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, None); + } +}