From: alex <> Date: Tue, 24 Dec 2024 09:23:41 +0000 (+0100) Subject: Day24 - part 1 X-Git-Url: https://aoc.elinar.fr/?a=commitdiff_plain;h=50fd427c436fcc1841a81b327add0e869cbe560a;p=aoc_2024 Day24 - part 1 --- diff --git a/src/day24.rs b/src/day24.rs new file mode 100644 index 0000000..7f8bf38 --- /dev/null +++ b/src/day24.rs @@ -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::().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> { + println!("Running {} - part 1", get_day()); + + let mut puzzle = Puzzle::new(input); + Ok(puzzle.solve()) +} + +fn run_part2(input: &str) -> Result> { + println!("Running {} - part 2", get_day()); + + Ok(0) +} + +pub fn run(input: &str) -> Result<(), Box> { + 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()); + } +} diff --git a/src/main.rs b/src/main.rs index 5bdf7bb..a7f650f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ pub mod day19; pub mod day20; pub mod day22; pub mod day23; +pub mod day24; fn main() { let args: Vec = env::args().collect(); @@ -70,6 +71,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box> { "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(())