day20 solution
parent
05861a06b0
commit
59e06d73eb
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,5 +19,6 @@ mod day16;
|
||||||
mod day17;
|
mod day17;
|
||||||
mod day18;
|
mod day18;
|
||||||
mod day19;
|
mod day19;
|
||||||
|
mod day20;
|
||||||
|
|
||||||
aoc_lib! { year = 2023 }
|
aoc_lib! { year = 2023 }
|
||||||
|
|
Loading…
Reference in New Issue