summaryrefslogtreecommitdiff
path: root/2024_rust/src
diff options
context:
space:
mode:
Diffstat (limited to '2024_rust/src')
-rw-r--r--2024_rust/src/bin/day7.rs129
1 files changed, 129 insertions, 0 deletions
diff --git a/2024_rust/src/bin/day7.rs b/2024_rust/src/bin/day7.rs
new file mode 100644
index 0000000..d81ad1e
--- /dev/null
+++ b/2024_rust/src/bin/day7.rs
@@ -0,0 +1,129 @@
+use itertools::Itertools;
+use regex::Regex;
+use std::fmt;
+
+struct Operator {
+ name: char,
+ f: Box<dyn Fn(u64, u64) -> u64>,
+}
+
+impl fmt::Display for Operator {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.name)
+ }
+}
+
+#[allow(dead_code)]
+fn op_chain_to_string(chain: &Vec<&Operator>) -> String {
+ format!("[{}]", chain.iter().map(|o| o.to_string()).join(", "))
+}
+
+#[derive(Debug)]
+struct Equation {
+ result: u64,
+ values: Vec<u64>,
+}
+
+impl Equation {
+ fn parse(s: &str) -> Self {
+ let re = Regex::new("^([0-9]+): ((?:[0-9]+ ?)+)$").unwrap();
+ let caps = re.captures(s).unwrap();
+ let (_full, [result, values]) = caps.extract();
+ Equation {
+ result: result.parse().unwrap(),
+ values: values.split(' ').map(|n| n.parse().unwrap()).collect(),
+ }
+ }
+
+ fn is_solution(&self, chain: &Vec<&Operator>) -> bool {
+ let mut chain_it = chain.iter();
+ let mut self_it = self.values.iter();
+ let mut acc: u64 = *self_it.next().unwrap();
+ for value in self_it {
+ let Some(op) = chain_it.next() else {
+ panic!("Impossible")
+ };
+ acc = (op.f)(acc, *value);
+ if acc > self.result {
+ return false;
+ }
+ }
+ // // TODO why does this not work?
+ // self.values.iter()
+ // .reduce(|v1, v2| {
+ // let Some(op) = chain_it.next() else { panic!("Impossible") };
+ // (op.f)(v1, v2)
+ // });
+ acc == self.result
+ }
+
+ fn find_solution<'a>(&self, ops: &'a [Operator]) -> Option<Vec<&'a Operator>> {
+ // println!("Finding solution for {self:?}...");
+ let op_chains = itertools::repeat_n(ops, self.values.len() - 1).multi_cartesian_product();
+ for chain in op_chains {
+ // print!(" Trying chain {}... ", op_chain_to_string(&chain));
+ if self.is_solution(&chain) {
+ // println!("YES!");
+ return Some(chain.clone());
+ }
+ // println!("nope");
+ }
+ None
+ }
+
+ fn has_solution(&self, ops: &[Operator]) -> bool {
+ self.find_solution(ops).is_some()
+ }
+}
+
+fn sum_solutions(input: &str, ops: &[Operator]) -> u64 {
+ let equations: Vec<Equation> = input.lines().map(|l| Equation::parse(l)).collect();
+ // println!("Equations: {equations:?}");
+ equations
+ .iter()
+ .filter(|e| e.has_solution(&ops))
+ .map(|e| e.result)
+ .sum()
+}
+
+fn p1(input: &str) -> String {
+ let ops: [Operator; 2] = [
+ Operator {
+ name: '+',
+ f: Box::new(|x, y| x + y),
+ },
+ Operator {
+ name: '*',
+ f: Box::new(|x, y| x * y),
+ },
+ ];
+
+ sum_solutions(input, &ops).to_string()
+}
+
+fn p2(input: &str) -> String {
+ let ops: [Operator; 3] = [
+ Operator {
+ name: '+',
+ f: Box::new(|x, y| x + y),
+ },
+ Operator {
+ name: '*',
+ f: Box::new(|x, y| x * y),
+ },
+ Operator {
+ name: '|',
+ f: Box::new(|x, y| {
+ format!("{}{}", x.to_string(), y.to_string())
+ .parse()
+ .unwrap()
+ }),
+ },
+ ];
+
+ sum_solutions(input, &ops).to_string()
+}
+
+fn main() {
+ aoc2024::run_day("7", p1, p2);
+}