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