:- module day4. :- interface. :- import_module basics. :- import_module univ. :- pred run(part::in, lines::in, univ::out) is cc_multi. :- pred number(int::out, chars::in, chars::out) is semidet. :- implementation. :- import_module int. :- import_module char. :- import_module string. :- import_module list. :- type ranges ---> r(int, int, int, int). number(N) --> digits(S), {to_int(from_char_list(S), N)}. :- pred digits(chars::out, chars::in, chars::out) is semidet. digits([C | Cs]) --> [C], {is_digit(C)}, (if digits(Cs2) then {Cs = Cs2} else {Cs = []}). :- pred int_pair(int::out, int::out, chars::in, chars::out) is semidet. int_pair(A, B) --> number(A), ['-'], number(B). :- pred ranges(ranges::out, chars::in, chars::out) is semidet. ranges(r(A, B, C, D)) --> int_pair(A, B), [','], int_pair(C, D). :- pred ranges(string::in, ranges::out) is det. ranges(Str, R) :- if ranges(R2, to_char_list(Str), []) then R = R2 else die("invalid line: ""%s""", [s(Str)]). :- pred all_overlap(ranges::in) is semidet. all_overlap(r(A, B, C, D)) :- C >= A, D =< B ; D >= B, C =< A. :- pred any_overlap(ranges::in) is semidet. any_overlap(r(A, B, C, D)) :- A =< C, B >= C ; C =< A, D >= A. :- pred go(pred(ranges)::(pred(in) is semidet), lines::in, int::out) is det. go(P, Lines, Out) :- map(ranges, Lines, Ranges), filter(P, Ranges, Overlaps), length(Overlaps, Out). :- pragma no_determinism_warning(run/3). run(one, Lines, univ(Out)) :- go(all_overlap, Lines, Out). run(two, Lines, univ(Out)) :- go(any_overlap, Lines, Out).