You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.7 KiB

-module(day9).
-export([solve/1]).
solve(Input) ->
%#{visited := Visited} = EndState = fold_moves(Input, fun simulate/2, State),
{simulate_rope(Input, 1), simulate_rope(Input, 9)}.
make_rope(Length) ->
Rope0 = make_head(),
Rope1 = add_knots(Rope0, Length),
add_trace(Rope1).
simulate_rope(Input, Length) ->
{RopeFn, RopeState} = make_rope(Length),
{Visited, _RopeState} = fold_moves(Input, RopeFn, RopeState),
map_size(Visited).
make_head() ->
{
fun(Move, [Pos]) ->
[vec_add(Move, Pos)]
end,
[{0, 0}]
}.
add_knot({HeadFn, Head0}) ->
{
fun(Move, [TailPos|HeadState]) ->
[HeadPosNew|_] = HeadStateNew = HeadFn(Move, HeadState),
[chase_tail(HeadPosNew, TailPos) | HeadStateNew]
end,
[{0,0}|Head0]
}.
add_knots(Stream, 0) -> Stream;
add_knots(Stream, N) -> add_knots(add_knot(Stream), N-1).
add_trace({SimFn, Sim0}) ->
{
fun(Move, {Visited, SimAccIn}) ->
[Pos | _] = SimAccOut = SimFn(Move, SimAccIn),
{Visited#{Pos => []}, SimAccOut}
end,
{#{}, Sim0}
}.
simulate(Move, #{head := Head, tail := Tail, visited := Visited}) ->
NewHead = vec_add(Head, Move),
NewTail = chase_tail(NewHead, Tail),
NewVisited = Visited#{NewTail => []},
#{head => NewHead, tail => NewTail, visited => NewVisited}.
chase_tail(Head, Tail) ->
Diff = vec_sub(Head, Tail),
case vec_norm(Diff) of
Diff -> Tail;
Norm -> vec_add(Norm, Tail)
end.
fold_instructions(<<Letter, $\s, RestIn/binary>>, Fun, Acc) ->
{Count, RestOut} = parse_int(RestIn, 0),
Direction =
case Letter of
$U -> up;
$D -> down;
$L -> left;
$R -> right
end,
fold_instructions(RestOut, Fun, Fun({Direction, Count}, Acc));
fold_instructions(<<$\n, Rest/binary>>, Fun, Acc) -> fold_instructions(Rest, Fun, Acc);
fold_instructions(<<>>, _Fun, Acc) -> Acc.
fold_moves(Stream, Fun, Acc) -> element(2, fold_instructions(Stream, fun per_move/2, {Fun, Acc})).
per_move({Direction, Count}, {Fun, Acc}) -> {Fun, per_move0(direction_vec(Direction), Count, Fun, Acc)}.
per_move0(_Move, 0, _Fun, Acc) -> Acc;
per_move0(Move, Count, Fun, Acc) -> per_move0(Move, Count-1, Fun, Fun(Move, Acc)).
direction_vec(up) -> {0, 1};
direction_vec(down) -> {0, -1};
direction_vec(left) -> {-1, 0};
direction_vec(right) -> {1, 0}.
vec_add({X1, Y1}, {X2, Y2}) -> {X1+X2, Y1+Y2}.
vec_sub({X1, Y1}, {X2, Y2}) -> {X1-X2, Y1-Y2}.
vec_norm({X, Y}) -> {norm(X), norm(Y)}.
norm(X) when X > 0 -> 1;
norm(X) when X < 0 -> -1;
norm(0) -> 0.
parse_int(<<Char, Rest/binary>>, Acc) when Char >= $0 andalso Char =< $9 -> parse_int(Rest, Acc*10+(Char - $0));
parse_int(Rest, Acc) -> {Acc, Rest}.