This commit is contained in:
Andrew Glaze 2023-12-21 10:10:57 -05:00
parent d3c11dcbed
commit a19a3258c2
4 changed files with 305 additions and 0 deletions

83
Cargo.lock generated
View File

@ -10,6 +10,7 @@ dependencies = [
"aoc-runner-derive", "aoc-runner-derive",
"array2d", "array2d",
"itertools", "itertools",
"num",
"prev-iter", "prev-iter",
"regex", "regex",
"rust-crypto", "rust-crypto",
@ -61,6 +62,12 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b39cb2c1bf5a7c0dd097aa95ab859cf87dab5a4328900f5388942dc1889f74" checksum = "d8b39cb2c1bf5a7c0dd097aa95ab859cf87dab5a4328900f5388942dc1889f74"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "either" name = "either"
version = "1.9.0" version = "1.9.0"
@ -112,6 +119,82 @@ version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "num"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "prev-iter" name = "prev-iter"
version = "0.1.2" version = "0.1.2"

View File

@ -16,3 +16,4 @@ strum = "0.25.0"
strum_macros = "0.25" strum_macros = "0.25"
prev-iter = "0.1.2" prev-iter = "0.1.2"
regex = "1.10.2" regex = "1.10.2"
num = "0.4.1"

220
src/day20.rs Normal file
View File

@ -0,0 +1,220 @@
use std::collections::{HashMap, VecDeque};
use aoc_runner_derive::{aoc, aoc_generator};
use num::Integer;
#[derive(Debug, Clone)]
enum Module {
FlipFlop { state: bool, dests: Vec<String> },
Conjunction { state: HashMap<String, bool>, dests: Vec<String> },
Broadcast { dests: Vec<String> },
}
#[aoc_generator(day20)]
fn parse(input: &str) -> HashMap<String, Module> {
let mut input: HashMap<_, _> = input.lines().map(|line| {
let (name, dests) = line.split_once("->").unwrap();
let dests = parse_destinations(dests);
let module = parse_module(name.trim(), dests);
(name.trim_matches(['&', '%', ' '].as_slice()).to_string(), module)
}).collect();
collect_inputs(&mut input);
input
}
fn parse_module(name: &str, dests: Vec<String>) -> Module {
match name {
"broadcaster" => Module::Broadcast { dests },
name if name.starts_with('%') => Module::FlipFlop { state: false, dests },
name if name.starts_with('&') => Module::Conjunction { state: HashMap::new(), dests },
_ => panic!("Invalid Module {}", name)
}
}
fn collect_inputs(modules: &mut HashMap<String, Module>) {
for (name, module) in modules.clone() {
let dests = match module {
Module::FlipFlop { state: _, dests: dest } => dest,
Module::Conjunction { state: _, dests: dest } => dest,
Module::Broadcast { dests: dest } => dest,
};
for dest_name in dests {
if let Some(dest_mod) = modules.get_mut(&dest_name) {
match dest_mod {
Module::Conjunction { state, dests: _ } => state.insert(name.to_string(), false),
_ => continue
};
}
}
}
}
fn parse_destinations(dests: &str) -> Vec<String> {
dests.split(',')
.map(|x| x.trim().to_string())
.collect::<Vec<String>>()
}
#[aoc(day20, part1)]
fn part1(modules: &HashMap<String, Module>) -> usize {
let mut modules = modules.clone();
let mut high: usize = 0;
let mut low: usize = 0;
for _ in 0..1000 {
let (high_pulses, low_pulses) = push_the_button(&mut modules);
high += high_pulses;
low += low_pulses;
}
high * low
}
fn push_the_button(modules: &mut HashMap<String, Module>) -> (usize, usize) {
let mut process_queue: VecDeque<(String, bool, String)> = VecDeque::new();
process_queue.push_back(("broadcaster".to_string(), false, "".to_string()));
let mut low_pulses: usize = 0;
let mut high_pulses: usize = 0;
while let Some((module_name, input, sender)) = process_queue.pop_front() {
match input {
true => high_pulses += 1,
false => low_pulses += 1,
}
if let Some(module) = modules.get_mut(&module_name) {
match module {
Module::FlipFlop { state, dests } => {
if !input {
let flipped = !(*state);
*state = flipped;
for dest in dests {
process_queue.push_back((dest.clone(), state.clone(), module_name.clone()));
}
}
},
Module::Conjunction { state, dests } => {
let stored = state.get_mut(&sender.to_string()).unwrap();
*stored = input;
let mut send = true;
if state.values().all(|x| *x) {
send = false;
}
for dest in dests {
process_queue.push_back((dest.clone(), send, module_name.clone()));
}
},
Module::Broadcast { dests } => {
for dest in dests {
process_queue.push_back((dest.clone(), input, module_name.clone()));
}
},
}
}
}
return (high_pulses, low_pulses)
}
#[aoc(day20, part2)]
fn part2(og_modules: &HashMap<String, Module>) -> usize {
let mut lcm = vec![];
let before = ["tr", "xm", "dr", "nh"];
for module_name in before {
let mut modules = og_modules.clone();
let mut count: usize = 1;
while !push_the_button_part2(&mut modules, module_name.to_string()) {
count += 1;
}
lcm.push(count);
}
println!("{:?}", lcm);
let lcm = lcm.iter()
.cloned()
.reduce(|a, b| a.lcm(&b))
.unwrap();
lcm
}
fn push_the_button_part2(modules: &mut HashMap<String, Module>, to_find: String) -> bool {
let mut process_queue: VecDeque<(String, bool, String)> = VecDeque::new();
process_queue.push_back(("broadcaster".to_string(), false, "".to_string()));
while let Some((module_name, input, sender)) = process_queue.pop_front() {
if module_name == to_find && input == false {
return true
}
if let Some(module) = modules.get_mut(&module_name) {
match module {
Module::FlipFlop { state, dests } => {
if !input {
let flipped = !(*state);
*state = flipped;
for dest in dests {
process_queue.push_back((dest.clone(), state.clone(), module_name.clone()));
}
}
},
Module::Conjunction { state, dests } => {
let stored = state.get_mut(&sender.to_string()).unwrap();
*stored = input;
let mut send = true;
if state.values().all(|x| *x) {
send = false;
}
for dest in dests {
process_queue.push_back((dest.clone(), send, module_name.clone()));
}
},
Module::Broadcast { dests } => {
for dest in dests {
process_queue.push_back((dest.clone(), input, module_name.clone()));
}
},
}
}
}
return false
}
#[cfg(test)]
mod tests {
use super::*;
const EX_1: &str = r"broadcaster -> a, b, c
%a -> b
%b -> c
%c -> inv
&inv -> a";
const EX_2: &str = r"broadcaster -> a
%a -> inv, con
&inv -> b
%b -> con
&con -> rx";
#[test]
fn part1_example1() {
assert_eq!(part1(&parse(EX_1)), 32000000);
}
#[test]
fn part1_example2() {
assert_eq!(part1(&parse(EX_2)), 11687500);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX_2)), 1);
}
}

View File

@ -1,3 +1,4 @@
mod day20;
mod day19; mod day19;
mod day18; mod day18;
mod day17; mod day17;