1
0
Fork 0

day20 solution

main
Andrew Coleman 2024-01-11 15:07:13 -05:00
parent 05861a06b0
commit 59e06d73eb
2 changed files with 226 additions and 0 deletions

225
2023/src/day20.rs Normal file
View File

@ -0,0 +1,225 @@
use aoc_runner_derive::aoc;
use num::integer::lcm;
use std::collections::{HashMap, VecDeque};
#[derive(Eq, PartialEq)]
enum MachineType {
Broadcaster,
FlipFlop,
Conjuction,
}
struct Machine {
name: String,
mt: MachineType,
neighbors: Vec<String>,
states: HashMap<String, bool>,
}
fn pulse(
machine: &mut Machine,
signal: bool,
source: String,
queue: &mut VecDeque<(String, String, bool)>,
) {
match machine.mt {
MachineType::Broadcaster => {
for n in machine.neighbors.iter() {
queue.push_back((n.to_string(), machine.name.clone(), signal));
}
}
MachineType::FlipFlop => {
if signal {
return;
}
machine
.states
.entry(machine.name.clone())
.and_modify(|s| *s = !*s);
let &signal = machine.states.get(&machine.name).unwrap();
for n in machine.neighbors.iter() {
queue.push_back((n.to_string(), machine.name.clone(), signal));
}
}
MachineType::Conjuction => {
machine
.states
.entry(source)
.and_modify(|s| *s = signal)
.or_insert(signal);
let mut next = false;
for (_name, &t) in machine.states.iter() {
if !t {
next = true;
break;
}
}
for n in machine.neighbors.iter() {
queue.push_back((n.to_string(), machine.name.clone(), next));
}
}
}
}
fn parse<'a>(input: &str) -> HashMap<String, Machine> {
let mut r: HashMap<String, Machine> = HashMap::new();
let mut c: Vec<String> = vec![];
for line in input.lines() {
if line.is_empty() {
continue;
}
let lparts = line.split(" -> ").collect::<Vec<_>>();
let name = if lparts[0].starts_with("&") {
lparts[0].strip_prefix("&").unwrap()
} else if lparts[0].starts_with("%") {
lparts[0].strip_prefix("%").unwrap()
} else {
lparts[0]
};
let neighbors = lparts[1]
.split(", ")
.map(|s| s.to_string())
.collect::<Vec<_>>();
if name == "broadcaster" {
r.insert(
name.to_string(),
Machine {
name: name.to_string(),
mt: MachineType::Broadcaster,
neighbors,
states: HashMap::with_capacity(0),
},
);
} else if line.starts_with("&") {
c.push(name.to_string());
r.insert(
name.to_string(),
Machine {
name: name.to_string(),
mt: MachineType::Conjuction,
neighbors,
states: HashMap::new(),
},
);
} else if line.starts_with("%") {
r.insert(
name.to_string(),
Machine {
name: name.to_string(),
mt: MachineType::FlipFlop,
neighbors,
states: HashMap::from([(name.to_string(), false)]),
},
);
}
}
let mut c2: HashMap<String, Vec<String>> = HashMap::new();
for (name, node) in r.iter() {
for n in node.neighbors.iter() {
if c.contains(n) {
c2.entry(n.clone())
.and_modify(|t| t.push(name.clone()))
.or_insert(vec![name.clone()]);
}
}
}
for (name, inputs) in c2.iter() {
let node = r.get_mut(name).unwrap();
for i in inputs.iter() {
node.states.entry(i.clone()).or_insert(false);
}
}
r
}
#[aoc(day20, part1)]
fn part1(input: &str) -> u64 {
let mut parts = parse(input);
let mut queue: VecDeque<(String, String, bool)> = VecDeque::new();
let mut high = 0;
let mut low = 0;
for _ in 0..1000 {
queue.push_back((String::from("broadcaster"), String::from("button"), false));
while let Some((dest, source, signal)) = queue.pop_front() {
if signal {
high += 1;
} else {
low += 1;
}
if let Some(mut node) = parts.get_mut(&dest) {
pulse(&mut node, signal, source, &mut queue);
}
}
}
high * low
}
#[aoc(day20, part2)]
fn part2(input: &str) -> u64 {
let mut parts = parse(input);
let mut queue: VecDeque<(String, String, bool)> = VecDeque::new();
let mut last_cons = vec![
String::from("zl"),
String::from("xn"),
String::from("qn"),
String::from("xf"),
];
let mut con_indexes: Vec<u64> = vec![];
let mut c = 1;
for i in 0..10000 {
queue.push_back((String::from("broadcaster"), String::from("button"), false));
while let Some((dest, source, signal)) = queue.pop_front() {
if signal {
if let Some(index) = last_cons.iter().position(|s| *s == source) {
last_cons.remove(index);
con_indexes.push(i + 1);
c = lcm(i + 1, c);
if last_cons.is_empty() {
return c;
}
}
}
if let Some(mut node) = parts.get_mut(&dest) {
pulse(&mut node, signal, source, &mut queue);
}
}
}
0
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE_DATA: &'static str = r#"broadcaster -> a, b, c
%a -> b
%b -> c
%c -> inv
&inv -> a
"#;
const SAMPLE_DATA2: &'static str = r#"broadcaster -> a
%a -> inv, con
&inv -> b
%b -> con
&con -> output"#;
#[test]
fn sample_data() {
assert_eq!(part1(&SAMPLE_DATA), 32000000);
// assert_eq!(part2(&SAMPLE_DATA), 71503);
}
#[test]
fn sample_data2() {
assert_eq!(part1(&SAMPLE_DATA2), 11687500);
}
}

View File

@ -19,5 +19,6 @@ mod day16;
mod day17;
mod day18;
mod day19;
mod day20;
aoc_lib! { year = 2023 }