Advent 2022 - Day 8
Mix.install([
{:kino, github: "livebook-dev/kino"}
])
:ok
Setup
input = Kino.Input.textarea("Please paste your input file:")
trees =
input
|> Kino.Input.read()
|> String.split("\n")
|> Enum.map(fn row -> row |> String.graphemes() |> Enum.map(&String.to_integer/1) end)
[[3, 0, 3, 7, 3], [2, 5, 5, 1, 2], [6, 5, 3, 3, 2], [3, 3, 5, 4, 9], [3, 5, 3, 9, 0]]
Drawing
Not required for problem solving, but just to make the output pretty :)
defmodule Draw do
def grid(grid) do
for row <- grid do
for x <- row do
if x, do: "X", else: "_"
end
|> Enum.join("")
end
|> Enum.join("\n")
end
end
{:module, Draw, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:grid, 1}}
Utils
defmodule Quadcopter do
def navigate(trees) do
x = trees
x_rev = x |> Enum.map(&Enum.reverse/1)
y = trees |> Enum.zip() |> Enum.map(&Tuple.to_list/1)
y_rev = y |> Enum.map(&Enum.reverse/1)
[x, x_rev, y, y_rev]
end
def analyze_visibility(line) do
Enum.map_reduce(line, -1, fn x, acc ->
if x > acc do
{false, x}
else
{true, acc}
end
end)
|> elem(0)
end
def analyze_scenic_score(value, line, score \\ 0)
def analyze_scenic_score(value, [compare | remainder], score) do
if value > compare do
analyze_scenic_score(value, remainder, score + 1)
else
score + 1
end
end
def analyze_scenic_score(_value, [], score), do: score
def analyze_scenic_score(line) do
for {x, index} <- Enum.with_index(line) do
seen = Enum.drop(line, index + 1)
analyze_scenic_score(x, seen)
end
end
def realign([x, x_rev, y, y_rev]) do
x_rev = x_rev |> Enum.map(&Enum.reverse/1)
y = y |> Enum.zip() |> Enum.map(&Tuple.to_list/1)
y_rev = y_rev |> Enum.map(&Enum.reverse/1) |> Enum.zip() |> Enum.map(&Tuple.to_list/1)
[x, x_rev, y, y_rev]
end
def combine_results(directions, combiner) do
Enum.reduce(directions, fn direction, acc ->
Enum.zip(direction, acc)
|> Enum.map(&Tuple.to_list/1)
|> Enum.map(&Enum.zip/1)
|> Enum.map(fn line ->
Enum.map(line, fn {a, b} -> combiner.(a, b) end)
end)
end)
end
end
{:module, Quadcopter, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:combine_results, 2}}
Part 1
visibility =
trees
|> Quadcopter.navigate()
|> Enum.map(fn direction -> Enum.map(direction, &Quadcopter.analyze_visibility/1) end)
|> Quadcopter.realign()
|> Quadcopter.combine_results(&(&1 and &2))
Draw.grid(visibility) |> IO.write()
count_of_not_hidden =
visibility
|> List.flatten()
|> Enum.count(&(!&1))
_____
___X_
__X__
_X_X_
_____
21
Part 2
scenic_scores =
trees
|> Quadcopter.navigate()
|> Enum.map(fn direction -> Enum.map(direction, &Quadcopter.analyze_scenic_score/1) end)
|> Quadcopter.realign()
|> Quadcopter.combine_results(&(&1 * &2))
scenic_scores
|> List.flatten()
|> Enum.max()
8