parse_line(S, [A, B, C, D]) :- split_string(S, " ->", "", [X, _, _, _, Y]), split_string(X, ",", "", [A0, B0]), split_string(Y, ",", "", [C0, D0]), number_string(A, A0), number_string(B, B0), number_string(C, C0), number_string(D, D0). read_file(Stream, []) :- at_end_of_stream(Stream). read_file(Stream, [X|L]) :- \+ at_end_of_stream(Stream), read_line_to_codes(Stream, C), string_chars(S, C), parse_line(S, X), read_file(Stream, L). main :- open('../input/05', read, Stream), read_file(Stream, Lines), !, close(Stream), minmax_seq(Lines, X0, X1, Y0, Y1), C = [X0 - 10, X1 + 10, Y0 - 10, Y1 + 10], filter_hor_vert(Lines, L0), convert_coords(L0, C, L1), create_grid(C, G), !, mark_lines(G, L1, G1), !, count_ge2(G1, W), print(W). filter_hor_vert([], []). filter_hor_vert([A|As], [A|Bs]) :- (horizontal(A); vertical(A)), filter_hor_vert(As, Bs). filter_hor_vert([A|As], B) :- \+ horizontal(A), \+ vertical(A), filter_hor_vert(As, B). convert_coords([], _, []). convert_coords([[A0,A1,A2,A3]|As], [X0, X1, Y0, Y1], [[B0,B1,B2,B3]|Bs]) :- C0 is A0 - X0, C1 is A1 - Y0, C2 is A2 - X0, C3 is A3 - Y0, B0 is min(C0, C2), B2 is max(C0, C2), B1 is min(C1, C3), B3 is max(C1, C3), convert_coords(As, [X0, X1, Y0, Y1], Bs). create_row(0, []). create_row(X, [0|As]) :- X > 0, X1 is X - 1, create_row(X1, As). create_grid([X0, X1, Y0, Y1], A) :- create_grid(X1 - X0 + 1, Y1 - Y0 + 1, A). create_grid(_, 0, []). create_grid(X, Y, [A|As]) :- Y > 0, Y1 is Y - 1, create_row(X, A), create_grid(X, Y1, As). minmax([A, B, C, D], X0, X1, Y0, Y1) :- X0 is min(A, C), X1 is max(A, C), Y0 is min(B, D), Y1 is max(B, D). minmax_seq([A], X0, X1, Y0, Y1) :- minmax(A, X0, X1, Y0, Y1). minmax_seq([A|As], X0, X1, Y0, Y1) :- minmax_seq(As, X00, X01, Y00, Y01), minmax(A, X10, X11, Y10, Y11), X0 is min(X00, X10), X1 is max(X01, X11), Y0 is min(Y00, Y10), Y1 is max(Y01, Y11). vertical([A, _, A, _]). horizontal([_, A, _, A]). prefix_n(0, _, []). prefix_n(X, [A|As], [A|Ps]) :- X > 0, X1 is X - 1, prefix_n(X1, As, Ps), !. suffix_n(N, A, S) :- reverse(A, B), prefix_n(N, B, P), reverse(P, S), !. add_one([], []). add_one([A|As], [B|Bs]) :- B is A + 1, add_one(As, Bs), !. mark_in_row(X, [A, B], Y) :- length(X, L), L1 is L - B - 1, prefix_n(A, X, Pfx), suffix_n(L1, X, Sfx), append([Pfx, Q, Sfx], X), add_one(Q, W), append([Pfx, W, Sfx], Y), !. mark_row(X, [A, B, C, B], Y) :- length(X, L), L1 is L - B - 1, prefix_n(B, X, Pfx), suffix_n(L1, X, Sfx), nth0(B, X, Row0), mark_in_row(Row0, [A, C], Row1), append([Pfx, [Row1], Sfx], Y), !. mark_cols([], _, []). mark_cols([X|Xs], A, [Y|Ys]) :- mark_in_row(X, [A, A], Y), !, mark_cols(Xs, A, Ys), !. mark_col(X, [A, B, A, D], Y) :- length(X, L), L1 is L - D - 1, prefix_n(B, X, Pfx), suffix_n(L1, X, Sfx), append([Pfx, Q, Sfx], X), mark_cols(Q, A, W), !, append([Pfx, W, Sfx], Y). mark_line(X, Z, Y) :- (mark_col(X, Z, Y), !); (mark_row(X, Z, Y), !). mark_lines(X, [], X). mark_lines(X, [Z|Zs], Y) :- mark_line(X, Z, Y0), !, mark_lines(Y0, Zs, Y), !. count_ge2_row([], 0). count_ge2_row([A|As], C) :- A >= 2, count_ge2_row(As, C1), C is C1 + 1. count_ge2_row([A|As], C) :- A < 2, count_ge2_row(As, C). count_ge2([], 0). count_ge2([X|Xs], Y) :- count_ge2(Xs, Y0), count_ge2_row(X, Y1), Y is Y0 + Y1.