diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/day7.rs | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/bin/day7.rs b/src/bin/day7.rs new file mode 100644 index 0000000..3bc4a81 --- /dev/null +++ b/src/bin/day7.rs @@ -0,0 +1,178 @@ +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::<u16>() { + 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<String, Operation>, +} + +impl Circuit { + fn new<T: AsRef<str>>(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::<u8>().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::<u8>().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); + } +} |
