Advent of Code 2021 - Day 11

This topic is about Day 11 of the Advent of Code 2021.

We have a private leaderboard (shared with users of the elixir forum ):

https://adventofcode.com/2021/leaderboard/private/view/370884

The entry code is:
370884-a6a71927

3 Likes

Very similar to Day 9 challenge, took some parsing code from that day. Part 2 was basically a 1 line change from Part 1.
I have a feeling there is going to be more sophisticated cell automation in the future challenges :slight_smile: :

main(File) ->
    {ok, RawData} = file:read_file(File),
    Data = [ [ N - $0 || N <- binary_to_list(Line) ]
             || Line <- binary:split(RawData, <<"\n">>, [global, trim]) ],
    Map = load(Data),
    io:format("part 1: ~p~n", [solve1(Map)]),
    io:format("part 2: ~p~n", [solve2(Map)]).

load(Data) ->
    maps:from_list([ {{X, Y}, N} || {Y, Line} <- enum(Data),
                                    {X, N}    <- enum(Line) ]).

enum(List) ->
    lists:zip(lists:seq(1, length(List)), List).

solve1(Map) ->
    simulate(Map, 0, 100).

simulate(_Map, Count, 0)    -> Count;
simulate( Map, Count, Step) ->
    {NewMap, NewCount} = simulate_iter(maps:map(fun (_, V) -> V + 1 end, Map), Count),
    case (NewCount - Count) =:= maps:size(Map) of
        true  -> -Step;
        false -> simulate(NewMap, NewCount, Step - 1)
    end.

simulate_iter(Map, Count) ->
    {NewMap, NewCount} = maps:fold(fun simulate_iter/3, {Map, Count}, Map),
    case NewCount > Count of
        true  -> simulate_iter(NewMap, NewCount);
        false -> {NewMap, NewCount}
    end.

simulate_iter(XY, V, {Map, Count}) ->
    case V > 9 of
        true ->
            NewMap   = lists:foldl(fun (Adj, M) -> flash(Adj, M) end, Map, neighbours(XY)),
            NewCount = Count + 1,
            {NewMap#{XY => 0}, NewCount};
        false ->
            {Map, Count}
    end.

flash(Adj, M) ->
    NewV = case maps:get(Adj, M) of
               0 -> 0;
               V -> V + 1
           end,
    maps:put(Adj, NewV, M).

neighbours({X, Y}) ->
    [{X0, Y0} || X0 <- lists:seq(X - 1, X + 1),
                 Y0 <- lists:seq(Y - 1, Y + 1),
                 X0 >= 1, X0 =< 10, Y0 >= 1, Y0 =< 10 ]
 -- [{X, Y}].

solve2(Map) ->
    simulate(Map, 0, -1).
3 Likes

Since I didn’t have time yesterday I tried to build a solution creating as many higher level functions as useful. A few of them could be interesting in the maps module whose functionality is quite spartan.

Notable here: maps_mapfold and maps_fold_merge

p11() ->
    Tab = p11_read("priv/p11.txt"),
    M = coord_map(Tab),
    {C, _} = lists:foldl(fun(_,A) -> step(A) end, {0, M}, 
                       lists:seq(1,100)),
    {C, count_until(fun step/1, fun all_flashed/1, 0, {0, M})}.
                        
p11_read(Fn) ->
    {ok, Bin} = file:read_file(Fn),
    border(b, [ [ C - $0 || <<C:8>> <= L ] 
                 || L <- string:split(string:trim(Bin), "\n", all) ]).

step({C,M}) ->
    {C1,M1} = cooldown(fixpoint(fun flash/1, inc_map(M))),
    {C1+C, M1}.

cooldown(M) ->
    maps_mapfold(fun(_,flashed,A) -> {0, A+1};
                    (_,V,A) -> {V, A}
                 end, 0, M).
                         
all_flashed({_,M}) ->                      
    #{} =:= maps:filter(fun(_, X) when is_number(X), X > 0 -> true;
                           (_, _) -> false
                        end, M).

flash(Map) ->
    maps_fold_merge(fun(K,V,M) when is_number(V), V > 9 ->
                            M1 = inc_map(surround8(K, M)),
                            M1#{K => flashed};
                       (_,_,M) -> M
                    end, Map).

count_until(Fun, Cond, N, X) ->
    case Cond(X) of
        true -> N;
        false -> 
            X1 = Fun(X),
            count_until(Fun, Cond, N+1, X1)
    end.

fixpoint(F, M) ->
    case F(M) of
        X when X =:= M -> X;
        X -> fixpoint(F, X)
    end.
                      
maps_mapfold(Fun, Acc, Map) ->
    maps:fold(fun(K,V,{A,M}) -> 
                      {V1, A1} = Fun(K,V,A),
                      M1 = maps:put(K,V1,M),
                      {A1,M1}
              end, {Acc, Map}, Map).
                      

maps_fold_merge(F, M) ->
    maps:fold(fun(K,V,A) -> maps:merge(A,F(K,V,A)) end, M, M).

inc_map(M) ->
    maps:map(fun(_,X) when is_number(X) -> X+1; (_,X) -> X end, M).
                     

coord_map(T) ->
    lists:foldl(fun({E,X,Y}, M) -> M#{{X,Y} => E} end, #{},  
                lists:flatten(add_coords(T))).

border(V, LoL) ->
   Len = length(hd(LoL)) + 2,
   Tb = lists:duplicate(Len, V),
   [Tb] ++ [ [V] ++ L ++ [V] || L <- LoL ] ++ [Tb].

add_coords(LoL) ->
    H = length(LoL),
    W = length(hd(LoL)),
    [ [ {E, X, Y} || {E, X} <- lists:zip(L, lists:seq(1,W)) ] 
                       || {L, Y} <- lists:zip(LoL, lists:seq(1,H)) ].
            
surround8({X,Y},M) ->
    maps:with([{X-1,Y},{X+1,Y},{X,Y-1},{X,Y+1},
               {X-1,Y-1},{X-1,Y+1},{X+1,Y-1},{X+1,Y+1}], M).

4 Likes