diff --git a/data/examples/20.txt b/data/examples/20.txt index e69de29..2dc1bab 100644 --- a/data/examples/20.txt +++ b/data/examples/20.txt @@ -0,0 +1,5 @@ +broadcaster -> a, b, c +%a -> b +%b -> c +%c -> inv +&inv -> a diff --git a/src/bin/20.rs b/src/bin/20.rs index f3cad6a..5bdb6af 100644 --- a/src/bin/20.rs +++ b/src/bin/20.rs @@ -1,9 +1,14 @@ -use std::{collections::HashMap, str::FromStr}; +use std::{ + collections::{HashMap, VecDeque}, + mem::swap, + process::Output, + str::FromStr, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum Module { Broadcaster, - FlipFlop, + FlipFlop(bool), Conjuction, } @@ -14,7 +19,7 @@ impl FromStr for Module { type Err = ParseModuleError; fn from_str(s: &str) -> Result { Ok(match s { - "%" => Module::FlipFlop, + "%" => Module::FlipFlop(false), "&" => Module::Conjuction, _ => Module::Broadcaster, }) @@ -22,16 +27,37 @@ impl FromStr for Module { } #[derive(Debug)] -struct Location { +struct Node { + index: usize, module: Module, - inputs: HashMap>, - outputs: Vec, + inputs: Vec, + outputs: Vec, } -fn parse_input(input: &str) -> (Vec, HashMap) { - let mut locations = Vec::new(); +fn parse_input(input: &str) -> Vec { + let mut nodes = Vec::new(); let mut mapper: HashMap = HashMap::new(); + for line in input.lines() { + let (from, _) = line.split_once(" -> ").unwrap(); + let (module, mut name) = from.split_at(1); + let module: Module = module.parse().unwrap(); + if module == Module::Broadcaster { + name = from; + } + + *mapper.entry(name.to_string()).or_default() = nodes.len(); + + let l = Node { + module, + index: nodes.len(), + inputs: Vec::new(), + outputs: Vec::new(), + }; + + nodes.push(l); + } + for line in input.lines() { let (from, to) = line.split_once(" -> ").unwrap(); let (module, mut name) = from.split_at(1); @@ -40,53 +66,96 @@ fn parse_input(input: &str) -> (Vec, HashMap) { name = from; } - let l = Location { - module, - inputs: HashMap::new(), - outputs: to.split(", ").map(String::from).collect(), - }; - - locations.push(l); - *mapper.entry(name.to_string()).or_default() = locations.len() - 1; - } - for line in input.lines() { - let (from, to) = line.split_once(" -> ").unwrap(); - let (_, name) = from.split_at(1); - + let index = mapper[name]; for destination in to.split(", ") { - let index = mapper[name]; - locations[index] - .inputs - .entry(destination.to_string()) - .or_default(); + let to_index = mapper[destination]; + nodes[index].outputs.push(to_index); + nodes[to_index].inputs.push(index); } } - (locations, mapper) + nodes } pub fn part_one(input: &str) -> Option { - let (locations, mapper) = parse_input(input); + let mut nodes = parse_input(input); - let mut high = 0; - let mut low = 0; + let mut graph = vec![vec![None; input.len()]; input.len()]; + + let mut highs = 0; + let mut lows = 0; + + let broadcaster = nodes + .iter() + .find(|x| x.module == Module::Broadcaster)? + .index; for _ in 0..1000 { - let mut stack = vec!["broadcaster".to_string()]; + let mut stack = VecDeque::from([broadcaster]); while !stack.is_empty() { - let mut new_stack = Vec::new(); + let mut new_stack = VecDeque::new(); - while let Some(s) = stack.pop() { - let index = mapper[&s]; - let loc = &locations[index]; + while let Some(index) = stack.pop_front() { + let node = &nodes[index]; + let mut new_module = None; - match loc.module { + match node.module { Module::Broadcaster => { - for dest in loc.outputs.iter() { - let index = mapper[dest]; - let loc = &locations[index]; + for dest_index in node.outputs.iter() { + graph[index][*dest_index] = Some(false); + new_stack.push_back(*dest_index); + lows += 1; } } + Module::FlipFlop(high) => { + let mut swapper = None; + for in_index in nodes[index].inputs.iter() { + let value = &mut graph[*in_index][index]; + if value.is_some() { + debug_assert!(swapper.is_none()); + swap(&mut swapper, value); + } + } + + if !swapper.unwrap() { + let signal = !high; + + for dest_index in nodes[index].outputs.iter() { + graph[index][*dest_index] = Some(signal); + new_stack.push_back(*dest_index); + if signal { + highs += 1; + } else { + lows += 1; + } + } + + new_module = Some(Module::FlipFlop(signal)); + } + } + Module::Conjuction => { + let mut all = true; + + for in_index in nodes[index].inputs.iter() { + let value = graph[*in_index][index]; + all &= value.unwrap_or(false); + } + + for dest_index in nodes[index].outputs.iter() { + graph[index][*dest_index] = Some(!all); + new_stack.push_back(*dest_index); + if !all { + highs += 1; + } else { + lows += 1; + } + } + } + } + + let node = &mut nodes[index]; + if let Some(module) = new_module { + node.module = module; } } @@ -94,7 +163,7 @@ pub fn part_one(input: &str) -> Option { } } - Some(high * low) + Some(highs * lows) } pub fn part_two(input: &str) -> Option {