Advent of Code 2022 Day 8 - Discussions

This topic is about Day 8 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

Re-used some of the code from previous year to parse numerical grid into a map:

main(File) ->
    {ok, RawData} = file:read_file(File),
    Data = [ [ X - $0 || X <- 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(Data) ->
    MaxC  = {MaxX, MaxY} = lists:max(maps:keys(Data)),
    Edges = 2 * MaxX + 2 * MaxY - 4,
    length([ true || X <- lists:seq(2, MaxX - 1),
                     Y <- lists:seq(2, MaxY - 1),
                     is_visible({X, Y}, MaxC, Data) ])
  + Edges.

is_visible(Coord, MaxC, Map) ->
    Height = maps:get(Coord, Map),
    lists:any(fun (D) -> all_shorter(Height, Map, enum_direction(D, Coord, MaxC)) end,
              [left, right, up, down]).

all_shorter(Height, Map, Coords) ->
    lists:all(fun (C) -> maps:get(C, Map) < Height end, Coords).

enum_direction(left,  {X0, Y0}, _        ) -> [ {X,  Y0} || X <- lists:seq(X0 - 1, 1, -1) ];
enum_direction(right, {X0, Y0}, {MaxX, _}) -> [ {X,  Y0} || X <- lists:seq(X0 + 1, MaxX)  ];
enum_direction(up,    {X0, Y0}, _        ) -> [ {X0, Y } || Y <- lists:seq(Y0 - 1, 1, -1) ];
enum_direction(down,  {X0, Y0}, {_, MaxY}) -> [ {X0, Y } || Y <- lists:seq(Y0 + 1, MaxY)  ].

solve2(Data) ->
    MaxC = {MaxX, MaxY} = lists:max(maps:keys(Data)),
    lists:max([ scenic_score({X, Y}, MaxC, Data) || X <- lists:seq(2, MaxX - 1),
                                                    Y <- lists:seq(2, MaxY - 1) ]).

scenic_score(Coord, MaxC, Map) ->
    Height = maps:get(Coord, Map),
    lists:foldl(fun (D, Acc) -> Acc * view_distance(Height, Map, enum_direction(D, Coord, MaxC)) end,
                1,
                [left, right, up, down]).

view_distance(Height, Map, [C|Rest]) ->
    case maps:get(C, Map) >= Height of
        true  -> 1;
        false -> 1 + view_distance(Height, Map, Rest)
    end;
view_distance(_, _, []) ->
    0.
2 Likes

I didn’t know what I was doing last night but I solved it using Clojure. Nastiest Clojure I wrote, having transposed and reverted and reverted transposed matrices and comparing with original… arghhh.

I attempted to do the same for Erlang, after having enough hammock time. I am proud of the code (Although I took ample inspiration from your code at Part 2 especially, thank you). Especially I liked the way I regained my [Head | Tail] fluency (the list -> map function).

Did this at 5AM, took ~40 minutes (like I said, reading your code helped).

-module(day_8).

-export([solve/0]).

input() ->
  {ok, RawHeights} = file:read_file("data/8.txt"),
  RawHeights.

parse(RawHeights) ->
  TreeList =
    [[X - $0 || X <- binary_to_list(Line)]
     || Line <- binary:split(RawHeights, <<"\n">>, [global, trim])],
  Length = length(TreeList),
  Breadth = length(hd(TreeList)),
  Edges = 2 * Length + 2 * Breadth - 4,
  TreeMap = tree_list_to_tree_map(TreeList),
  {TreeMap, Edges, Length, Breadth}.

solve() ->
  RawHeights = input(),
  {TreeMap, Edges, Length, Breadth} = parse(RawHeights),
  Solve1 = solve1(TreeMap, Edges, Length, Breadth),
  Solve2 = solve2(TreeMap, Length, Breadth),
  {Solve1, Solve2}.

solve1(TreeMap, Edges, Length, Breadth) ->
  Interior =
    length([true
            || X <- lists:seq(2, Length - 1),
               Y <- lists:seq(2, Breadth - 1),
               is_visible({X, Y}, {Length, Breadth}, TreeMap)]),
  Edges + Interior.

solve2(TreeMap, Length, Breadth) ->
  lists:max([scenic_score({X, Y}, {Length, Breadth}, TreeMap)
             || X <- lists:seq(2, Length - 1), Y <- lists:seq(2, Breadth - 1)]).

tree_list_to_tree_map(TreeList) ->
  tree_list_to_tree_map(TreeList, 1, 1, []).

tree_list_to_tree_map([], _, _, TreeList) ->
  maps:from_list(TreeList);
tree_list_to_tree_map([[] | Lengths], X, _, TreeList) ->
  tree_list_to_tree_map(Lengths, X + 1, 1, TreeList);
tree_list_to_tree_map([[Height | Breadths] | Lengths], X, Y, TreeList) ->
  tree_list_to_tree_map([Breadths | Lengths], X, Y + 1, [{{X, Y}, Height} | TreeList]).

seen_from(top, {XX, YY}, _) ->
  [{X, YY} || X <- lists:seq(XX - 1, 1, -1)];
seen_from(bottom, {XX, YY}, {Length, _}) ->
  [{X, YY} || X <- lists:seq(XX + 1, Length)];
seen_from(left, {XX, YY}, _) ->
  [{XX, Y} || Y <- lists:seq(YY - 1, 1, -1)];
seen_from(right, {XX, YY}, {_, Breadth}) ->
  [{XX, Y} || Y <- lists:seq(YY + 1, Breadth)].

is_visible(Coord, Dims, Map) ->
  lists:any(fun(Dir) -> is_tallest(maps:get(Coord, Map), Map, seen_from(Dir, Coord, Dims))
            end,
            [top, bottom, left, right]).

is_tallest(Height, Map, Coords) ->
  lists:all(fun(C) -> maps:get(C, Map) < Height end, Coords).

scenic_score(Coord, Dims, Map) ->
  Height = maps:get(Coord, Map),
  Reducer =
    fun(Dir, Acc) -> Acc * view_distance(Height, Map, seen_from(Dir, Coord, Dims)) end,
  lists:foldl(Reducer, 1, [top, bottom, left, right]).

view_distance(Height, TreeMap, [C | Rest]) ->
  case maps:get(C, TreeMap) >= Height of
    true ->
      1;
    false ->
      1 + view_distance(Height, TreeMap, Rest)
  end;
view_distance(_, _, []) ->
  0.
2 Likes

Hah! That TreeMap and TreeList naming was intentional… a tribute to Java if you will.

2 Likes