2023-12-20 04:48:21 -06:00
|
|
|
:- use_module(library(pio)).
|
|
|
|
:- use_module(library(dcg/basics)).
|
|
|
|
:- initialization(main, main).
|
|
|
|
|
|
|
|
main([FileName|_]) :-
|
|
|
|
input(FileName, Circuit),
|
2023-12-20 04:49:40 -06:00
|
|
|
run1000(Circuit, Answer),
|
|
|
|
write(Answer), nl.
|
2023-12-20 04:48:21 -06:00
|
|
|
|
|
|
|
% part1
|
|
|
|
run1000(Circuit, Answer) :-
|
|
|
|
length(Range, 1000),
|
|
|
|
foldl(
|
|
|
|
{Circuit}/[_, In-Lin-Hin, Out-Lout-Hout]>>(
|
|
|
|
run([button-l-broadcaster], In, Out, L-H),
|
|
|
|
Lout is L+Lin, Hout is H+Hin),
|
|
|
|
Range, Circuit-0-0, _-Lx-Hx),
|
|
|
|
Answer is Lx*Hx.
|
|
|
|
|
|
|
|
% code to run one circuit
|
|
|
|
run([], Circuit, Circuit, 0-0).
|
|
|
|
run([Src-Level-Target|Pulses], CircuitIn, CircuitOut, Ls-Hs) :-
|
|
|
|
( member(Type-Target-State-Dests, CircuitIn)
|
|
|
|
-> /*write([Src, Level, Target]), write(" -> "),
|
|
|
|
write([Type, Target, State, Dests]), write(" = "),*/
|
|
|
|
call(Type, Src, Level, State, NewState, Out),
|
|
|
|
send(Target, Out, Dests, AdditionalPulses),
|
|
|
|
% write(NewState-AdditionalPulses), nl,
|
|
|
|
select(Type-Target-State-Dests, CircuitIn,
|
|
|
|
Type-Target-NewState-Dests, Circuit1),
|
|
|
|
append(Pulses, AdditionalPulses, NewPulses),
|
|
|
|
run(NewPulses, Circuit1, CircuitOut, NextLs-NextHs)
|
|
|
|
; run(Pulses, CircuitIn, CircuitOut, NextLs-NextHs)
|
|
|
|
),
|
|
|
|
call(Level, NextLs-NextHs, Ls-Hs).
|
|
|
|
|
|
|
|
l(L1s-H1s, L2s-H1s) :- L2s is L1s + 1.
|
|
|
|
h(L1s-H1s, L1s-H2s) :- H2s is H1s + 1.
|
|
|
|
|
|
|
|
broadcaster(_, l, x, x, l).
|
|
|
|
|
|
|
|
ff(_, h, State, State, none).
|
|
|
|
ff(_, l, 0, 1, h).
|
|
|
|
ff(_, l, 1, 0, l).
|
|
|
|
|
|
|
|
nand(Src, Level, State, NewState, OutLevel) :-
|
|
|
|
select(Src-_, State, Src-Level, NewState),
|
|
|
|
(maplist([_-h]>>(true), NewState) -> OutLevel = l; OutLevel = h).
|
|
|
|
|
|
|
|
send(_, none, _, []).
|
|
|
|
send(From, Level, Dests, Pulses) :-
|
|
|
|
\+ Level = none,
|
|
|
|
maplist({Level}/[Dest, From-Level-Dest]>>(true), Dests, Pulses).
|
|
|
|
|
|
|
|
% input initialization
|
|
|
|
prefill_nands([], Circuit, Circuit).
|
|
|
|
prefill_nands([_-Src-_-Dests|Nodes], CircuitIn, CircuitOut) :-
|
|
|
|
convlist(
|
|
|
|
{CircuitIn}/[Dest, Dest]>>(member(nand-Dest-_-_, CircuitIn)),
|
|
|
|
Dests, NandDests),
|
|
|
|
foldl(fill_one_nand(Src), NandDests, CircuitIn, Circuit1),
|
|
|
|
prefill_nands(Nodes, Circuit1, CircuitOut).
|
|
|
|
|
|
|
|
fill_one_nand(Src, Nand, CIn, COut) :-
|
|
|
|
select(nand-Nand-State-Dests, CIn, nand-Nand-[Src-l|State]-Dests, COut).
|
|
|
|
|
|
|
|
% input parsing stuff below
|
|
|
|
input(FileName, Circuit) :-
|
|
|
|
phrase_from_file(modules(EmptyCircuit), FileName),
|
|
|
|
prefill_nands(EmptyCircuit, EmptyCircuit, Circuit).
|
|
|
|
|
|
|
|
modules([]) --> eos, !.
|
|
|
|
modules([Module|Modules]) --> module(Module), "\n", modules(Modules).
|
|
|
|
|
|
|
|
module(broadcaster-broadcaster-x-Dests) --> "broadcaster -> ", dests(Dests).
|
|
|
|
module(ff-Name-0-Dests) --> "%", node(Name), " -> ", dests(Dests).
|
|
|
|
module(nand-Name-[]-Dests) --> "&", node(Name), " -> ", dests(Dests).
|
|
|
|
|
|
|
|
dests([Dest]) --> node(Dest).
|
|
|
|
dests([Dest|Dests]) --> node(Dest), ", ", dests(Dests).
|
|
|
|
|
|
|
|
node(Name) --> string_without(", \n", NameStr), {atom_codes(Name, NameStr)}.
|