AoC 2022 Day 8
Mix.install([:kino])
defmodule Utils do
def split(line, sep \\ "") do
String.split(line, sep, trim: true)
end
def split_all_lines(text, sep \\ "") do
text
|> String.split("\n", trim: true)
|> Enum.map(&split(&1, sep))
end
def to_numbers(number) when is_binary(number) do
String.to_integer(number)
end
def to_numbers(numbers) when is_list(numbers) do
Enum.map(numbers, &to_numbers/1)
end
def to_matrix(text, sep \\ "") do
text
|> split_all_lines(sep)
|> then(fn data ->
for {row, r} <- Enum.with_index(data), {col, c} <- Enum.with_index(row) do
{{r, c}, String.to_integer(col)}
end
end)
|> Map.new()
end
end
Setup
import Utils
input = Kino.Input.textarea("Input:")
text = Kino.Input.read(input)
data = to_matrix(text)
P1
defmodule P1 do
def solve(text) do
edge = text |> String.split("\n", trim: true) |> length
edge_visible = edge |> Kernel.*(4) |> Kernel.-(4)
data = to_matrix(text)
visible =
Enum.reduce(1..(edge - 2), MapSet.new(), fn row, set ->
{_, set} =
Enum.reduce(1..(edge - 2), {data[{row, 0}], set}, fn col, {max, set} ->
process(row, col, max, set, data)
end)
{_, set} =
Enum.reduce((edge - 2)..1//-1, {data[{row, edge - 1}], set}, fn col, {max, set} ->
process(row, col, max, set, data)
end)
set
end)
visible =
Enum.reduce(1..(edge - 2), visible, fn col, set ->
{_, set} =
Enum.reduce(1..(edge - 2), {data[{0, col}], set}, fn row, {max, set} ->
process(row, col, max, set, data)
end)
{_, set} =
Enum.reduce((edge - 2)..1//-1, {data[{edge - 1, col}], set}, fn row, {max, set} ->
process(row, col, max, set, data)
end)
set
end)
MapSet.size(visible) + edge_visible
end
defp process(row, col, max, set, data) do
if (h = data[{row, col}]) > max do
{h, MapSet.put(set, {row, col})}
else
{max, set}
end
end
end
P1.solve(text)
P2
defmodule P2 do
def solve(text) do
edge = text |> String.split("\n", trim: true) |> length
data = to_matrix(text)
map =
Enum.reduce(0..(edge - 1), %{}, fn row, map ->
{_, map} =
Enum.reduce(
0..(edge - 1),
{%{}, map},
fn col, {near, map} ->
h = data[{row, col}]
v = Enum.map(9..h//-1, &near[&1]) |> Enum.reject(&is_nil/1)
v =
if match?([], v) do
col
else
col - Enum.max(v)
end
{Map.put(near, h, col), Map.update(map, {row, col}, v, &(&1 * v))}
end
)
{_, map} =
Enum.reduce(
(edge - 1)..0//-1,
{%{}, map},
fn col, {near, map} ->
h = data[{row, col}]
v = Enum.map(9..h//-1, &near[&1]) |> Enum.reject(&is_nil/1)
v =
if match?([], v) do
edge - 1 - col
else
Enum.min(v) - col
end
{Map.put(near, h, col), Map.update(map, {row, col}, v, &(&1 * v))}
end
)
map
end)
map =
Enum.reduce(0..(edge - 1), map, fn col, map ->
{_, map} =
Enum.reduce(
0..(edge - 1),
{%{}, map},
fn row, {near, map} ->
h = data[{row, col}]
v = Enum.map(9..h//-1, &near[&1]) |> Enum.reject(&is_nil/1)
v =
if match?([], v) do
row
else
row - Enum.max(v)
end
{Map.put(near, h, row), Map.update(map, {row, col}, v, &(&1 * v))}
end
)
{_, map} =
Enum.reduce(
(edge - 1)..0//-1,
{%{}, map},
fn row, {near, map} ->
h = data[{row, col}]
v = Enum.map(9..h//-1, &near[&1]) |> Enum.reject(&is_nil/1)
v =
if match?([], v) do
edge - 1 - row
else
Enum.min(v) - row
end
{Map.put(near, h, row), Map.update(map, {row, col}, v, &(&1 * v))}
end
)
map
end)
map |> Map.values() |> Enum.max()
end
end
P2.solve(text)