2023 - Day 20 [Part 2 works with manual help]
This commit is contained in:
parent
bd741d38d4
commit
fbceb13123
58
2023/input/20/input
Normal file
58
2023/input/20/input
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
%rq -> ch, sj
|
||||||
|
%nf -> sm, rg
|
||||||
|
%pc -> rz, zp
|
||||||
|
%xt -> bc
|
||||||
|
%nt -> kq, sj
|
||||||
|
%hc -> kb, zp
|
||||||
|
%rd -> lk
|
||||||
|
%ml -> pp, xt
|
||||||
|
%sq -> kl, sj
|
||||||
|
%jg -> fl, rg
|
||||||
|
&xl -> df
|
||||||
|
%kl -> mb, sj
|
||||||
|
%nd -> rg, jg
|
||||||
|
&rg -> cs, zb, cp, vz, gp
|
||||||
|
%mf -> zp
|
||||||
|
%rz -> zp, fr
|
||||||
|
%kk -> rg, bj
|
||||||
|
%nb -> qj
|
||||||
|
%pr -> pp
|
||||||
|
&zp -> vl, lk, rd, kb, xl
|
||||||
|
%fl -> nf, rg
|
||||||
|
%tb -> pk, pp
|
||||||
|
%bh -> pp, pr
|
||||||
|
%nh -> sj, rq
|
||||||
|
%lk -> hc
|
||||||
|
%cp -> kk
|
||||||
|
&ln -> df
|
||||||
|
&xp -> df
|
||||||
|
%bc -> nb, pp
|
||||||
|
%lj -> rg
|
||||||
|
%vz -> nd
|
||||||
|
%vl -> lv, zp
|
||||||
|
&gp -> df
|
||||||
|
%hd -> pp, bq
|
||||||
|
%fq -> pp, bh
|
||||||
|
%pk -> fq, pp
|
||||||
|
%cs -> zb, rg
|
||||||
|
%sn -> fd
|
||||||
|
%kq -> sj, qq
|
||||||
|
%zb -> vz
|
||||||
|
%lv -> zp, rd
|
||||||
|
%qj -> pp, hd
|
||||||
|
%fd -> nt
|
||||||
|
&df -> rx
|
||||||
|
broadcaster -> vl, cs, cn, ml
|
||||||
|
%bq -> tb
|
||||||
|
%kb -> pc
|
||||||
|
%cn -> sn, sj
|
||||||
|
%qq -> sq
|
||||||
|
%mb -> sj, nh
|
||||||
|
%jd -> zp, mf
|
||||||
|
&sj -> xp, qq, cn, fd, sn
|
||||||
|
&pp -> ln, ml, xt, bq, nb
|
||||||
|
%sm -> rg, cp
|
||||||
|
%ch -> sj
|
||||||
|
%bj -> lj, rg
|
||||||
|
%fr -> zp, mr
|
||||||
|
%mr -> zp, jd
|
5
2023/input/20/test-1
Normal file
5
2023/input/20/test-1
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
broadcaster -> a, b, c
|
||||||
|
%a -> b
|
||||||
|
%b -> c
|
||||||
|
%c -> inv
|
||||||
|
&inv -> a
|
5
2023/input/20/test-2
Normal file
5
2023/input/20/test-2
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
broadcaster -> a
|
||||||
|
%a -> inv, con
|
||||||
|
&inv -> b
|
||||||
|
%b -> con
|
||||||
|
&con -> output
|
252
2023/src/bin/day20.rs
Normal file
252
2023/src/bin/day20.rs
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
#![feature(test)]
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use aoc::Solver;
|
||||||
|
|
||||||
|
// -- Runners --
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
Day::solve()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_test1() -> Result<()> {
|
||||||
|
Day::test(Day::part1, "test-1", 32000000)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_test2() -> Result<()> {
|
||||||
|
Day::test(Day::part1, "test-2", 11687500)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_solution() -> Result<()> {
|
||||||
|
Day::test(Day::part1, "input", 666795063)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_solution() -> Result<()> {
|
||||||
|
Day::test(Day::part2, "input", 253302889093151)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmarks
|
||||||
|
extern crate test;
|
||||||
|
#[bench]
|
||||||
|
#[ignore]
|
||||||
|
fn part1_bench(b: &mut test::Bencher) {
|
||||||
|
Day::benchmark(Day::part1, b)
|
||||||
|
}
|
||||||
|
#[bench]
|
||||||
|
#[ignore]
|
||||||
|
fn part2_bench(b: &mut test::Bencher) {
|
||||||
|
Day::benchmark(Day::part2, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum ModuleType<'a> {
|
||||||
|
Broadcaster,
|
||||||
|
FlipFlop(bool),
|
||||||
|
Conjunction(HashMap<&'a str, bool>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Module<'a> {
|
||||||
|
module_type: ModuleType<'a>,
|
||||||
|
destinations: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Module<'a> {
|
||||||
|
fn process(&mut self, source: &'a str, high: bool) -> Option<bool> {
|
||||||
|
match &mut self.module_type {
|
||||||
|
ModuleType::Broadcaster => Some(high),
|
||||||
|
ModuleType::FlipFlop(current) => {
|
||||||
|
if high {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
*current = !*current;
|
||||||
|
Some(*current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ModuleType::Conjunction(inputs) => {
|
||||||
|
let input = inputs.get_mut(source).unwrap();
|
||||||
|
*input = high;
|
||||||
|
|
||||||
|
Some(!inputs.iter().all(|(_, prev)| *prev))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Pulse<'a> {
|
||||||
|
source: &'a str,
|
||||||
|
destination: &'a str,
|
||||||
|
high: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Solution --
|
||||||
|
pub struct Day;
|
||||||
|
impl aoc::Solver for Day {
|
||||||
|
type Output1 = usize;
|
||||||
|
type Output2 = usize;
|
||||||
|
|
||||||
|
fn day() -> u8 {
|
||||||
|
20
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Self::Output1 {
|
||||||
|
let mut modules: HashMap<_, _> = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let (name, destinations) = line.split_once(" -> ").unwrap();
|
||||||
|
let destinations: Vec<_> = destinations.split(", ").collect();
|
||||||
|
|
||||||
|
let (name, module_type) = if name.starts_with('%') {
|
||||||
|
(name.split_at(1).1, ModuleType::FlipFlop(false))
|
||||||
|
} else if name.starts_with('&') {
|
||||||
|
(name.split_at(1).1, ModuleType::Conjunction(HashMap::new()))
|
||||||
|
} else if name == "broadcaster" {
|
||||||
|
(name, ModuleType::Broadcaster)
|
||||||
|
} else {
|
||||||
|
unreachable!("Invalid input");
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
Module {
|
||||||
|
module_type,
|
||||||
|
destinations,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// TODO: Because of the borrow check we have to create a clone of modules here
|
||||||
|
for (name, module) in modules.clone() {
|
||||||
|
for destination in &module.destinations {
|
||||||
|
if let Some(module) = modules.get_mut(destination) {
|
||||||
|
if let ModuleType::Conjunction(inputs) = &mut module.module_type {
|
||||||
|
inputs.insert(name, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = (0, 0);
|
||||||
|
let mut pulses = VecDeque::new();
|
||||||
|
for _ in 0..1000 {
|
||||||
|
pulses.push_back(Pulse {
|
||||||
|
source: "button",
|
||||||
|
destination: "broadcaster",
|
||||||
|
high: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
while let Some(pulse) = pulses.pop_front() {
|
||||||
|
if pulse.high {
|
||||||
|
count.1 += 1;
|
||||||
|
} else {
|
||||||
|
count.0 += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(module) = modules.get_mut(pulse.destination) {
|
||||||
|
if let Some(high) = module.process(pulse.source, pulse.high) {
|
||||||
|
for destination in &module.destinations {
|
||||||
|
pulses.push_back(Pulse {
|
||||||
|
source: pulse.destination,
|
||||||
|
destination,
|
||||||
|
high,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count.0 * count.1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> Self::Output2 {
|
||||||
|
let mut modules: HashMap<_, _> = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
let (name, destinations) = line.split_once(" -> ").unwrap();
|
||||||
|
let destinations: Vec<_> = destinations.split(", ").collect();
|
||||||
|
|
||||||
|
let (name, module_type) = if name.starts_with('%') {
|
||||||
|
(name.split_at(1).1, ModuleType::FlipFlop(false))
|
||||||
|
} else if name.starts_with('&') {
|
||||||
|
(name.split_at(1).1, ModuleType::Conjunction(HashMap::new()))
|
||||||
|
} else if name == "broadcaster" {
|
||||||
|
(name, ModuleType::Broadcaster)
|
||||||
|
} else {
|
||||||
|
unreachable!("Invalid input");
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
Module {
|
||||||
|
module_type,
|
||||||
|
destinations,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// TODO: Because of the borrow check we have to create a clone of modules here
|
||||||
|
for (name, module) in modules.clone() {
|
||||||
|
for destination in &module.destinations {
|
||||||
|
if let Some(module) = modules.get_mut(destination) {
|
||||||
|
if let ModuleType::Conjunction(inputs) = &mut module.module_type {
|
||||||
|
inputs.insert(name, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let r#final = modules
|
||||||
|
.iter()
|
||||||
|
.find(|(_, module)| module.destinations.contains(&"rx"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let final_name = r#final.0.to_owned();
|
||||||
|
let final_module = r#final.1.clone();
|
||||||
|
|
||||||
|
println!("{final_name}: {final_module:?}");
|
||||||
|
|
||||||
|
let mut pulses = VecDeque::new();
|
||||||
|
for i in 0..10000 {
|
||||||
|
pulses.push_back(Pulse {
|
||||||
|
source: "button",
|
||||||
|
destination: "broadcaster",
|
||||||
|
high: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
while let Some(pulse) = pulses.pop_front() {
|
||||||
|
if let Some(module) = modules.get_mut(pulse.destination) {
|
||||||
|
if pulse.destination == final_name && pulse.high {
|
||||||
|
// TODO: Instead of printing this, keep track of it
|
||||||
|
// Once all inputs have received a pulse calculate the LCM and output that
|
||||||
|
println!("{} high after {} presses", pulse.source, i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(high) = module.process(pulse.source, pulse.high) {
|
||||||
|
for destination in &module.destinations {
|
||||||
|
pulses.push_back(Pulse {
|
||||||
|
source: pulse.destination,
|
||||||
|
destination,
|
||||||
|
high,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user