55 lines
1.5 KiB
Mathematica
55 lines
1.5 KiB
Mathematica
|
:- module day4.
|
||
|
:- 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.
|
||
|
|
||
|
:- type ranges ---> r(int, int, int, int).
|
||
|
|
||
|
:- pred number(int::out, chars::in, chars::out) is semidet.
|
||
|
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),
|
||
|
list(string)::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).
|