day20: problem 1 solution
This commit is contained in:
		
							
								
								
									
										118
									
								
								20/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								20/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					# This file is automatically @generated by Cargo.
 | 
				
			||||||
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
 | 
					version = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "aho-corasick"
 | 
				
			||||||
 | 
					version = "1.1.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "day20"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "lazy-regex",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "lazy-regex"
 | 
				
			||||||
 | 
					version = "3.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "lazy-regex-proc_macros",
 | 
				
			||||||
 | 
					 "once_cell",
 | 
				
			||||||
 | 
					 "regex",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "lazy-regex-proc_macros"
 | 
				
			||||||
 | 
					version = "3.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "regex",
 | 
				
			||||||
 | 
					 "syn",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "memchr"
 | 
				
			||||||
 | 
					version = "2.6.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "once_cell"
 | 
				
			||||||
 | 
					version = "1.19.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "proc-macro2"
 | 
				
			||||||
 | 
					version = "1.0.70"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "unicode-ident",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "quote"
 | 
				
			||||||
 | 
					version = "1.0.33"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "regex"
 | 
				
			||||||
 | 
					version = "1.10.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "aho-corasick",
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					 "regex-automata",
 | 
				
			||||||
 | 
					 "regex-syntax",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "regex-automata"
 | 
				
			||||||
 | 
					version = "0.4.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "aho-corasick",
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					 "regex-syntax",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "regex-syntax"
 | 
				
			||||||
 | 
					version = "0.8.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "syn"
 | 
				
			||||||
 | 
					version = "2.0.41"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "unicode-ident",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "unicode-ident"
 | 
				
			||||||
 | 
					version = "1.0.12"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 | 
				
			||||||
							
								
								
									
										9
									
								
								20/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								20/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "day20"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					lazy-regex = "3.1.0"
 | 
				
			||||||
							
								
								
									
										58
									
								
								20/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								20/input
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					%hm -> cr
 | 
				
			||||||
 | 
					%qc -> nd
 | 
				
			||||||
 | 
					&dh -> rm
 | 
				
			||||||
 | 
					%ph -> zz
 | 
				
			||||||
 | 
					%ps -> kc, dt
 | 
				
			||||||
 | 
					%qb -> dt
 | 
				
			||||||
 | 
					%jl -> vt, tb
 | 
				
			||||||
 | 
					%fh -> dm, gr
 | 
				
			||||||
 | 
					broadcaster -> np, mg, vd, xr
 | 
				
			||||||
 | 
					%zz -> sq
 | 
				
			||||||
 | 
					&rm -> rx
 | 
				
			||||||
 | 
					%nd -> br
 | 
				
			||||||
 | 
					%nx -> vr, vt
 | 
				
			||||||
 | 
					%qf -> dt, dv
 | 
				
			||||||
 | 
					%np -> xm, ph
 | 
				
			||||||
 | 
					%dm -> nf, gr
 | 
				
			||||||
 | 
					%sq -> kj
 | 
				
			||||||
 | 
					%bv -> fp, xm
 | 
				
			||||||
 | 
					%br -> kt
 | 
				
			||||||
 | 
					%mg -> dz, gr
 | 
				
			||||||
 | 
					&dt -> vd, dv, dh, hm, ks, hd, kq
 | 
				
			||||||
 | 
					%ks -> qf
 | 
				
			||||||
 | 
					&qd -> rm
 | 
				
			||||||
 | 
					%xr -> vt, rn
 | 
				
			||||||
 | 
					%vr -> tg, vt
 | 
				
			||||||
 | 
					%lc -> xm
 | 
				
			||||||
 | 
					%tq -> gr, fh
 | 
				
			||||||
 | 
					%cr -> kq, dt
 | 
				
			||||||
 | 
					%vd -> dt, ks
 | 
				
			||||||
 | 
					%tb -> nx
 | 
				
			||||||
 | 
					%dz -> gr, fd
 | 
				
			||||||
 | 
					&gr -> dp, mg, fd, qn
 | 
				
			||||||
 | 
					%nf -> gr
 | 
				
			||||||
 | 
					%dv -> hm
 | 
				
			||||||
 | 
					%qj -> lc, xm
 | 
				
			||||||
 | 
					%kc -> dt, gf
 | 
				
			||||||
 | 
					%gf -> dt, qb
 | 
				
			||||||
 | 
					%vh -> xm, sv
 | 
				
			||||||
 | 
					%sr -> vt
 | 
				
			||||||
 | 
					%fp -> qg, xm
 | 
				
			||||||
 | 
					%kj -> vh
 | 
				
			||||||
 | 
					%pc -> tq, gr
 | 
				
			||||||
 | 
					%kq -> hd
 | 
				
			||||||
 | 
					%xd -> xg, gr
 | 
				
			||||||
 | 
					%tg -> sr, vt
 | 
				
			||||||
 | 
					&bb -> rm
 | 
				
			||||||
 | 
					%rn -> vt, qc
 | 
				
			||||||
 | 
					%hd -> ps
 | 
				
			||||||
 | 
					%qg -> xm, qj
 | 
				
			||||||
 | 
					&dp -> rm
 | 
				
			||||||
 | 
					%qn -> pc
 | 
				
			||||||
 | 
					%kt -> jl
 | 
				
			||||||
 | 
					%sv -> bv
 | 
				
			||||||
 | 
					&vt -> bb, nd, qc, xr, br, tb, kt
 | 
				
			||||||
 | 
					%fd -> mx
 | 
				
			||||||
 | 
					&xm -> zz, sv, sq, ph, kj, np, qd
 | 
				
			||||||
 | 
					%xg -> gr, qn
 | 
				
			||||||
 | 
					%mx -> gr, xd
 | 
				
			||||||
							
								
								
									
										304
									
								
								20/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								20/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,304 @@
 | 
				
			|||||||
 | 
					use std::collections::{BinaryHeap, HashMap, VecDeque};
 | 
				
			||||||
 | 
					use std::fmt::Display;
 | 
				
			||||||
 | 
					use std::fs::File;
 | 
				
			||||||
 | 
					use std::io::{BufRead, BufReader, Lines};
 | 
				
			||||||
 | 
					use std::time::Instant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use lazy_regex::lazy_regex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BOILERPLATE
 | 
				
			||||||
 | 
					type InputIter = Lines<BufReader<File>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_input() -> InputIter {
 | 
				
			||||||
 | 
					    let f = File::open("input").unwrap();
 | 
				
			||||||
 | 
					    let br = BufReader::new(f);
 | 
				
			||||||
 | 
					    br.lines()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    let start = Instant::now();
 | 
				
			||||||
 | 
					    let ans1 = problem1(get_input());
 | 
				
			||||||
 | 
					    let duration = start.elapsed();
 | 
				
			||||||
 | 
					    println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let start = Instant::now();
 | 
				
			||||||
 | 
					    let ans2 = problem2(get_input());
 | 
				
			||||||
 | 
					    let duration = start.elapsed();
 | 
				
			||||||
 | 
					    println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PARSE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MODULE_PATTERN: lazy_regex::Lazy<lazy_regex::Regex> = lazy_regex!("^([%&]?)([a-z]+) -> ([a-z, ]+)$");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 | 
				
			||||||
 | 
					enum PulseType {
 | 
				
			||||||
 | 
					    Low,
 | 
				
			||||||
 | 
					    High,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<bool> for PulseType {
 | 
				
			||||||
 | 
					    fn from(value: bool) -> Self {
 | 
				
			||||||
 | 
					        match value {
 | 
				
			||||||
 | 
					            true => PulseType::High,
 | 
				
			||||||
 | 
					            false => PulseType::Low,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<PulseType> for bool {
 | 
				
			||||||
 | 
					    fn from(value: PulseType) -> Self {
 | 
				
			||||||
 | 
					        match value {
 | 
				
			||||||
 | 
					            PulseType::High => true,
 | 
				
			||||||
 | 
					            PulseType::Low => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for PulseType {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            PulseType::Low => f.write_str("low"),
 | 
				
			||||||
 | 
					            PulseType::High => f.write_str("high"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					enum ModuleKind {
 | 
				
			||||||
 | 
					    FlipFlop,
 | 
				
			||||||
 | 
					    Conjunction,
 | 
				
			||||||
 | 
					    Broadcast,
 | 
				
			||||||
 | 
					    Button,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					struct Module {
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    kind: Option<ModuleKind>,
 | 
				
			||||||
 | 
					    inputs: Vec<String>,
 | 
				
			||||||
 | 
					    outputs: Vec<String>,
 | 
				
			||||||
 | 
					    on: bool,
 | 
				
			||||||
 | 
					    last_input_states: HashMap<String, PulseType>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Module {
 | 
				
			||||||
 | 
					    fn new(name: String) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            kind: None,
 | 
				
			||||||
 | 
					            inputs: Vec::new(),
 | 
				
			||||||
 | 
					            outputs: Vec::new(),
 | 
				
			||||||
 | 
					            on: false,
 | 
				
			||||||
 | 
					            last_input_states: HashMap::new(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn with_kind(name: String, kind: ModuleKind) -> Self {
 | 
				
			||||||
 | 
					        let mut m = Self::new(name);
 | 
				
			||||||
 | 
					        m.kind = Some(kind);
 | 
				
			||||||
 | 
					        m
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn and_destinations(mut self, destinations: &str) -> Self {
 | 
				
			||||||
 | 
					        println!("{} destinations: {}", self.name, destinations);
 | 
				
			||||||
 | 
					        for dest in destinations.split(", ") {
 | 
				
			||||||
 | 
					            println!("  {}", dest);
 | 
				
			||||||
 | 
					            self.outputs.push(dest.into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn and_source(mut self, source: String) -> Self {
 | 
				
			||||||
 | 
					        self.add_source(source);
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn add_source(&mut self, source: String) {
 | 
				
			||||||
 | 
					        self.inputs.push(source.clone());
 | 
				
			||||||
 | 
					        self.last_input_states.insert(source, PulseType::Low);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<&str> for Module {
 | 
				
			||||||
 | 
					    fn from(s: &str) -> Self {
 | 
				
			||||||
 | 
					        println!("s: {}", s);
 | 
				
			||||||
 | 
					        let Some(re_result) = MODULE_PATTERN.captures(s) else {
 | 
				
			||||||
 | 
					            panic!("unparseable module: {}", s);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let (_, [kind, name, destinations]) = re_result.extract();
 | 
				
			||||||
 | 
					        if name == "broadcaster" {
 | 
				
			||||||
 | 
					            return Module::with_kind(name.into(), ModuleKind::Broadcast).and_destinations(destinations);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        match kind {
 | 
				
			||||||
 | 
					            "%" => Module::with_kind(name.into(), ModuleKind::FlipFlop).and_destinations(destinations),
 | 
				
			||||||
 | 
					            "&" => Module::with_kind(name.into(), ModuleKind::Conjunction).and_destinations(destinations),
 | 
				
			||||||
 | 
					            _ => panic!("invalid module kind {}", kind),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					struct Job {
 | 
				
			||||||
 | 
					    signal: PulseType,
 | 
				
			||||||
 | 
					    targets: Vec<String>,
 | 
				
			||||||
 | 
					    from: String,
 | 
				
			||||||
 | 
					    priority: usize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PartialEq for Job {
 | 
				
			||||||
 | 
					    fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
 | 
					        self.priority == other.priority
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Eq for Job {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PartialOrd for Job {
 | 
				
			||||||
 | 
					    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 | 
				
			||||||
 | 
					        other.priority.partial_cmp(&self.priority)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Ord for Job {
 | 
				
			||||||
 | 
					    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 | 
				
			||||||
 | 
					        self.partial_cmp(other).unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					struct Machine {
 | 
				
			||||||
 | 
					    modules: HashMap<String, Module>,
 | 
				
			||||||
 | 
					    work_queue: BinaryHeap<Job>,
 | 
				
			||||||
 | 
					    count_low: u64,
 | 
				
			||||||
 | 
					    count_high: u64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: BufRead> From<Lines<T>> for Machine {
 | 
				
			||||||
 | 
					    fn from(mut lines: Lines<T>) -> Self {
 | 
				
			||||||
 | 
					        let mut modules = HashMap::from([(
 | 
				
			||||||
 | 
					            "button".into(),
 | 
				
			||||||
 | 
					            Module::with_kind("button".into(), ModuleKind::Button).and_destinations("broadcaster"),
 | 
				
			||||||
 | 
					        )]);
 | 
				
			||||||
 | 
					        while let Some(Ok(line)) = lines.next() {
 | 
				
			||||||
 | 
					            let mut module = Module::from(line.as_str());
 | 
				
			||||||
 | 
					            for output in &module.outputs {
 | 
				
			||||||
 | 
					                if let Some(output_mod) = modules.get_mut(output) {
 | 
				
			||||||
 | 
					                    // already exists, push to input list
 | 
				
			||||||
 | 
					                    output_mod.add_source(module.name.to_owned());
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // forward declaration of 'unknown' modules
 | 
				
			||||||
 | 
					                    modules.insert(
 | 
				
			||||||
 | 
					                        output.clone(),
 | 
				
			||||||
 | 
					                        Module::new(output.clone()).and_source(module.name.clone()),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if let Some(existing_mod) = modules.get(&module.name) {
 | 
				
			||||||
 | 
					                module.inputs = existing_mod.inputs.clone(); // might have been pre-prepared, the rest we take ours
 | 
				
			||||||
 | 
					                module.last_input_states = existing_mod.last_input_states.clone();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            modules.insert(module.name.clone(), module);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Machine {
 | 
				
			||||||
 | 
					            modules,
 | 
				
			||||||
 | 
					            work_queue: BinaryHeap::new(),
 | 
				
			||||||
 | 
					            count_low: 0, count_high: 0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Machine {
 | 
				
			||||||
 | 
					    fn press_button(&mut self) {
 | 
				
			||||||
 | 
					        self.send_pulse(PulseType::Low, "broadcaster", "button", 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn send_pulse(&mut self, signal: PulseType, target: &str, from: &str, priority: usize) {
 | 
				
			||||||
 | 
					        // count pulse when it is received
 | 
				
			||||||
 | 
					        match signal {
 | 
				
			||||||
 | 
					            PulseType::Low => self.count_low += 1,
 | 
				
			||||||
 | 
					            PulseType::High => self.count_high += 1,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        match self.modules[target].kind {
 | 
				
			||||||
 | 
					            Some(ModuleKind::Button) | Some(ModuleKind::Broadcast) => {
 | 
				
			||||||
 | 
					                self.send_all_outputs(PulseType::Low, target, priority)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Some(ModuleKind::FlipFlop) => match signal {
 | 
				
			||||||
 | 
					                PulseType::High => (),
 | 
				
			||||||
 | 
					                PulseType::Low => {
 | 
				
			||||||
 | 
					                    let new_state = !self.modules.get_mut(target).unwrap().on;
 | 
				
			||||||
 | 
					                    self.modules.get_mut(target).unwrap().on = new_state;
 | 
				
			||||||
 | 
					                    self.send_all_outputs(new_state.into(), target, priority)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Some(ModuleKind::Conjunction) => {
 | 
				
			||||||
 | 
					                self.modules
 | 
				
			||||||
 | 
					                    .get_mut(target)
 | 
				
			||||||
 | 
					                    .unwrap()
 | 
				
			||||||
 | 
					                    .last_input_states
 | 
				
			||||||
 | 
					                    .insert(from.to_owned(), signal);
 | 
				
			||||||
 | 
					                if self.modules[target]
 | 
				
			||||||
 | 
					                    .last_input_states
 | 
				
			||||||
 | 
					                    .values()
 | 
				
			||||||
 | 
					                    .all(|state| *state == PulseType::High)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    self.send_all_outputs(PulseType::Low, target, priority)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    self.send_all_outputs(PulseType::High, target, priority)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            None => (),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn send_all_outputs(&mut self, signal: PulseType, from: &str, priority: usize) {
 | 
				
			||||||
 | 
					        self.work_queue.push(Job {
 | 
				
			||||||
 | 
					            signal,
 | 
				
			||||||
 | 
					            targets: self.modules[from].outputs.iter().map(|op| op.to_owned()).collect(),
 | 
				
			||||||
 | 
					            from: from.to_owned(),
 | 
				
			||||||
 | 
					            priority: priority + 1,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn run(&mut self) {
 | 
				
			||||||
 | 
					        while let Some(job) = self.work_queue.pop() {
 | 
				
			||||||
 | 
					            for target in job.targets {
 | 
				
			||||||
 | 
					                self.send_pulse(job.signal, &target, &job.from, job.priority);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PROBLEM 1 solution
 | 
				
			||||||
 | 
					const PROBLEM1_ITERATIONS: usize = 1000;
 | 
				
			||||||
 | 
					fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
 | 
				
			||||||
 | 
					    let mut machine = Machine::from(input);
 | 
				
			||||||
 | 
					    println!("{:?}", machine);
 | 
				
			||||||
 | 
					    for _ in 0..PROBLEM1_ITERATIONS {
 | 
				
			||||||
 | 
					        machine.press_button();
 | 
				
			||||||
 | 
					        machine.run();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    machine.count_low * machine.count_high
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PROBLEM 2 solution
 | 
				
			||||||
 | 
					fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
 | 
				
			||||||
 | 
					    0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use crate::*;
 | 
				
			||||||
 | 
					    use std::io::Cursor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const EXAMPLE: &str = &"broadcaster -> a
 | 
				
			||||||
 | 
					%a -> inv, con
 | 
				
			||||||
 | 
					&inv -> b
 | 
				
			||||||
 | 
					%b -> con
 | 
				
			||||||
 | 
					&con -> output";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn problem1_example() {
 | 
				
			||||||
 | 
					        let c = Cursor::new(EXAMPLE);
 | 
				
			||||||
 | 
					        assert_eq!(problem1(c.lines()), 11687500);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn problem2_example() {
 | 
				
			||||||
 | 
					        let c = Cursor::new(EXAMPLE);
 | 
				
			||||||
 | 
					        assert_eq!(problem2(c.lines()), 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user