Skip to content

Instantly share code, notes, and snippets.

@p-a
Last active December 20, 2023 22:33
Show Gist options
  • Save p-a/b02154c0aa14e9140aab23d77f3ffac0 to your computer and use it in GitHub Desktop.
Save p-a/b02154c0aa14e9140aab23d77f3ffac0 to your computer and use it in GitHub Desktop.
AoC 2023 Day 20
import { product } from "../../lib/arrays.js";
import { lcm } from "../../lib/math.js";
import { pipe } from "../../lib/utils.js";
const createModule = (module, dst, modules) => {
const m = {
queue: [],
outputs: dst,
nextState: () => m.queue.shift()[0],
pulse: ([p, src]) => {
m.queue.push([p, src]);
const next = m.nextState();
if (next === undefined) return [];
return m.outputs.map(d => [next, d]);
},
};
if (module[0] === "%") {
module = module.slice(1);
m.state = false;
m.nextState = () => {
if (m.queue.shift()[0]) return undefined;
m.state = !m.state;
return m.state;
};
} else if (module[0] === "&") {
module = module.slice(1);
m.mem = new Map(
modules
.filter(([, dst]) => dst.includes(module))
.map(([n]) => [
"&%".includes(n[0]) ? n.slice(1) : n,
false,
])
);
m.nextState = () => {
const [p, src] = m.queue.shift();
m.mem.set(src, p);
return [...m.mem.values()].some(v => !v);
};
}
return [module, m];
};
const parse = input =>
new Map(
input
.split("\n")
.concat("button -> broadcaster")
.map(row => row.split(" -> "))
.map(([m, dst]) => [m, dst.split(", ")])
.map(([m, dst], _, self) =>
createModule(m, dst, self)
)
);
const countPulses = times => system => {
const pulses = [];
const pulseCounts = [0, 0];
let i = times;
while (i--) {
pulses.push([false, "button", "elf"]);
while (pulses.length) {
const [p, curr, src] = pulses.shift();
pulses.push(
...(system
.get(curr)
?.pulse([p, src])
.filter(([p]) => ++pulseCounts[p ? 1 : 0])
.map(next => [...next, curr]) ?? [])
);
}
}
return pulseCounts;
};
const untilRX = system => {
const gate = [...system.values()].find(m =>
m.outputs.some(v => v === "rx")
);
const pins = new Set([...gate.mem].map(([k]) => k));
const pulseCounts = [];
const pulses = [];
let i = 0;
while (pins.size) {
i++;
pulses.push([false, "button", "elf"]);
while (pulses.length) {
const [p, curr, src] = pulses.shift();
if (p && pins.has(src)) {
pins.delete(src);
pulseCounts.push(i);
}
pulses.push(
...(system
.get(curr)
?.pulse([p, src])
.map(next => [...next, curr]) ?? [])
);
}
}
return pulseCounts;
};
const cycleLength = pulseCounts =>
pulseCounts.reduce((acc, v) => lcm(acc, v));
export const part1 = pipe(
parse,
countPulses(1000),
product
);
export const part2 = pipe(parse, untilRX, cycleLength);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment