Day 6

2020-01-25

Problem

I decided to go the route of using a single inductive predicate to solve the problem. union/2 and intersection/2 were useful, but I did have to modify my predicate with an extra rule to handle the null set, else the sum of group answers be zero. There was also a base case that was missing (and had missed when I initially posted this).

One thing that has hampered my learning progress in Prolog in the past was my insistence on writing most predicates from scratch. Using standard library functions is 100% the way to go when trying to learn something new. Why write something from scratch when you can build from a robust toolset? Once I got the hang of the common patterns, I think I’ll be able to go back to the Ninety-Nine Prolog Problems with more appreciation.

Solution

process([], X, [X]).
process([""|T], X, [X|Res]):-
    process(T, [], Res).
process([H|T], Acc, Res):-
    string_chars(H, Items),
    union(Items, Acc, Acc2),
    process(T, Acc2, Res).

main(Input, Output):-
    split_string(Input, '\n', '\s', Lines),
    process(Lines,[], Groups),
    maplist(length, Groups, Counts),
    sumlist(Counts, Output).

% the same as process, except an intersection instead of union
% however, it needs an extra rule when the intitial set is null, and
% we need to differentiate between the first and last intersection in a set
process2([], _, X, [X]).
process2([H|T], 0, [], Res):-
    string_chars(H, Items),
    process2(T, 1, Items, Res).
process2([""|T], _, X, [X|Res]):-
    process2(T, 0, [], Res).
process2([H|T], C, Acc, Res):-
    string_chars(H, Items),
    intersection(Items, Acc, Acc2),
    C2 is C + 1,
    process2(T, C2, Acc2, Res).

main2(Input, Output):-
    split_string(Input, '\n', '\s', Lines),
    process2(Lines, 0, [], Groups),
    maplist(length, Groups, Counts),
    sumlist(Counts, Output).

sample("abc

a
b
c

ab
ac

a
a
a
a

b").

Index