diff --git a/.aoc_tiles/tiles/2024/24.png b/.aoc_tiles/tiles/2024/24.png
index cdc4ce2..89f755a 100644
Binary files a/.aoc_tiles/tiles/2024/24.png and b/.aoc_tiles/tiles/2024/24.png differ
diff --git a/README.md b/README.md
index c3d691c..bd4c125 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
- 2024 - 45 ⭐ - Rust
+ 2024 - 46 ⭐ - Rust
@@ -71,4 +71,7 @@
+
+
+
diff --git a/src/day24.rs b/src/day24.rs
new file mode 100644
index 0000000..3789464
--- /dev/null
+++ b/src/day24.rs
@@ -0,0 +1,229 @@
+use aoc_runner_derive::aoc;
+use itertools::Itertools;
+use nom::And;
+use regex::Regex;
+use rustc_hash::FxHashMap;
+
+#[derive(Copy, Clone, Debug)]
+enum Op {
+ And,
+ Or,
+ Xor,
+ Constant,
+}
+
+impl From<&str> for Op {
+ fn from(value: &str) -> Self {
+ match value {
+ "AND" => Self::And,
+ "OR" => Self::Or,
+ "XOR" => Self::Xor,
+ s => panic!("invalid operation {}", s),
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+struct Gate {
+ op: Op,
+ value: Option,
+ arguments: [String; 2],
+}
+
+impl Gate {
+ fn eval(&self, machine: &GateMachine) -> bool {
+ match self.op {
+ Op::And => machine.val_of(&self.arguments[0]) && machine.val_of(&self.arguments[1]),
+ Op::Or => machine.val_of(&self.arguments[0]) || machine.val_of(&self.arguments[1]),
+ Op::Xor => machine.val_of(&self.arguments[0]) ^ machine.val_of(&self.arguments[1]),
+ Op::Constant => self.value.unwrap(),
+ }
+ }
+}
+
+#[derive(Debug)]
+struct GateMachine {
+ gates: FxHashMap,
+}
+
+impl GateMachine {
+ fn val_of(&self, gate: &str) -> bool {
+ println!("gate: {}", gate);
+ if let Some(val) = self.gates[gate].value {
+ val
+ } else {
+ self.gates[gate].eval(self)
+ }
+ }
+}
+
+fn parse(input: &str) -> GateMachine {
+ let mut gates = FxHashMap::default();
+ for line in input.lines() {
+ println!("{line}");
+ let const_re = Regex::new(r"^([xyz][0-9]{2}): ([01])$").unwrap();
+ let gate_re = Regex::new(r"^([a-z0-9]{3}) (AND|XOR|OR) ([a-z0-9]{3}) -> ([a-z0-9]{3})$").unwrap();
+
+ if let Some(caps) = const_re.captures(line) {
+ println!(" is const: {:?}", caps);
+ gates.insert(
+ caps[1].to_string(),
+ Gate {
+ op: Op::Constant,
+ value: if &caps[2] == "1" { Some(true) } else { Some(false) },
+ arguments: [String::new(), String::new()],
+ },
+ );
+ } else if let Some(caps) = gate_re.captures(line) {
+ println!(" is gate: {:?}", caps);
+ gates.insert(
+ caps[4].to_string(),
+ Gate {
+ op: Op::from(&caps[2]),
+ value: None,
+ arguments: [caps[1].to_string(), caps[3].to_string()],
+ },
+ );
+ }
+ }
+ GateMachine { gates }
+}
+
+#[aoc(day24, part1)]
+pub fn part1(input: &str) -> i64 {
+ let machine = parse(input);
+ let z_gates = machine
+ .gates
+ .keys()
+ .filter(|k| k.starts_with('z'))
+ .map(|s| (s, s.split_at(1).1.parse::().unwrap()));
+ let bit_vals = z_gates
+ .map(|(name, bit)| if machine.val_of(name) { 1 << bit } else { 0 })
+ .fold(0, |accum, val| accum | val);
+ bit_vals
+}
+
+#[aoc(day24, part2)]
+pub fn part2(input: &str) -> i64 {
+ 0
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ const EXAMPLE1: &str = "x00: 1
+x01: 1
+x02: 1
+y00: 0
+y01: 1
+y02: 0
+
+x00 AND y00 -> z00
+x01 XOR y01 -> z01x00: 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
+x02 OR y02 -> z02";
+
+ const EXAMPLE2: &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 part1_example() {
+ assert_eq!(part1(EXAMPLE1), 4);
+ assert_eq!(part1(EXAMPLE2), 2024);
+ }
+
+ #[test]
+ fn part2_example() {
+ assert_eq!(part2(EXAMPLE1), 0);
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 6adecb4..6cfecaf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,6 +14,7 @@ pub mod day20;
pub mod day21;
pub mod day22;
pub mod day23;
+pub mod day24;
pub mod day3;
pub mod day4;
pub mod day5;