Hello all, AoC is upon us again I’ve chosen Prolog again this year, and now that I have a bit of experience with it, it is a delight to be tinkering again.
I’m keeping my solutions here, with a special effort this year to write code using declarative idioms unique to the Prolog approach.
Please share your thoughts and solutions!
Here are the first couple days:
Day 1
This uses re_foldl/6 and a nth0/3 index matching trick I saw @jan do once to solve both parts concisely.
acc(_{0:_, l1:X, l2:Y}, Xs-Ys, [X|Xs]-[Y|Ys]).
solve(In, Part1, Part2) :-
read_file_to_string(In, S, []),
re_foldl(acc, "(?<l1_I>\\d+) +(?<l2_I>\\d+)", S, []-[], Xs_-Ys_, []),
maplist(msort, [Xs_,Ys_], [Xs,Ys]),
aggregate_all(sum(abs(X-Y)), (nth0(Idx,Xs,X), nth0(Idx,Ys,Y)), Part1),
aggregate_all(sum(A*C), (member(A,Xs), aggregate_all(count, member(A,Ys), C)), Part2).
Day 2
This uses the magical append/3 and select/3 predicates to concisely and declaratively implement the safety tests.
safe(Xs) :-
Xs \= [],
\+ (append(_, [A,B|_], Xs), A>=B, append(_, [C,D|_], Xs), D>=C),
\+ (append(_, [A,B|_], Xs), (abs(A-B) =:= 0; abs(A-B) > 3)).
mod_then_safe(Xs) :- member(X, Xs), select(X, Xs, Ys), safe(Ys), !.
acc(_{0:_,n:X}, Xs, [X|Xs]).
nums(S,Xs) :- re_foldl(acc, "(?<n_I>\\d+)", S, [], Xs, []).
solve(In, Part1, Part2) :-
read_file_to_string(In, S, []),
split_string(S, "\n", "", Ss),
maplist(nums, Ss, Xs),
aggregate_all(count, (member(X, Xs), safe(X)), Part1),
aggregate_all(count, (member(X, Xs), mod_then_safe(X)), Part2).