Day 20
This commit is contained in:
parent
b37750d5ae
commit
a1a6e2a9a7
|
@ -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
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue