aoc23/08/part2.cheese.pl
2023-12-08 17:10:35 -08:00

86 lines
2.8 KiB
Prolog

:- table direction_loop/1.
:- op(700, xfx, l).
:- op(700, xfx, r).
From l To :- From to To-_.
From r To :- From to _-To.
% We want to satisfy {Offset_i + Stride_i*Loops_i + Sub_ij = Z}
answer() :-
starts(Starts),
maplist([S, S-Off-Stride-Loop]>>(zloop([], S, 0, [], Off, Stride, Loop)),
Starts, Events),
maplist(split, Events, EquationSets),
pick(EquationSets, Eqs),
index1(Eqs, IEqs),
write('Find N_i such that: '),
foldl(write_eq, IEqs, _, _),
write('Z\n'),
% foldl(satisfy, EquationsN, _, Answer),
true.
write_eq(I-(A-B-C), _, _) :-
writef('%t + %t*N%t ', [A, B, I]),
(C =\= 0 -> writef('+ %t ', [C]); true),
write('= ').
% satisfy((A-B-C), N, Z, Z) :- natnum(N), Z is A + B*N + C.
% [mma-2-2-[0-mmz], nna-3-6-[0-nnz, 3-nnz]] -> [2-2-0, 3-6-0, 3-6-3]
split(_-_-_-[], []).
split(A-Offset-Stride-[Sub-_ | Loop], [Offset-Stride-Sub | Cdr]) :-
split(A-Offset-Stride-Loop, Cdr).
% Everything above this is not needed to get the input answer
% starts(Starts),
% maplist([S, S-Off-Stride-Loop]>>(zloop([], S, 0, [], Off, Stride, Loop)),
% Starts, Loops).
% then find the LCD of the strides (which are equal to offsets).
zloop(_, _, _, Zs, Offset, Stride, Loop) :-
Zs = [FirstZIndex-Z | _], reverse(Zs, [LastZIndex-Z | ReversedZs]),
DeltaZ is LastZIndex - FirstZIndex, DeltaZ =\= 0,
direction_len(Len),
divmod(DeltaZ, Len, _, 0),
Offset = FirstZIndex, Stride = DeltaZ,
foldl([Idx-Z, NewIdx-Z, Off, Off]>>(NewIdx is Idx - Off),
ReversedZs, ReversedLoop, Offset, _),
reverse(ReversedLoop, Loop),
!.
zloop(Directions, Node, Index, Zs, Offset, Stride, Loop) :-
( is_end(Node)
-> append(Zs, [Index-Node], NewZs)
; NewZs = Zs
),
next_step(Directions, Move, Remain),
G =.. [Move, Node, To], G,
NewIndex is Index + 1,
zloop(Remain, To, NewIndex, NewZs, Offset, Stride, Loop).
starts(Starts) :- findall(X, X to _, Nodes), include(is_start, Nodes, Starts).
is_start(Node) :- atom_chars(Node, [_, _, a]).
is_end(Node) :- atom_chars(Node, [_, _, z]).
next_step([Move | Remain], Move, Remain).
next_step([], Move, Remain) :- direction_list([Move | Remain]).
direction_list(Dir) :- direction(Str), atom_chars(Str, Dir).
direction_len(Len) :- direction_list(D), length(D, Len).
% pick([[1,2,3], [4], [5,6]], X). X = [1,4,5]; X = [1,4,6]; X = [2,4,5]; ...
pick(ListOfLists, Items) :-
maplist([SubList, X]>>(member(X, SubList)), ListOfLists, Items).
index1(L, IL) :- reverse(L, RL), index1r(RL, IRL), reverse(IRL, IL).
index1r([X], [1-X]).
index1r([X, Y | Cdr], [NextI-X, I-Y | ICdr]) :-
index1r([Y | Cdr], [I-Y | ICdr]), NextI is I + 1.
same_elements([_]).
same_elements([X-_, Y-Z2 | Cdr]) :- X =:= Y, same_elements([Y-Z2 | Cdr]).
natnum(0).
natnum(N) :- natnum(N0), N is N0 + 1.