Advent of Code 2022 Day 17 - Discussion

This topic is about Day 17 of the Advent of Code 2022 .

Link to our leaderboard:

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

The entry code is:
370884-a6a71927

Good luck!

2 Likes

Is that Tetris I see?

2 Likes

Oh boy, first part simulation was straightforward, finding cycles for second part in the simulation was not, I’m not sure my solution is general enough, I thought that it’s expected to have a full line at some point so you can treat it as if there are no previous blocks in the state, and go from there, but I don’t think it will work on all inputs, anyway here’s solution that works for my input :smiley:

main(File) ->
    {ok, RawData} = file:read_file(File),
    Data = binary_to_list(RawData),
    io:format("part 1: ~p~n", [solve1(Data)]),
    io:format("part 2: ~p~n", [solve2(Data)]).

solve1(Data) ->
    element(1, simulate(Data, 1, 2022)).

solve2(Data) ->
    {_, Rep} = simulate(Data, 1, 10000),
    {CycleHeight, CyclePeriod, CycleStart} = find_cycle(Rep),
    Total  = 1000000000000,
    Cycles = Total div CyclePeriod,
    io:format("~nHeight: ~p Period: ~p Start: ~p~n", [CycleHeight, CyclePeriod, CycleStart]),
    io:format("Cycles: ~p~n~n", [Cycles]),
    {AddedHeight, _} = simulate(Data, 1, Total - Cycles * CyclePeriod),
    AddedHeight + Cycles * CycleHeight.

find_cycle(Rep) ->
    [{H1, B1, _, P}, {H2, B2, _, P}|_]
        = hd([ V || {_, _, R, P} <- Rep,
              length(V = [ X || {_, _, R0, P0} = X <- Rep, R0 =:= R, P0 =:= P ]) > 1 ]),
    {H2 - H1, B2 - B1, B1}.

simulate(Pattern, From, To) ->
    State = {0, Pattern, [], #{}, []},
    {FloorHeight, _, _, _, Rep} = lists:foldl(fun do_simulate/2, State, lists:seq(From, To)),
    {FloorHeight, lists:reverse(Rep)}.

do_simulate(RockNum, {FloorHeight, Pattern, RestPattern, Map, Rep}) ->
    Rock = plus({2, FloorHeight + 3}, rock((RockNum - 1) rem 5)),
    {MaxY, NewP, NewRestP, NewMap, NewRep} = simulate_drop(Rock, RockNum, Pattern, RestPattern, Map, Rep),
    {max(FloorHeight, MaxY), NewP, NewRestP, NewMap, NewRep}.

simulate_drop(Rock, RockNum, [], RestPattern, Map, Rep) ->
    simulate_drop(Rock, RockNum, lists:reverse(RestPattern), [], Map, Rep);
simulate_drop(Rock, RockNum, [Direction|Rest], RestPattern, Map, Rep) ->
    Plus = case Direction of
               $< -> {-1, 0};
               $> -> { 1, 0}
           end,
    NewRock0 = plus(Plus, Rock),
    NewRock1 = case collision(NewRock0, Map) of
                   true  -> Rock;
                   false -> NewRock0
               end,
    NewRock2 = plus({0, -1}, NewRock1),
    case collision(NewRock2, Map) of
        true  ->
            MaxY = lists:max([ Y || {_, Y} <- NewRock1 ]),
            NewMap = lists:foldl(fun (X, Acc) -> Acc#{X => ok} end, Map, NewRock1),
            NewRep = case length([ true || X <- lists:seq(1, 7), maps:is_key({X, MaxY}, NewMap) ]) of
                          7 -> [{MaxY, RockNum, (RockNum - 1) rem 5, length(RestPattern)}|Rep];
                          _ -> Rep
                     end,
            {MaxY, Rest, [Direction|RestPattern], NewMap, NewRep};
        false ->
            simulate_drop(NewRock2, RockNum, Rest, [Direction|RestPattern], Map, Rep)
    end.

plus({X, Y}, Rock) ->
    [ {X0 + X, Y0 + Y} || {X0, Y0} <- Rock ].

collision(Rock, Map) ->
    lists:any(fun ({X, Y} = C) -> X =:= 0 orelse X =:= 8 orelse Y =:= 0 orelse is_map_key(C, Map) end, Rock).

rock(0) -> [ {X, 1} || X <- lists:seq(1, 4) ];
rock(1) -> [{2, 1}, {2, 3}] ++ [ {X, 2} || X <- lists:seq(1, 3) ];
rock(2) -> [{3, 3}, {3, 2}] ++ [ {X, 1} || X <- lists:seq(1, 3) ];
rock(3) -> [ {1, Y} || Y <- lists:seq(1, 4) ];
rock(4) -> [{1, 1}, {2, 1}, {1, 2}, {2, 2}].
1 Like