125 lines
3.4 KiB
Prolog
125 lines
3.4 KiB
Prolog
chars_digits([], []).
|
|
chars_digits([A|As], [B|Bs]) :-
|
|
char_type(A, digit(B)),
|
|
chars_digits(As, Bs).
|
|
|
|
read_file(Stream, []) :-
|
|
at_end_of_stream(Stream).
|
|
read_file(Stream, [X|Xs]) :-
|
|
\+ at_end_of_stream(Stream),
|
|
read_line_to_codes(Stream, C),
|
|
chars_digits(C, X),
|
|
read_file(Stream, Xs).
|
|
|
|
main :-
|
|
open('../input/09', read, Stream),
|
|
read_file(Stream, Lines), !,
|
|
close(Stream),
|
|
low_points(Lines, Res),
|
|
basins(Lines, Res, B0),
|
|
msort(B0, B1),
|
|
reverse(B1, [B2,B3,B4|_]),
|
|
X is B2 * B3 * B4,
|
|
print(X).
|
|
|
|
basins(_, [], []).
|
|
basins(A, [P|Ps], [B|Bs]) :-
|
|
points_high_neighbors_all(A, [P], Bas),
|
|
length(Bas, B),
|
|
basins(A, Ps, Bs).
|
|
|
|
fetch_value(A, [X, Y], V) :-
|
|
nth0(Y, A, R),
|
|
nth0(X, R, V).
|
|
|
|
fetch_values(_, [], []).
|
|
fetch_values(A, [P|Ps], [V|Vs]) :-
|
|
fetch_value(A, P, V),
|
|
fetch_values(A, Ps, Vs).
|
|
|
|
low_point(A, X, Y) :-
|
|
valid_paths(A, X, Y, P),
|
|
fetch_values(A, P, V),
|
|
fetch_value(A, [X, Y], V0),
|
|
min_list(V, V1),
|
|
V1 > V0.
|
|
|
|
low_points_rest([A|As], X, Y, Rs) :-
|
|
length(A, W),
|
|
(
|
|
(X > 0, X0 is X - 1, low_points([A|As], X0, Y, Rs));
|
|
(X = 0, Y > 0, X0 is W - 1, Y0 is Y - 1, low_points([A|As], X0, Y0, Rs))
|
|
).
|
|
|
|
low_points(A, 0, 0, [[0, 0]]) :- low_point(A, 0, 0).
|
|
low_points(A, 0, 0, []) :- \+ low_point(A, 0, 0).
|
|
low_points(A, X, Y, [[X, Y]|Rs]) :-
|
|
low_point(A, X, Y),
|
|
low_points_rest(A, X, Y, Rs).
|
|
low_points(A, X, Y, Rs) :-
|
|
low_points_rest(A, X, Y, Rs).
|
|
low_points([A|As], Ret) :-
|
|
length([A|As], H),
|
|
length(A, W),
|
|
X0 is W - 1,
|
|
Y0 is H - 1,
|
|
low_points([A|As], X0, Y0, Ret).
|
|
|
|
high_neighbor(A, [X1, Y1], [X0, Y0]) :-
|
|
nth0(Y1, A, R1),
|
|
nth0(Y0, A, R0),
|
|
nth0(X1, R1, A1),
|
|
A1 =\= 9,
|
|
nth0(X0, R0, A0),
|
|
A1 > A0.
|
|
|
|
high_neighbors(A, X, Y, P) :-
|
|
valid_paths(A, X, Y, W),
|
|
setof(Q, (member(Q, W), high_neighbor(A, Q, [X, Y])), P).
|
|
high_neighbors(A, X, Y, []) :-
|
|
valid_paths(A, X, Y, W),
|
|
\+ setof(Q, (member(Q, W), high_neighbor(A, Q, [X, Y])), _).
|
|
|
|
points_high_neighbors(_, [], []).
|
|
points_high_neighbors(A, [[X,Y]|Ps], N) :-
|
|
points_high_neighbors(A, Ps, N1),
|
|
high_neighbors(A, X, Y, N0),
|
|
append(N0, N1, N2),
|
|
sort(N2, N).
|
|
|
|
points_high_neighbors_all(A, P, P) :-
|
|
points_high_neighbors(A, P, []).
|
|
points_high_neighbors_all(A, P, N) :-
|
|
points_high_neighbors(A, P, N1),
|
|
points_high_neighbors_all(A, N1, N2),
|
|
append(P, N2, N3),
|
|
sort(N3, N).
|
|
|
|
in_bounds(W, H, X, Y) :-
|
|
X >= 0, X < W,
|
|
Y >= 0, Y < H.
|
|
|
|
valid_paths([A|As], X, Y, P) :-
|
|
length([A|As], H),
|
|
length(A, W),
|
|
valid_paths(W, H, X, Y, P).
|
|
valid_paths(W, H, X, Y, [P|Ps]) :-
|
|
X0 is X - 1, in_bounds(W, H, X0, Y), P = [X0, Y], valid_paths_1(W, H, X, Y, Ps).
|
|
valid_paths(W, H, X, Y, Ps) :-
|
|
X0 is X - 1,
|
|
\+ in_bounds(W, H, X0, Y),
|
|
valid_paths_1(W, H, X, Y, Ps).
|
|
valid_paths_1(W, H, X, Y, [P|Ps]) :-
|
|
X0 is X + 1, in_bounds(W, H, X0, Y), P = [X0, Y], valid_paths_2(W, H, X, Y, Ps).
|
|
valid_paths_1(W, H, X, Y, Ps) :-
|
|
X0 is X + 1, \+ in_bounds(W, H, X0, Y), valid_paths_2(W, H, X, Y, Ps).
|
|
valid_paths_2(W, H, X, Y, [P|Ps]) :-
|
|
Y0 is Y - 1, in_bounds(W, H, X, Y0), P = [X, Y0], valid_paths_3(W, H, X, Y, Ps).
|
|
valid_paths_2(W, H, X, Y, Ps) :-
|
|
Y0 is Y - 1, \+ in_bounds(W, H, X, Y0), valid_paths_3(W, H, X, Y, Ps).
|
|
valid_paths_3(W, H, X, Y, [P]) :-
|
|
Y0 is Y + 1, in_bounds(W, H, X, Y0), P = [X, Y0].
|
|
valid_paths_3(W, H, X, Y, []) :-
|
|
Y0 is Y + 1, \+ in_bounds(W, H, X, Y0).
|
|
|