add 2023/20/1

This commit is contained in:
kageru 2023-12-20 11:27:02 +01:00
parent 702a77a31e
commit b7db7574fa
2 changed files with 209 additions and 0 deletions

58
2023/inputs/day20 Normal file
View File

@ -0,0 +1,58 @@
%xf -> qr
%qr -> bt, zt
%xm -> gp, cq
%zs -> ct
&vg -> lg
%dx -> bt, tz
%tq -> jm
%pr -> gp, pf
&nb -> lg
%tz -> bt
%kj -> fk
%hx -> rb
%xh -> zs, rb
&vc -> lg
%tl -> bn
%bb -> kf, rb
%nn -> xf, bt
%nk -> nn, bt
%kp -> vk
&bt -> tl, nk, pb, xf, vg
%sr -> vs, ml
%sh -> zk
%jm -> ml, kp
%kq -> tl, bt
%vs -> tq, ml
%sv -> dx, bt
%gs -> gp
%kf -> rb, ph
%ct -> rt, rb
%sj -> kj, rb
%kh -> ml
%nt -> gs, gp
%bn -> sv, bt
%lx -> ff, gp
%rt -> hq
%ph -> rb, hx
&ls -> lg
%nv -> xm
%df -> nv
%vk -> tk
%cq -> gp, mq
%hq -> bb
&lg -> rx
%zk -> ml, ps
&ml -> kp, sr, tq, nb, tk, sh, vk
%pf -> gp, nt
%ff -> gp, df
%zt -> pb, bt
broadcaster -> sj, sr, tp, nk
%mq -> pr
&rb -> vc, zs, fk, hq, rt, sj, kj
%pb -> kq
%qz -> ml, kh
%tp -> gp, lx
%tk -> sh
&gp -> df, ls, mq, tp, nv
%fk -> xh
%ps -> qz, ml

151
2023/src/bin/day20.rs Normal file
View File

@ -0,0 +1,151 @@
#![feature(test)]
extern crate test;
use std::collections::VecDeque;
use self::{Node::*, Pulse::*};
use aoc2023::{boilerplate, common::*};
use fnv::FnvHashMap as Map;
const DAY: usize = 20;
type Parsed<'a> = Map<&'a str, (Node<'a>, Vec<&'a str>)>;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum Pulse {
High,
Low,
}
#[derive(Debug, Clone)]
enum Node<'a> {
Broadcaster,
FlipFlop(bool),
Conjunction(Map<&'a str, Pulse>),
}
fn parse_input(raw: &str) -> Parsed {
let mut parsed: Parsed = raw
.lines()
.map(|line| line.split_once(" -> ").unwrap())
.map(|(node, outputs)| {
let (node, name) = match node.as_bytes()[0] {
b'%' => (FlipFlop(false), &node[1..]),
b'&' => (Conjunction(Map::default()), &node[1..]),
_ => (Broadcaster, node),
};
let outputs = outputs.split(", ").collect();
(name, (node, outputs))
})
.collect();
// Now the annoying part: set all inputs of all conjunctions to Low
let mut con_inputs = Map::<&str, Vec<&str>>::default();
for (input, (_, outputs)) in parsed.iter() {
for output in outputs {
if matches!(parsed.get(output), Some((Conjunction(_), _))) {
match con_inputs.get_mut(output) {
Some(v) => v.push(input),
None => {
con_inputs.insert(output, vec![input]);
}
};
}
}
}
for (con, inputs) in con_inputs {
let Some((Conjunction(map), _)) = parsed.get_mut(con) else { unreachable!() };
for i in inputs {
map.insert(i, Low);
}
}
parsed
}
const EMPTY: &Vec<&str> = &Vec::new();
fn process<'a, 'b>(map: &'a mut Parsed<'b>, name: &'b str, pulse: Pulse, src: &'b str) -> (&'b str, Pulse, &'a Vec<&'b str>) {
// println!("{src} ({pulse:?}) -> {name}");
// First modify as needed…
match map.get_mut(name) {
// nodes that don’t lead anywhere, e.g. `output` from the second example
None => return ("", Low, EMPTY),
Some((FlipFlop(_), _)) if pulse == High => return ("", Low, EMPTY),
Some((FlipFlop(b), _)) => *b = !*b,
Some((Conjunction(inputs), _)) => {
inputs.insert(src, pulse);
}
Some(_) => (),
};
// …then match again on an immutable borrow from the map so we can return the output vector.
let (pulse, out) = match (map.get(name).unwrap(), pulse) {
((Broadcaster, out), p) => (p, out),
// Careful: we already flipped the flipflops above, so off gives low and on gives high.
((FlipFlop(false), out), Low) => (Low, out),
((FlipFlop(true), out), Low) => (High, out),
((FlipFlop(_), _), High) => (High, EMPTY),
((Conjunction(inputs), out), _) => {
if inputs.values().all(|&v| v == High) {
(Low, out)
} else {
(High, out)
}
}
};
(name, pulse, out)
}
fn push_button<'a, 'b>(map: &'a mut Parsed<'b>) -> (usize, usize) {
let mut low_count = 1; // initial button
let mut high_count = 0;
let mut queue = VecDeque::new();
queue.push_back(("button", Low, "broadcaster"));
while let Some((src, pulse, output)) = queue.pop_front() {
let (src, pulse, outputs) = process(map, output, pulse, src);
for output in outputs {
queue.push_back((src, pulse, output));
match pulse {
Low => low_count += 1,
High => high_count += 1,
}
}
}
(low_count, high_count)
}
fn part1<'a>(map: &Parsed) -> usize {
let mut map = map.to_owned();
let (mut low, mut high) = (0, 0);
for _ in 0..1000 {
let (new_low, new_high) = push_button(&mut map);
low += new_low;
high += new_high;
}
low * high
}
fn part2(parsed: &Parsed) -> usize {
unimplemented!()
}
boilerplate! {
TEST_INPUT == "\
broadcaster -> a, b, c
%a -> b
%b -> c
%c -> inv
&inv -> a",
TEST_INPUT_2 == "\
broadcaster -> a
%a -> inv, con
&inv -> b
%b -> con
&con -> output"
for tests: {
part1: {
TEST_INPUT => 32000000,
TEST_INPUT_2 => 11687500,
},
part2: { TEST_INPUT => 0 },
},
bench1 == 929810733,
bench2 == 0,
bench_parse: Map::len => 58,
}