|
|
@ -2,63 +2,49 @@ |
|
|
|
|
|
|
|
|
-export([solve/1]). |
|
|
-export([solve/1]). |
|
|
|
|
|
|
|
|
-compile(export_all). |
|
|
|
|
|
|
|
|
|
|
|
solve(InputData) -> |
|
|
solve(InputData) -> |
|
|
{part1(InputData), none}. |
|
|
|
|
|
|
|
|
{part1(InputData), part2(InputData)}. |
|
|
|
|
|
|
|
|
part1(Input) -> |
|
|
part1(Input) -> |
|
|
State = parse_input(Input), |
|
|
State = parse_input(Input), |
|
|
EndState = step(10, State), |
|
|
EndState = step(10, State), |
|
|
{XMin, XMax, YMin, YMax} = Bounds = get_bounds(EndState), |
|
|
|
|
|
%io:format("~p~n", [Bounds]), |
|
|
|
|
|
|
|
|
{XMin, XMax, YMin, YMax} = get_bounds(EndState), |
|
|
(XMax - XMin + 1) * (YMax - YMin + 1) - num_elves(State). |
|
|
(XMax - XMin + 1) * (YMax - YMin + 1) - num_elves(State). |
|
|
|
|
|
|
|
|
|
|
|
part2(InputData) -> |
|
|
|
|
|
State = parse_input(InputData), |
|
|
|
|
|
step_until(0, State). |
|
|
|
|
|
|
|
|
parse_input(Input) -> parse_input(Input, 0, 0, 1, {#{}, #{}}). |
|
|
parse_input(Input) -> parse_input(Input, 0, 0, 1, {#{}, #{}}). |
|
|
|
|
|
|
|
|
parse_input(<<>>, _X, _Y, _NumElves, State) -> |
|
|
parse_input(<<>>, _X, _Y, _NumElves, State) -> |
|
|
State; |
|
|
State; |
|
|
parse_input(<<$., Rest/binary>>, X, Y, ElfId, State) -> |
|
|
parse_input(<<$., Rest/binary>>, X, Y, ElfId, State) -> |
|
|
parse_input(Rest, X+1, Y, ElfId, State); |
|
|
parse_input(Rest, X+1, Y, ElfId, State); |
|
|
parse_input(<<$\n, Rest/binary>>, X, Y, ElfId, State) -> |
|
|
|
|
|
|
|
|
parse_input(<<$\n, Rest/binary>>, _X, Y, ElfId, State) -> |
|
|
parse_input(Rest, 0, Y+1, ElfId, State); |
|
|
parse_input(Rest, 0, Y+1, ElfId, State); |
|
|
parse_input(<<$#, Rest/binary>>, X, Y, ElfId, {ActiveElves, Positions}) -> |
|
|
parse_input(<<$#, Rest/binary>>, X, Y, ElfId, {ActiveElves, Positions}) -> |
|
|
parse_input(Rest, X+1, Y, ElfId+1, {ActiveElves#{ElfId => {X, Y}}, Positions#{{X, Y} => ElfId}}). |
|
|
parse_input(Rest, X+1, Y, ElfId+1, {ActiveElves#{ElfId => {X, Y}}, Positions#{{X, Y} => ElfId}}). |
|
|
|
|
|
|
|
|
num_elves({_ActiveElves, Positions}) -> map_size(Positions). |
|
|
num_elves({_ActiveElves, Positions}) -> map_size(Positions). |
|
|
|
|
|
|
|
|
board_put(X, Y, Char, {W, Data}) -> |
|
|
|
|
|
Index = Y * (W+1) + X, |
|
|
|
|
|
Before = binary_part(Data, {0, Index}), |
|
|
|
|
|
After = binary_part(Data, {Index + 1, byte_size(Data) - Index - 1}), |
|
|
|
|
|
{W, <<Before/bytes, Char, After/bytes>>}. |
|
|
|
|
|
|
|
|
|
|
|
mkboard(W, H) -> |
|
|
|
|
|
mkboard(W, H, <<>>). |
|
|
|
|
|
|
|
|
|
|
|
mkboard(W, 0, Acc) -> {W, Acc}; |
|
|
|
|
|
mkboard(W, H, Acc) -> |
|
|
|
|
|
MkRow = fun MkRow(0, R) -> R; |
|
|
|
|
|
MkRow(N, R) -> MkRow(N-1, <<R/binary, $.>>) end, |
|
|
|
|
|
WithRow = MkRow(W, Acc), |
|
|
|
|
|
mkboard(W, H-1, <<WithRow/binary, $\n>>). |
|
|
|
|
|
|
|
|
|
|
|
render({_Active, Positions} = State) -> |
|
|
|
|
|
{MinX, MaxX, MinY, MaxY} = get_bounds(State), |
|
|
|
|
|
{_, Data} = maps:fold(fun ({X, Y}, Id, Board) -> board_put(X - MinX, Y - MinY, (Id rem 10) + $0, Board) end, |
|
|
|
|
|
mkboard(MaxX - MinX + 1, MaxY - MinY + 1), |
|
|
|
|
|
Positions), |
|
|
|
|
|
Data. |
|
|
|
|
|
|
|
|
|
|
|
step(N, State) -> step(0, N, State). |
|
|
step(N, State) -> step(0, N, State). |
|
|
|
|
|
|
|
|
|
|
|
step_until(I, State) -> |
|
|
|
|
|
NewState = do_step(State, I), |
|
|
|
|
|
if |
|
|
|
|
|
State == NewState -> I+1; |
|
|
|
|
|
true -> step_until(I+1, NewState) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
step(N, N, State) -> State; |
|
|
step(N, N, State) -> State; |
|
|
step(I, N, State) when N - I > 0 -> step(I+1, N, do_step(State, I)). |
|
|
step(I, N, State) when N - I > 0 -> step(I+1, N, do_step(State, I)). |
|
|
|
|
|
|
|
|
do_step({ActiveElves, PositionsIn}, Round) -> |
|
|
do_step({ActiveElves, PositionsIn}, Round) -> |
|
|
%io:format(" Stepping ~n", []), |
|
|
|
|
|
|
|
|
%io:format(" Stepping ~p ~n", [Round]), |
|
|
%io:format("~s~n", [render({ActiveElves, PositionsIn})]), |
|
|
%io:format("~s~n", [render({ActiveElves, PositionsIn})]), |
|
|
{PlannedMoves, _Inactive} = plan_moves(ActiveElves, PositionsIn, Round), |
|
|
{PlannedMoves, _Inactive} = plan_moves(ActiveElves, PositionsIn, Round), |
|
|
|
|
|
%io:format(" moves ~p ~n", [map_size(PlannedMoves)]), |
|
|
|
|
|
|
|
|
maps:fold(fun (NewPos, ElfId, {Active, Positions}) -> |
|
|
maps:fold(fun (NewPos, ElfId, {Active, Positions}) -> |
|
|
#{ElfId := OldPos} = Active, |
|
|
#{ElfId := OldPos} = Active, |
|
|
Updooted = maps:remove(OldPos, Positions), |
|
|
Updooted = maps:remove(OldPos, Positions), |
|
|
@ -140,8 +126,8 @@ get_move({ElfX, ElfY}, Positions, Round) -> |
|
|
end |
|
|
end |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
mark_inactive(ElfId, {ActiveElves, Positions}) -> maps:remove(ElfId, ActiveElves). |
|
|
|
|
|
mark_active(ElfId, ElfPosition, {ActiveElves, Positions}) -> ActiveElves#{ElfId => ElfPosition}. |
|
|
|
|
|
|
|
|
mark_inactive(ElfId, {ActiveElves, _Positions}) -> maps:remove(ElfId, ActiveElves). |
|
|
|
|
|
mark_active(ElfId, ElfPosition, {ActiveElves, _Positions}) -> ActiveElves#{ElfId => ElfPosition}. |
|
|
|
|
|
|
|
|
get_bounds({_ActiveElves, Positions}) -> |
|
|
get_bounds({_ActiveElves, Positions}) -> |
|
|
maps:fold(fun ({X, Y}, _Value, {MinX, MaxX, MinY, MaxY}) -> |
|
|
maps:fold(fun ({X, Y}, _Value, {MinX, MaxX, MinY, MaxY}) -> |
|
|
@ -149,3 +135,27 @@ get_bounds({_ActiveElves, Positions}) -> |
|
|
end, |
|
|
end, |
|
|
{50000000, 0, 50000000, 0}, |
|
|
{50000000, 0, 50000000, 0}, |
|
|
Positions). |
|
|
Positions). |
|
|
|
|
|
|
|
|
|
|
|
mkboard(W, H) -> |
|
|
|
|
|
mkboard(W, H, <<>>). |
|
|
|
|
|
|
|
|
|
|
|
mkboard(W, 0, Acc) -> {W, Acc}; |
|
|
|
|
|
mkboard(W, H, Acc) -> |
|
|
|
|
|
MkRow = fun MkRow(0, R) -> R; |
|
|
|
|
|
MkRow(N, R) -> MkRow(N-1, <<R/binary, $.>>) end, |
|
|
|
|
|
WithRow = MkRow(W, Acc), |
|
|
|
|
|
mkboard(W, H-1, <<WithRow/binary, $\n>>). |
|
|
|
|
|
|
|
|
|
|
|
render({_Active, Positions} = State) -> |
|
|
|
|
|
{MinX, MaxX, MinY, MaxY} = get_bounds(State), |
|
|
|
|
|
{_, Data} = maps:fold(fun ({X, Y}, Id, Board) -> board_put(X - MinX, Y - MinY, (Id rem 10) + $0, Board) end, |
|
|
|
|
|
mkboard(MaxX - MinX + 1, MaxY - MinY + 1), |
|
|
|
|
|
Positions), |
|
|
|
|
|
Data. |
|
|
|
|
|
|
|
|
|
|
|
board_put(X, Y, Char, {W, Data}) -> |
|
|
|
|
|
Index = Y * (W+1) + X, |
|
|
|
|
|
Before = binary_part(Data, {0, Index}), |
|
|
|
|
|
After = binary_part(Data, {Index + 1, byte_size(Data) - Index - 1}), |
|
|
|
|
|
{W, <<Before/bytes, Char, After/bytes>>}. |
|
|
|
|
|
|