add 2023/20/1
This commit is contained in:
parent
702a77a31e
commit
b7db7574fa
|
@ -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
|
|
@ -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,
|
||||
}
|
Loading…
Reference in New Issue
Block a user