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