diff --git a/day9.erl b/day9.erl new file mode 100644 index 0000000..067febd --- /dev/null +++ b/day9.erl @@ -0,0 +1,59 @@ +-module(day9). + +-export([solve/1]). + +solve(Input) -> + State = #{head => {0, 0}, tail => {0, 0}, visited => #{{0, 0} => []}}, + #{visited := Visited} = EndState = fold_moves(Input, fun simulate/2, State), + {map_size(Visited), none}. + +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(<>, 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(<>, Acc) when Char >= $0 andalso Char =< $9 -> parse_int(Rest, Acc*10+(Char - $0)); +parse_int(Rest, Acc) -> {Acc, Rest}.