diff --git a/20/day20.rs b/20/day20.rs new file mode 100644 index 0000000..8cf8517 --- /dev/null +++ b/20/day20.rs @@ -0,0 +1,146 @@ +use std::io::{self, BufRead}; +use std::convert::TryInto; +// use num::Integer; +use std::collections::{HashMap, VecDeque}; + +type Pulse = u8; +const LOW: Pulse = 0; +const HIGH: Pulse = 1; + +trait Module { + fn get_pulse(&mut self, from: u16, pulse: Pulse) -> Option; + fn add_input(&mut self, input: u16) {} + fn get_connections(&self) -> &Vec; +} +#[derive(Clone)] +struct FlipFlop { + name: u16, + modules: Vec, + state: Pulse, +} +impl Module for FlipFlop { + fn get_pulse(&mut self, from: u16, pulse: Pulse) -> Option { + if pulse == LOW { + self.state ^= HIGH; + return Some(self.state); + } + None + } + fn get_connections(&self) -> &Vec { return &self.modules; } +} + +#[derive(Clone)] +struct Conjunction { + name: u16, + modules: Vec, + state: Pulse, + last_inputs: HashMap, +} +impl Module for Conjunction { + fn get_pulse(&mut self, from: u16, pulse: Pulse) -> Option { + self.last_inputs.iter().for_each(|(k, v)| print!("{}: {},", k, v)); + println!(); + if !self.last_inputs.contains_key(&from) { + panic!("Conjunction got unexpected impulse from {}", from); + } + *self.last_inputs.get_mut(&from).unwrap() = pulse; + if self.last_inputs.iter().all(|(k,v)| *v == HIGH) { self.state = LOW; } + else { self.state = HIGH; } + return Some(self.state) + } + fn add_input(&mut self, input: u16) { + self.last_inputs.insert(input, LOW); + } + fn get_connections(&self) -> &Vec { return &self.modules; } +} + +#[derive(Clone)] +struct Start { + name: u16, + modules: Vec, + state: Pulse, +} +impl Module for Start { + fn get_pulse(&mut self, from: u16, pulse: Pulse) -> Option { + self.state = pulse; + return Some(self.state) + } + fn get_connections(&self) -> &Vec { return &self.modules; } +} + + +fn make_index(s: &str) -> u16 { + println!("{}", s); + if s.len() == 2 { + let mut t: u16 = 0; + s.as_bytes().iter().enumerate().for_each(|(i, c)| t |= (*c as u16) << i*8); + return t; + } + return 0 +} +fn from_index(i: u16) -> char { + if i == 0 { return 'B' } + let mut c: u8 = i as u8; + c |= i.overflowing_shr(8).0 as u8; + return c as char +} + +fn main() { + let input = "input.txt"; + // let input = "example.txt"; + // let input = "example2.txt"; + let mut lines = read_lines(&input); + let mut modules = HashMap::>::new(); + for line in lines.map(|r| r.ok().unwrap()) { + let dash = line.find('-').unwrap(); + let module = make_index(&line[1..dash-1]); + println!("{module}"); + let connected_modules = line[dash+2..].split(',').map(|s| make_index(&s[1..])).collect(); + let _ = match line.chars().next().unwrap() { + '&' => modules.insert(module, Box::new(Conjunction{name:module, modules: connected_modules, state: LOW, last_inputs: HashMap::new()})), + '%' => modules.insert(module, Box::new(FlipFlop{name:module, modules: connected_modules, state: LOW})), + _ => modules.insert(module, Box::new(Start{name:module, modules: connected_modules, state: LOW})), + }; + } + let keys = modules.keys().map(|k| *k).collect::>().clone(); + for n in keys.iter() { + let connected_modules = modules[n].get_connections().clone().iter().filter(|c| modules.contains_key(c)).map(|c| *c).collect::>(); + for c in connected_modules.iter() { + let m = modules.get_mut(c).unwrap(); + m.add_input(*n); + } + } + let mut modules2 = modules.clone(); + let mut queue: VecDeque::<(u16, Pulse)> = VecDeque::new(); + let mut lows: usize = 0; + let mut highs: usize = 0; + for i in 0..1000 { + println!("{i}"); + queue.push_back((0, LOW)); + lows += 1; + while !queue.is_empty() { + let (from, pulse) = queue.pop_front().unwrap(); + if !modules.contains_key(&from) { continue; } + for m in modules[&from].get_connections().clone().iter() { + println!("{:6} -{} -> {}", from_index(from), pulse, from_index(*m)); + if pulse == LOW { lows += 1 } else { highs += 1 } + if !modules.contains_key(m) { continue; } + if let Some(new_pulse) = modules.get_mut(&m).unwrap().get_pulse(from, pulse) { + queue.push_back((*m, new_pulse)); + } + } + } + } + println!("lows: {}, highs: {}", lows, highs); + println!("lows * highs (1): {}", lows * highs); + +} + + +fn read_lines

(filename: P) -> io::Lines> +where P: AsRef, { + return match std::fs::File::open(filename) { + Err(why) => panic!("Could not open file. {}", why), + Ok(file) => std::io::BufReader::new(file).lines() + }; +}