2022-12-03 00:33:45 -05:00
|
|
|
:- module day3.
|
|
|
|
:- interface.
|
|
|
|
:- import_module basics.
|
|
|
|
:- import_module list.
|
|
|
|
:- import_module univ.
|
|
|
|
|
|
|
|
:- pred run(part::in, list(string)::in, univ::out) is cc_multi.
|
|
|
|
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
|
|
:- import_module char.
|
|
|
|
:- import_module string.
|
|
|
|
|
2022-12-03 05:24:35 -05:00
|
|
|
:- pred split(string::in, string::out, string::out) is semidet.
|
2022-12-03 00:33:45 -05:00
|
|
|
split(X, L, H) :-
|
|
|
|
Len = length(X), even(Len),
|
2022-12-03 05:24:35 -05:00
|
|
|
split(X, Len / 2, L, H).
|
2022-12-03 00:33:45 -05:00
|
|
|
|
2022-12-03 05:24:35 -05:00
|
|
|
:- pred member(char::out, string::in) is nondet.
|
|
|
|
member(C, S) :-
|
|
|
|
nondet_int_in_range(0, length(S) - 1, I),
|
|
|
|
index(S, I, C).
|
|
|
|
|
|
|
|
:- pred common(list(string)::in, char::out) is nondet.
|
2022-12-03 00:33:45 -05:00
|
|
|
common([S | Ss], C) :- member(C, S), (Ss = [] ; common(Ss, C)).
|
|
|
|
|
2022-12-03 00:55:52 -05:00
|
|
|
:- func prio(char) = int.
|
|
|
|
prio(C) = I :-
|
2022-12-03 00:33:45 -05:00
|
|
|
if is_lower(C) then
|
|
|
|
I = to_int(C) - to_int('a') + 1
|
|
|
|
else
|
|
|
|
I = to_int(C) - to_int('A') + 27.
|
|
|
|
|
2022-12-03 00:59:06 -05:00
|
|
|
|
|
|
|
:- type triple(T) ---> t(T, T, T).
|
|
|
|
|
|
|
|
:- pred threes(list(T)::in, list(triple(T))::out) is semidet.
|
2022-12-03 05:38:14 -05:00
|
|
|
threes(In, Out) :- threes(Out, In, []).
|
|
|
|
|
|
|
|
:- pred threes(list(triple(T))::out, list(T)::in, list(T)::out) is semidet.
|
|
|
|
threes([]) --> =([]).
|
|
|
|
threes([t(X, Y, Z) | Rest]) --> [X, Y, Z], threes(Rest).
|
2022-12-03 00:33:45 -05:00
|
|
|
|
|
|
|
|
|
|
|
:- pred go1(string::in, int::out) is cc_multi.
|
|
|
|
go1(Line, Out) :-
|
2022-12-03 05:24:35 -05:00
|
|
|
if split(Line, Fst, Snd),
|
2022-12-03 00:33:45 -05:00
|
|
|
common([Fst, Snd], C)
|
|
|
|
then
|
2022-12-03 00:55:52 -05:00
|
|
|
Out = prio(C)
|
2022-12-03 00:33:45 -05:00
|
|
|
else
|
|
|
|
die("invalid line: ""%s""", [s(Line)]).
|
|
|
|
|
|
|
|
|
2022-12-03 00:59:06 -05:00
|
|
|
:- pred go2(triple(string)::in, int::out) is cc_multi.
|
|
|
|
go2(t(X, Y, Z), Prio) :-
|
2022-12-03 05:24:35 -05:00
|
|
|
if common([X, Y, Z], C) then
|
2022-12-03 00:55:52 -05:00
|
|
|
Prio = prio(C)
|
2022-12-03 00:33:45 -05:00
|
|
|
else
|
2022-12-03 05:24:35 -05:00
|
|
|
die("no item in common in:\n - %s\n - %s\n - %s", [s(X), s(Y), s(Z)]).
|
2022-12-03 00:33:45 -05:00
|
|
|
|
|
|
|
|
2022-12-03 00:55:52 -05:00
|
|
|
run(one, Lines, univ(sum(Prios))) :-
|
|
|
|
map(go1, Lines, Prios).
|
|
|
|
run(two, Lines, univ(sum(Prios))) :-
|
2022-12-03 00:33:45 -05:00
|
|
|
if threes(Lines, Groups) then
|
2022-12-03 00:55:52 -05:00
|
|
|
map(go2, Groups, Prios)
|
2022-12-03 00:33:45 -05:00
|
|
|
else
|
2022-12-03 05:38:14 -05:00
|
|
|
die("%d lines given (not a multiple of 3)", [i(length(Lines))]).
|