From 6efeba31118533d95645f5e8be21af58960e1708 Mon Sep 17 00:00:00 2001 From: Adrian Groh Date: Tue, 24 Dec 2024 10:42:36 +0100 Subject: [PATCH] Add day24 part1 --- day24/Cargo.lock | 7 ++++ day24/Cargo.toml | 6 +++ day24/src/main.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 day24/Cargo.lock create mode 100644 day24/Cargo.toml create mode 100644 day24/src/main.rs diff --git a/day24/Cargo.lock b/day24/Cargo.lock new file mode 100644 index 0000000..6d2ef2f --- /dev/null +++ b/day24/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "day24" +version = "0.1.0" diff --git a/day24/Cargo.toml b/day24/Cargo.toml new file mode 100644 index 0000000..ddaaf58 --- /dev/null +++ b/day24/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day24" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/day24/src/main.rs b/day24/src/main.rs new file mode 100644 index 0000000..4827763 --- /dev/null +++ b/day24/src/main.rs @@ -0,0 +1,105 @@ +use std::{cmp::Reverse, collections::HashMap}; + +#[derive(Debug, Clone, Eq, PartialEq)] +enum Gate { + InputGate(bool), + CalcGate(CalcGate), +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +enum Operation { + And, + Or, + Xor, +} + +impl From<&str> for Operation { + fn from(value: &str) -> Self { + match value { + "AND" => Self::And, + "OR" => Self::Or, + "XOR" => Self::Xor, + _ => panic!(), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +struct CalcGate { + operation: Operation, + lhs: String, + rhs: String, +} + +fn parse(input: &str) -> HashMap { + let mut res = HashMap::new(); + let (inputs, calcs) = input.split_once("\n\n").unwrap(); + res.extend(inputs.lines().map(|l| { + let (name, val) = l.split_once(": ").unwrap(); + (name.to_string(), Gate::InputGate(val == "1")) + })); + res.extend(calcs.lines().map(|l| { + let mut iter = l.split(' '); + let lhs = iter.next().unwrap(); + let op = iter.next().unwrap(); + let rhs = iter.next().unwrap(); + let name = iter.nth(1).unwrap(); + ( + name.to_string(), + Gate::CalcGate(CalcGate { + operation: Operation::from(op), + lhs: lhs.to_string(), + rhs: rhs.to_string(), + }), + ) + })); + res +} + +fn get_gate_value( + gate: &str, + gates: &HashMap, + cache: &mut HashMap, +) -> bool { + if let Some(v) = cache.get(gate) { + return *v; + } + let res = match gates.get(gate).unwrap() { + Gate::InputGate(val) => *val, + Gate::CalcGate(calc_gate) => match calc_gate.operation { + Operation::And => { + get_gate_value(&calc_gate.lhs, gates, cache) + & get_gate_value(&calc_gate.rhs, gates, cache) + } + Operation::Or => { + get_gate_value(&calc_gate.lhs, gates, cache) + | get_gate_value(&calc_gate.rhs, gates, cache) + } + Operation::Xor => { + get_gate_value(&calc_gate.lhs, gates, cache) + ^ get_gate_value(&calc_gate.rhs, gates, cache) + } + }, + }; + cache.insert(gate.to_string(), res); + res +} + +fn part1(gates: &HashMap) -> usize { + let mut output_bits: Vec<_> = gates.keys().filter(|g| g.starts_with("z")).collect(); + let mut cache = HashMap::new(); + output_bits.sort_unstable_by_key(|v| Reverse(v.to_string())); + let mut res: usize = 0; + for bit in output_bits { + res <<= 1; + if get_gate_value(bit, gates, &mut cache) { + res += 1; + } + } + res +} + +fn main() { + let input = parse(include_str!("../input.txt")); + println!("{}", part1(&input)); +}