3 Commits
59cc25c565
...
4c69c50c6e
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
4c69c50c6e |
Day 25-1
|
3 years ago |
|
|
c627295fff |
Day 23-2
|
3 years ago |
|
|
fe5ef51e90 |
Day 23-1
|
3 years ago |
2 changed files with 192 additions and 0 deletions
@ -0,0 +1,161 @@ |
|||||
|
-module(day23). |
||||
|
|
||||
|
-export([solve/1]). |
||||
|
|
||||
|
solve(InputData) -> |
||||
|
{part1(InputData), part2(InputData)}. |
||||
|
|
||||
|
part1(Input) -> |
||||
|
State = parse_input(Input), |
||||
|
EndState = step(10, State), |
||||
|
{XMin, XMax, YMin, YMax} = get_bounds(EndState), |
||||
|
(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(<<>>, _X, _Y, _NumElves, State) -> |
||||
|
State; |
||||
|
parse_input(<<$., Rest/binary>>, X, Y, ElfId, State) -> |
||||
|
parse_input(Rest, X+1, Y, ElfId, State); |
||||
|
parse_input(<<$\n, Rest/binary>>, _X, Y, ElfId, State) -> |
||||
|
parse_input(Rest, 0, Y+1, ElfId, State); |
||||
|
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}}). |
||||
|
|
||||
|
num_elves({_ActiveElves, Positions}) -> map_size(Positions). |
||||
|
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(I, N, State) when N - I > 0 -> step(I+1, N, do_step(State, I)). |
||||
|
|
||||
|
do_step({ActiveElves, PositionsIn}, Round) -> |
||||
|
%io:format(" Stepping ~p ~n", [Round]), |
||||
|
%io:format("~s~n", [render({ActiveElves, PositionsIn})]), |
||||
|
{PlannedMoves, _Inactive} = plan_moves(ActiveElves, PositionsIn, Round), |
||||
|
%io:format(" moves ~p ~n", [map_size(PlannedMoves)]), |
||||
|
|
||||
|
maps:fold(fun (NewPos, ElfId, {Active, Positions}) -> |
||||
|
#{ElfId := OldPos} = Active, |
||||
|
Updooted = maps:remove(OldPos, Positions), |
||||
|
{Active#{ElfId := NewPos}, Updooted#{NewPos => ElfId}} |
||||
|
end, |
||||
|
{ActiveElves, PositionsIn}, |
||||
|
PlannedMoves). |
||||
|
|
||||
|
plan_moves(ActiveElves, Positions, Round) -> |
||||
|
{_Collisions, Moves, Inactive} = |
||||
|
maps:fold( |
||||
|
fun (ElfId, Position, {Collisions, MoveSet, Inactive}) -> |
||||
|
Move = get_move(Position, Positions, Round), |
||||
|
%io:format(" ~p ~p ~n", [ElfId, Position]), |
||||
|
%io:format(" ~p ~p ~n", [ElfId, Move]), |
||||
|
% Todo: only mark this unit as inactive if it exited because it had no neighbors (update the signature of get_move/2) |
||||
|
if |
||||
|
Position == Move -> |
||||
|
{Collisions, MoveSet, Inactive#{ElfId => Position}}; |
||||
|
is_map_key(Move, Collisions) -> |
||||
|
#{Move := Elves} = Collisions, |
||||
|
{Collisions#{Move:=[ElfId|Elves]}, MoveSet, Inactive}; |
||||
|
is_map_key(Move, MoveSet) -> |
||||
|
#{Move := CollidingElf} = MoveSet, |
||||
|
{Collisions#{Move => [ElfId, CollidingElf]}, maps:remove(Move, MoveSet), Inactive}; |
||||
|
true -> |
||||
|
{Collisions, MoveSet#{Move => ElfId}, Inactive} |
||||
|
end |
||||
|
end, |
||||
|
{#{}, #{}, #{}}, |
||||
|
ActiveElves), |
||||
|
{Moves, Inactive}. |
||||
|
|
||||
|
|
||||
|
open(Position, Positions) when is_map_key(Position, Positions) -> 0; |
||||
|
open(_Position, _Positions) -> 1. |
||||
|
|
||||
|
% N S W NW SW E NE SE |
||||
|
get_move({ElfX, ElfY}, Positions, Round) -> |
||||
|
[_|Adjacent] = [{X, Y} || X <- [ElfX, ElfX-1, ElfX+1], Y <- [ElfY, ElfY-1, ElfY+1]], |
||||
|
OpenByte= lists:foldl(fun (Pos, Acc) -> (Acc bsl 1) + open(Pos, Positions) end, 0, Adjacent), |
||||
|
%io:format("~.2B~n", [OpenByte]), |
||||
|
case Round rem 4 of |
||||
|
0 -> |
||||
|
if |
||||
|
2#11111111 == OpenByte -> {ElfX, ElfY}; |
||||
|
2#10010010 == (OpenByte band 2#10010010) -> {ElfX, ElfY-1}; |
||||
|
2#01001001 == (OpenByte band 2#01001001) -> {ElfX, ElfY+1}; |
||||
|
2#00111000 == (OpenByte band 2#00111000) -> {ElfX-1, ElfY}; |
||||
|
2#00000111 == (OpenByte band 2#00000111) -> {ElfX+1, ElfY}; |
||||
|
true -> {ElfX, ElfY} |
||||
|
end; |
||||
|
1 -> |
||||
|
if |
||||
|
2#11111111 == OpenByte -> {ElfX, ElfY}; |
||||
|
2#01001001 == (OpenByte band 2#01001001) -> {ElfX, ElfY+1}; |
||||
|
2#00111000 == (OpenByte band 2#00111000) -> {ElfX-1, ElfY}; |
||||
|
2#00000111 == (OpenByte band 2#00000111) -> {ElfX+1, ElfY}; |
||||
|
2#10010010 == (OpenByte band 2#10010010) -> {ElfX, ElfY-1}; |
||||
|
true -> {ElfX, ElfY} |
||||
|
end; |
||||
|
2 -> |
||||
|
if |
||||
|
2#11111111 == OpenByte -> {ElfX, ElfY}; |
||||
|
2#00111000 == (OpenByte band 2#00111000) -> {ElfX-1, ElfY}; |
||||
|
2#00000111 == (OpenByte band 2#00000111) -> {ElfX+1, ElfY}; |
||||
|
2#10010010 == (OpenByte band 2#10010010) -> {ElfX, ElfY-1}; |
||||
|
2#01001001 == (OpenByte band 2#01001001) -> {ElfX, ElfY+1}; |
||||
|
true -> {ElfX, ElfY} |
||||
|
end; |
||||
|
3 -> |
||||
|
if |
||||
|
2#11111111 == OpenByte -> {ElfX, ElfY}; |
||||
|
2#00000111 == (OpenByte band 2#00000111) -> {ElfX+1, ElfY}; |
||||
|
2#10010010 == (OpenByte band 2#10010010) -> {ElfX, ElfY-1}; |
||||
|
2#01001001 == (OpenByte band 2#01001001) -> {ElfX, ElfY+1}; |
||||
|
2#00111000 == (OpenByte band 2#00111000) -> {ElfX-1, ElfY}; |
||||
|
true -> {ElfX, ElfY} |
||||
|
end |
||||
|
end. |
||||
|
|
||||
|
mark_inactive(ElfId, {ActiveElves, _Positions}) -> maps:remove(ElfId, ActiveElves). |
||||
|
mark_active(ElfId, ElfPosition, {ActiveElves, _Positions}) -> ActiveElves#{ElfId => ElfPosition}. |
||||
|
|
||||
|
get_bounds({_ActiveElves, Positions}) -> |
||||
|
maps:fold(fun ({X, Y}, _Value, {MinX, MaxX, MinY, MaxY}) -> |
||||
|
{min(X, MinX), max(X, MaxX), min(Y, MinY), max(Y, MaxY)} |
||||
|
end, |
||||
|
{50000000, 0, 50000000, 0}, |
||||
|
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>>}. |
||||
|
|
||||
@ -0,0 +1,31 @@ |
|||||
|
-module(day25). |
||||
|
|
||||
|
-export([solve/1]). |
||||
|
|
||||
|
solve(Input) -> |
||||
|
RoundData = binary:split(Input, <<$\n>>, [trim_all, global]), |
||||
|
{part1(RoundData), none}. |
||||
|
|
||||
|
part1(Input) -> int_to_snafu(lists:sum(lists:map(fun snafu_to_int/1, Input))). |
||||
|
|
||||
|
snafu_to_int(Snafu) -> snafu_to_int(Snafu, 0). |
||||
|
|
||||
|
snafu_to_int(<<>>, Acc) -> Acc; |
||||
|
snafu_to_int(<<$2, Rest/binary>>, Acc) -> snafu_to_int(Rest, Acc * 5 + 2); |
||||
|
snafu_to_int(<<$1, Rest/binary>>, Acc) -> snafu_to_int(Rest, Acc * 5 + 1); |
||||
|
snafu_to_int(<<$0, Rest/binary>>, Acc) -> snafu_to_int(Rest, Acc * 5); |
||||
|
snafu_to_int(<<$-, Rest/binary>>, Acc) -> snafu_to_int(Rest, Acc * 5 - 1); |
||||
|
snafu_to_int(<<$=, Rest/binary>>, Acc) -> snafu_to_int(Rest, Acc * 5 - 2). |
||||
|
|
||||
|
int_to_snafu(0) -> <<"0">>; |
||||
|
int_to_snafu(N) -> int_to_snafu(N, []). |
||||
|
|
||||
|
int_to_snafu(0, Acc) -> list_to_binary(Acc); |
||||
|
int_to_snafu(Num, Acc) -> |
||||
|
case Num rem 5 of |
||||
|
0 -> int_to_snafu(Num div 5, [$0 | Acc]); |
||||
|
1 -> int_to_snafu(Num div 5, [$1 | Acc]); |
||||
|
2 -> int_to_snafu(Num div 5, [$2 | Acc]); |
||||
|
3 -> int_to_snafu(Num div 5 + 1, [$= | Acc]); |
||||
|
4 -> int_to_snafu(Num div 5 + 1, [$- | Acc]) |
||||
|
end. |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue