This commit is contained in:
Shadowfacts 2023-12-20 12:41:43 -05:00
parent b37750d5ae
commit a1a6e2a9a7
4 changed files with 385 additions and 2 deletions

58
input/day20.txt Normal file
View File

@ -0,0 +1,58 @@
%bc -> ph
%hr -> zq
%sn -> sj
%df -> dn, hf
%lp -> dm
%lf -> sn, vk
&fv -> sq
%gd -> vm, gr
%jt -> vm, lz
%xf -> vk
%nf -> lp, kb
%dl -> nn
&sq -> rx
%vb -> vm, lg
%zq -> kb, fl
%fk -> fz
%gj -> pq
%jx -> jh
%pq -> kb, nf
&dn -> kg, vt, tg, fs, pn, jx
%ln -> dn, fs
%fz -> vm, jt
%fs -> df
%dm -> kb, hr
%ds -> kb
&kk -> sq
%tg -> tv
&vt -> sq
%fl -> zl, kb
&vk -> bc, sj, jd, lf, xr, sn
%jd -> pp
%tv -> dn, pn
%sb -> gf, vk
&kb -> kk, gj, gt, hr, lp
%pp -> vk, bc
%pn -> pf
%zc -> vm
&vm -> dl, fk, nn, fv, gd, lg
%rn -> dn
%gr -> vb, vm
%sj -> kq
%zl -> kb, ds
%lz -> vm, zc
%jh -> dn, ln
%pf -> dn, jx
%kq -> sb, vk
%ph -> md, vk
%nc -> gj, kb
%kg -> tg, dn
%hf -> dn, rn
%nn -> fk
%gf -> jd, vk
%lg -> pv
broadcaster -> gd, kg, gt, lf
%gt -> nc, kb
%pv -> dl, vm
&xr -> sq
%md -> vk, xf

View File

@ -128,7 +128,7 @@ fn count_steps_until_end(
steps steps
} }
fn lcm(xs: impl Iterator<Item = usize>) -> usize { pub fn lcm(xs: impl Iterator<Item = usize>) -> usize {
let mut a = 1; let mut a = 1;
for x in xs { for x in xs {
a = a * x / gcd(a, x); a = a * x / gcd(a, x);

324
src/day20.rs Normal file
View File

@ -0,0 +1,324 @@
use std::{
collections::{HashMap, HashSet, VecDeque},
fmt::Display,
};
use itertools::Itertools;
pub fn run() {
let input = include_str!("../input/day20.txt");
// let input = r#"
// broadcaster -> a, b, c
// %a -> b
// %b -> c
// %c -> inv
// &inv -> a
// "#;
// let input = r#"
// broadcaster -> a
// %a -> inv, con
// &inv -> b
// %b -> con
// &con -> output
// "#;
let modules = parse_modules(input);
dbg!(simulate_one_thousand(modules.clone()));
let rx_input = find_inputs(&modules, "rx");
assert_eq!(rx_input.len(), 1);
let rx_input = rx_input[0];
assert!(modules[rx_input].as_any().is::<Conjunction>());
let rx_input_inputs = find_inputs(&modules, rx_input);
let cycles = rx_input_inputs
.into_iter()
.map(|s| find_output_cycle(modules.clone(), s))
.collect::<Vec<_>>();
dbg!(crate::day08::lcm(cycles.into_iter()));
}
fn parse_modules(s: &'static str) -> HashMap<&'static str, Box<dyn Module>> {
let mut m = HashMap::<&'static str, Box<dyn Module>>::new();
m.insert("output", Box::new(Output));
let mut conjunctions = vec![];
for l in s.trim().lines() {
let l = l.trim();
let (name, receivers) = l.split_once(" -> ").unwrap();
let receivers = receivers.split(", ").collect::<Vec<_>>();
let trimmed_name: &'static str;
let module: Box<dyn Module>;
if name == "broadcaster" {
trimmed_name = "broadcaster";
module = Box::new(Broadcaster { receivers });
} else if name.starts_with("%") {
trimmed_name = &name[1..];
module = Box::new(FlipFlop {
receivers,
state: false,
});
} else if name.starts_with("&") {
trimmed_name = &name[1..];
conjunctions.push(trimmed_name);
module = Box::new(Conjunction {
receivers,
inputs: HashMap::new(),
});
} else {
panic!("invalid name {}", name);
}
m.insert(trimmed_name, module);
}
for name in conjunctions {
let inputs = m
.iter()
.filter(|(_, v)| v.get_destinations().contains(&name))
.map(|(k, _)| (*k, false))
.collect::<HashMap<&'static str, bool>>();
let any = m.get_mut(name).unwrap().as_any_mut();
let conjunction = any.downcast_mut::<Conjunction>().unwrap();
conjunction.inputs = inputs;
}
m
}
#[derive(Debug, Clone, Copy)]
struct Pulse {
destination: &'static str,
value: bool,
}
trait Module: std::fmt::Debug {
fn get_destinations(&self) -> &[&'static str];
fn handle_pulse(&mut self, source: &'static str, value: bool) -> Vec<Pulse>;
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
fn as_any(&self) -> &dyn std::any::Any;
fn clone_module(&self) -> Box<dyn Module>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Broadcaster {
receivers: Vec<&'static str>,
}
impl Module for Broadcaster {
fn handle_pulse(&mut self, _source: &'static str, value: bool) -> Vec<Pulse> {
self.receivers
.iter()
.map(|r| Pulse {
destination: r,
value,
})
.collect()
}
fn get_destinations(&self) -> &[&'static str] {
&self.receivers
}
fn clone_module(&self) -> Box<dyn Module> {
Box::new(self.clone())
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct FlipFlop {
receivers: Vec<&'static str>,
state: bool,
}
impl Module for FlipFlop {
fn handle_pulse(&mut self, _source: &'static str, value: bool) -> Vec<Pulse> {
if value {
return vec![];
}
self.state = !self.state;
self.receivers
.iter()
.map(|r| Pulse {
destination: r,
value: self.state,
})
.collect()
}
fn get_destinations(&self) -> &[&'static str] {
&self.receivers
}
fn clone_module(&self) -> Box<dyn Module> {
Box::new(self.clone())
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Conjunction {
receivers: Vec<&'static str>,
inputs: HashMap<&'static str, bool>,
}
impl Module for Conjunction {
fn handle_pulse(&mut self, source: &'static str, value: bool) -> Vec<Pulse> {
self.inputs.insert(source, value);
let output = !self.inputs.values().all(|b| *b);
self.receivers
.iter()
.map(|r| Pulse {
destination: r,
value: output,
})
.collect()
}
fn get_destinations(&self) -> &[&'static str] {
&self.receivers
}
fn clone_module(&self) -> Box<dyn Module> {
Box::new(self.clone())
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Output;
impl Module for Output {
fn get_destinations(&self) -> &[&'static str] {
&[]
}
fn handle_pulse(&mut self, _source: &'static str, _value: bool) -> Vec<Pulse> {
vec![]
}
fn clone_module(&self) -> Box<dyn Module> {
Box::new(Output)
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
fn simulate(modules: &mut HashMap<&'static str, Box<dyn Module>>) -> (usize, usize) {
let mut pulses_to_send = VecDeque::from([(
"button",
Pulse {
destination: "broadcaster",
value: false,
},
)]);
let mut high = 0;
let mut low = 0;
// println!("button -low-> broadcaster");
while let Some((source, p)) = pulses_to_send.pop_front() {
if p.value {
high += 1;
} else {
low += 1;
}
let handler = p.destination;
let handling_module = modules.get_mut(handler);
if handling_module.is_none() {
// println!("no module {}", handler);
continue;
}
let new = handling_module.unwrap().handle_pulse(source, p.value);
for p in new {
// let value = if p.value { "high" } else { "low" };
// println!("{} -{}-> {}", handler, value, p.destination);
pulses_to_send.push_back((handler, p));
}
}
(high, low)
}
impl Clone for Box<dyn Module> {
fn clone(&self) -> Self {
self.clone_module()
}
}
fn simulate_one_thousand(mut modules: HashMap<&'static str, Box<dyn Module>>) -> usize {
let mut high = 0;
let mut low = 0;
for _ in 0..1000 {
let r = simulate(&mut modules);
high += r.0;
low += r.1;
}
high * low
}
fn find_inputs(
modules: &HashMap<&'static str, Box<dyn Module>>,
dest: &'static str,
) -> Vec<&'static str> {
let mut inputs = vec![];
for (name, module) in modules.iter() {
if module.get_destinations().contains(&dest) {
inputs.push(*name);
}
}
inputs
}
fn find_output_cycle(
mut modules: HashMap<&'static str, Box<dyn Module>>,
name: &'static str,
) -> usize {
let mut iterations = 0;
loop {
iterations += 1;
let mut pulses_to_send = VecDeque::from([(
"button",
Pulse {
destination: "broadcaster",
value: false,
},
)]);
while let Some((source, p)) = pulses_to_send.pop_front() {
if !p.value && p.destination == name {
return iterations;
}
let handler = p.destination;
if let Some(handling_module) = modules.get_mut(handler) {
let new = handling_module.handle_pulse(source, p.value);
for p in new {
pulses_to_send.push_back((handler, p));
}
}
}
}
}

View File

@ -20,7 +20,8 @@ mod day16;
mod day17; mod day17;
mod day18; mod day18;
mod day19; mod day19;
mod day20;
fn main() { fn main() {
day19::run(); day20::run();
} }