use std::collections::HashMap; use regex::Regex; fn main() { let input = advent::read_lines(7); let mut circuit = Circuit::new(&input); let signal_a = circuit.lookup_signal("a"); println!("7a: {}", signal_a); let mut circuit = Circuit::new(&input); circuit.instructions.insert("b".to_string(), Operation::Direct(Signal::Raw(signal_a))); let signal_a = circuit.lookup_signal("a"); println!("7b: {}", signal_a); } #[derive(Clone)] enum Signal { Raw(u16), Wire(String), } impl Signal { fn new(input: &str) -> Signal { match input.parse::() { Ok(val) => Signal::Raw(val), Err(_) => Signal::Wire(input.to_string()), } } } #[derive(Clone)] enum Operation { And(Signal, Signal), Or(Signal, Signal), Lshift(Signal, u8), Rshift(Signal, u8), Not(Signal), Direct(Signal), } struct Circuit { instructions: HashMap, } impl Circuit { fn new>(input: &[T]) -> Circuit { let re_and = Regex::new(r"^([a-z0-9]+) AND ([a-z0-9]+) -> ([a-z0-9]+)").unwrap(); let re_or = Regex::new(r"^([a-z0-9]+) OR ([a-z0-9]+) -> ([a-z0-9]+)").unwrap(); let re_lshift = Regex::new(r"^([a-z0-9]+) LSHIFT ([0-9]+) -> ([a-z0-9]+)").unwrap(); let re_rshift = Regex::new(r"^([a-z0-9]+) RSHIFT ([0-9]+) -> ([a-z0-9]+)").unwrap(); let re_not = Regex::new(r"^NOT ([a-z0-9]+) -> ([a-z0-9]+)").unwrap(); let re_direct = Regex::new(r"^([a-z0-9]+) -> ([a-z0-9]+)").unwrap(); let mut instructions = HashMap::new(); for line in input { let (out, operation) = if let Some(cap) = re_and.captures(line.as_ref()) { let s1 = Signal::new(&cap[1]); let s2 = Signal::new(&cap[2]); let out = cap[3].to_string(); (out, Operation::And(s1, s2)) } else if let Some(cap) = re_or.captures(line.as_ref()) { let s1 = Signal::new(&cap[1]); let s2 = Signal::new(&cap[2]); let out = cap[3].to_string(); (out, Operation::Or(s1, s2)) } else if let Some(cap) = re_lshift.captures(line.as_ref()) { let s1 = Signal::new(&cap[1]); let val = cap[2].parse::().unwrap(); let out = cap[3].to_string(); (out, Operation::Lshift(s1, val)) } else if let Some(cap) = re_rshift.captures(line.as_ref()) { let s1 = Signal::new(&cap[1]); let val = cap[2].parse::().unwrap(); let out = cap[3].to_string(); (out, Operation::Rshift(s1, val)) } else if let Some(cap) = re_not.captures(line.as_ref()) { let s1 = Signal::new(&cap[1]); let out = cap[2].to_string(); (out, Operation::Not(s1)) } else if let Some(cap) = re_direct.captures(line.as_ref()) { let s1 = Signal::new(&cap[1]); let out = cap[2].to_string(); (out, Operation::Direct(s1)) } else { panic!("invalid instruction: {}", line.as_ref()); }; instructions.insert(out, operation); } Circuit { instructions } } fn lookup_signal(&mut self, wire: &str) -> u16 { let res = match self.instructions.get(wire).unwrap().clone() { Operation::Direct(s) => { match s { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), } }, Operation::And(s1, s2) => { let val1 = match s1 { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; let val2 = match s2 { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; val1 & val2 }, Operation::Or(s1, s2) => { let val1 = match s1 { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; let val2 = match s2 { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; val1 | val2 }, Operation::Lshift(s, amnt) => { let val = match s { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; val << amnt }, Operation::Rshift(s, amnt) => { let val = match s { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; val >> amnt }, Operation::Not(s) => { let val = match s { Signal::Raw(i) => i, Signal::Wire(w) => self.lookup_signal(&w), }; val ^ 0xffff }, }; self.instructions.insert(wire.to_string(), Operation::Direct(Signal::Raw(res))); res } } #[cfg(test)] mod tests { use super::*; #[test] fn test() { let input = [ "123 -> x", "456 -> y", "x AND y -> d", "x OR y -> e", "x LSHIFT 2 -> f", "y RSHIFT 2 -> g", "NOT x -> h", "NOT y -> i", ]; let mut circuit = Circuit::new(&input); assert_eq!(circuit.lookup_signal("d"), 72); assert_eq!(circuit.lookup_signal("e"), 507); assert_eq!(circuit.lookup_signal("f"), 492); assert_eq!(circuit.lookup_signal("g"), 114); assert_eq!(circuit.lookup_signal("h"), 65412); assert_eq!(circuit.lookup_signal("i"), 65079); assert_eq!(circuit.lookup_signal("x"), 123); assert_eq!(circuit.lookup_signal("y"), 456); } }