]> aoc.elinar.fr Git - aoc_2024/commitdiff
Day24 - part 1
authoralex <>
Tue, 24 Dec 2024 09:23:41 +0000 (10:23 +0100)
committeralex <>
Tue, 24 Dec 2024 09:23:41 +0000 (10:23 +0100)
src/day24.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day24.rs b/src/day24.rs
new file mode 100644 (file)
index 0000000..7f8bf38
--- /dev/null
@@ -0,0 +1,196 @@
+use std::error::Error;
+use std::path::Path;
+use std::collections::HashMap;
+
+#[derive(Copy, Clone, Debug)]
+struct Gate<'a> {
+    in1: &'a str,
+    in2: &'a str,
+    op: &'a str,
+}
+
+impl<'a> Gate<'a> {
+    pub fn new(in1: &'a str, in2: &'a str, op: &'a str) -> Self {
+        Self { in1, in2, op }
+    }
+
+    fn solve(&self, wires: &HashMap<&str, u8>) -> u8 {
+        if !wires.contains_key(&self.in1) && !wires.contains_key(&self.in2) {
+            unreachable!();
+        }
+        let w1 = wires.get(&self.in1).unwrap();
+        let w2 = wires.get(&self.in2).unwrap();
+        match self.op {
+            "AND" => w1 & w2,
+            "OR" => w1 | w2,
+            "XOR" => w1 ^ w2,
+            _ => unreachable!()
+        }
+    }
+}
+
+struct Puzzle<'a> {
+    wires: HashMap<&'a str, u8>,
+    gates: HashMap<&'a str, Gate<'a>>,
+}
+
+impl<'a> Puzzle<'a> {
+    pub fn new(input: &'a str) -> Self {
+        let (wires, gates) = input.split_once("\n\n").unwrap();
+        let wires = wires.lines()
+            .map(|l| (&l[0..3], l[l.len()-1..].parse::<u8>().unwrap()))
+            .collect();
+        let gates = gates.lines()
+            .map(|l| {
+                let mut it = l.split_ascii_whitespace();
+                let in1 = it.next().unwrap();
+                let op = it.next().unwrap();
+                let in2 = it.next().unwrap();
+                it.next();
+                let res = it.next().unwrap();
+                (res, Gate::new(in1, in2, op))
+            })
+            .collect();
+        Self { wires, gates }
+    }
+
+    fn solve_gate(&mut self, out: &'a str) {
+        match self.wires.get(out) {
+            None => {
+                let g = *self.gates.get(out).unwrap();
+                match self.wires.get(g.in1) {
+                    None => self.solve_gate(g.in1),
+                    _ => {}
+                }
+                match self.wires.get(g.in2) {
+                    None => self.solve_gate(g.in2),
+                    _ => {},
+                }
+                let res = g.solve(&self.wires);
+                self.wires.insert(out, res);
+            },
+            _ => {}
+        }
+    }
+
+    fn solve(&mut self) -> u64 {
+        let mut z_gates: Vec<&str> = self.gates.keys()
+            .filter(|k| k.starts_with("z"))
+            .map(|k| *k)
+            .collect();
+        z_gates.sort_by(|a, b| a.cmp(&b));
+        z_gates.iter().for_each(|k| { self.solve_gate(k); });
+        let res = z_gates.iter().enumerate()
+            .map(|(i, z_gate)| {
+                let z = *self.wires.get(z_gate).unwrap();
+                let z = z as u64;
+                z << i
+            })
+            .sum();
+        res
+    }
+}
+
+fn run_part1(input: &str) -> Result<u64, Box<dyn Error>> {
+    println!("Running {} - part 1", get_day());
+
+    let mut puzzle = Puzzle::new(input);
+    Ok(puzzle.solve())
+}
+
+fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
+    println!("Running {} - part 2", get_day());
+
+    Ok(0)
+}
+
+pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
+    let res = run_part1(input)?;
+    println!("{res}");
+
+    let res = run_part2(input)?;
+    println!("{res}");
+
+    Ok(())
+}
+
+fn get_day() -> String {
+    let filename = file!();
+    Path::new(filename).file_stem().unwrap().to_str().unwrap().to_string()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    static TEXT_INPUT_0: &str = "\
+x00: 1
+x01: 1
+x02: 1
+y00: 0
+y01: 1
+y02: 0
+
+x00 AND y00 -> z00
+x01 XOR y01 -> z01
+x02 OR y02 -> z02";
+    static TEXT_INPUT: &str = "\
+x00: 1
+x01: 0
+x02: 1
+x03: 1
+x04: 0
+y00: 1
+y01: 1
+y02: 1
+y03: 1
+y04: 1
+
+ntg XOR fgs -> mjb
+y02 OR x01 -> tnw
+kwq OR kpj -> z05
+x00 OR x03 -> fst
+tgd XOR rvg -> z01
+vdt OR tnw -> bfw
+bfw AND frj -> z10
+ffh OR nrd -> bqk
+y00 AND y03 -> djm
+y03 OR y00 -> psh
+bqk OR frj -> z08
+tnw OR fst -> frj
+gnj AND tgd -> z11
+bfw XOR mjb -> z00
+x03 OR x00 -> vdt
+gnj AND wpb -> z02
+x04 AND y00 -> kjc
+djm OR pbm -> qhw
+nrd AND vdt -> hwm
+kjc AND fst -> rvg
+y04 OR y02 -> fgs
+y01 AND x02 -> pbm
+ntg OR kjc -> kwq
+psh XOR fgs -> tgd
+qhw XOR tgd -> z09
+pbm OR djm -> kpj
+x03 XOR y03 -> ffh
+x00 XOR y04 -> ntg
+bfw OR bqk -> z06
+nrd XOR fgs -> wpb
+frj XOR qhw -> z04
+bqk OR frj -> z07
+y03 OR x01 -> nrd
+hwm AND bqk -> z03
+tgd XOR rvg -> z12
+tnw OR pbm -> gnj";
+
+    #[test]
+    fn test_part1() {
+        assert_eq!(4, run_part1(TEXT_INPUT_0).unwrap());
+        assert_eq!(2024, run_part1(TEXT_INPUT).unwrap());
+    }
+
+    #[test]
+    fn test_part2() {
+        assert_eq!(0, run_part2(TEXT_INPUT).unwrap());
+    }
+}
index 5bdf7bb6d5bc581016e6822a56a6d887a3472789..a7f650f76133d79a4ebe5bc835f3fbe20e11cebd 100644 (file)
@@ -26,6 +26,7 @@ pub mod day19;
 pub mod day20;
 pub mod day22;
 pub mod day23;
+pub mod day24;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -70,6 +71,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "day20" => day20::run(&input)?,
         "day22" => day22::run(&input)?,
         "day23" => day23::run(&input)?,
+        "day24" => day24::run(&input)?,
         _ => return Err(format!("unknown or unimplemented day \"{day}\"").into()),
     }
     Ok(())