2022-12-09 06:18:58 -05:00
|
|
|
:- module day9.
|
|
|
|
:- interface.
|
|
|
|
:- import_module basics.
|
|
|
|
|
2022-12-10 01:05:22 -05:00
|
|
|
:- pred run(part::in, lines::in, answer::out) is cc_multi.
|
2022-12-09 06:18:58 -05:00
|
|
|
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
|
|
:- import_module string.
|
|
|
|
:- import_module list.
|
|
|
|
:- import_module set_bbbtree.
|
|
|
|
|
|
|
|
:- type set(T) == set_bbbtree(T).
|
|
|
|
|
|
|
|
|
|
|
|
:- type coord ---> c(x :: int, y :: int).
|
|
|
|
:- type rope == list(coord).
|
|
|
|
|
|
|
|
:- type direction ---> up; down; left; right.
|
|
|
|
|
|
|
|
:- pred to_direction(string, direction).
|
|
|
|
:- mode to_direction(in, out) is semidet.
|
|
|
|
:- mode to_direction(out, in) is det.
|
|
|
|
to_direction("U", up).
|
|
|
|
to_direction("D", down).
|
|
|
|
to_direction("L", left).
|
|
|
|
to_direction("R", right).
|
|
|
|
|
|
|
|
:- pred orth(direction::in, direction::in) is semidet.
|
|
|
|
orth(A, B) :-
|
|
|
|
((A = up ; A = down), (B = left ; B = right));
|
|
|
|
((A = left ; A = right), (B = up ; B = down)).
|
|
|
|
|
|
|
|
:- pred line(string::in, list(direction)::out) is semidet.
|
|
|
|
line(Str, replicate(N, D)) :-
|
|
|
|
words(Str) = [DD, NN],
|
|
|
|
to_direction(DD, D),
|
|
|
|
to_int(NN, N).
|
|
|
|
|
|
|
|
:- pred move_head(direction::out, coord::in, coord::out) is multi.
|
|
|
|
move_head(up, c(X, Y), c(X, Y+1)).
|
|
|
|
move_head(down, c(X, Y), c(X, Y-1)).
|
|
|
|
move_head(left, c(X, Y), c(X-1, Y)).
|
|
|
|
move_head(right, c(X, Y), c(X+1, Y)).
|
|
|
|
|
|
|
|
:- pred ok(coord::in, coord::in) is semidet.
|
|
|
|
ok(A, B) :- abs(A^x - B^x) =< 1, abs(A^y - B^y) =< 1.
|
|
|
|
|
|
|
|
:- pred ok(rope::in) is semidet.
|
|
|
|
ok([]). ok([_]).
|
|
|
|
ok([A, B | Rest]) :- ok(A, B), ok([B | Rest]).
|
|
|
|
|
|
|
|
:- pred same_rc(coord::in, coord::in) is semidet.
|
|
|
|
same_rc(A, B) :- A^x = B^x ; A^y = B^y.
|
|
|
|
|
|
|
|
:- pred move_tail1(coord::in, coord::in, coord::out) is nondet.
|
|
|
|
move_tail1(H, !T) :- ok(H, !.T).
|
|
|
|
move_tail1(H, !T) :-
|
|
|
|
if same_rc(H, !.T) then
|
|
|
|
move_head(_, !T),
|
|
|
|
ok(H, !.T)
|
|
|
|
else
|
|
|
|
move_head(D1, !T),
|
|
|
|
move_head(D2, !T),
|
|
|
|
orth(D1, D2),
|
|
|
|
ok(H, !.T).
|
|
|
|
|
|
|
|
:- pred move_tail(coord::in, rope::in, rope::out) is nondet.
|
|
|
|
move_tail(_, [], []).
|
|
|
|
move_tail(H, [!.T | !.Ts], [!:T | !:Ts]) :-
|
|
|
|
move_tail1(H, !T),
|
|
|
|
move_tail(!.T, !Ts).
|
|
|
|
|
|
|
|
:- pred move(direction::in, rope::in, rope::out) is nondet.
|
|
|
|
move(_, [], []).
|
|
|
|
move(D, [!.H | !.T], [!:H | !:T]) :-
|
|
|
|
move_head(D, !H),
|
|
|
|
move_tail(!.H, !T).
|
|
|
|
|
|
|
|
|
|
|
|
:- type seen == set(coord).
|
|
|
|
|
|
|
|
:- pred next(direction, rope, rope, seen, seen).
|
|
|
|
:- mode next(in, in, out, in, out) is nondet.
|
|
|
|
next(D, !Rope, !Seen) :-
|
|
|
|
move(D, !Rope),
|
|
|
|
last(!.Rope, Tail),
|
|
|
|
insert(Tail, !Seen).
|
|
|
|
|
|
|
|
:- pred run0(part::in, lines::in, int::out) is cc_nondet.
|
|
|
|
run0(Part, Lines, Out) :-
|
|
|
|
Start = replicate(part(Part, 2, 10), c(0, 0)),
|
|
|
|
map(line, Lines, Dirs),
|
|
|
|
foldl2(next, condense(Dirs), Start, _, init, End),
|
|
|
|
count(End, Out).
|
|
|
|
|
2022-12-10 01:05:22 -05:00
|
|
|
run(Part, Lines, int(Out)) :-
|
2022-12-09 06:18:58 -05:00
|
|
|
disable_warning [no_solution_disjunct] (
|
|
|
|
not run0(Part, Lines, Out) => die("bad input")
|
|
|
|
).
|