summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2022-08-30 01:49:59 +0200
committerReiner Herrmann <reiner@reiner-h.de>2022-08-30 01:49:59 +0200
commit9f9f0d19ff42793533cd8823c06741ad7c1b9be6 (patch)
tree1f88a00a11863988e1fcdd007cc5b4d6f8f35b50 /src/bin
parent06773c99cb5a614a54d80482e4e5fdd59b010e54 (diff)
day7
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/day7.rs178
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);
+ }
+}