AoC 2022 Day 12
Mix.install([:kino, :libgraph])
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}, col}
end
end)
|> Map.new()
end
end
Setup
import Utils
input = Kino.Input.textarea("Input:")
text = Kino.Input.read(input)
map =
text
|> to_matrix()
|> Map.new(fn {k, <>} -> {k, v} end)
start_spot = map |> Enum.find(fn {_k, v} -> v == ?S end) |> elem(0)
end_spot = map |> Enum.find(fn {_k, v} -> v == ?E end) |> elem(0)
map =
map
|> Map.put(start_spot, ?a - 1)
|> Map.put(end_spot, ?z + 1)
neighbours = fn {x, y} -> [{x + 1, y}, {x - 1, y}, {x, y + 1}, {x, y - 1}] end
paths =
Enum.reduce(map, MapSet.new(), fn {pos, el}, set ->
Enum.reduce(neighbours.(pos), set, fn npos, set ->
nel = Map.get(map, npos, -1)
if nel - el <= 1 do
MapSet.put(set, {pos, npos})
else
set
end
end)
end)
graph = Graph.add_edges(Graph.new(), Enum.to_list(paths))
P1
Graph.get_shortest_path(graph, start_spot, end_spot) |> length |> Kernel.-(1)
P2
Enum.filter(map, fn {_k, v} -> v == ?a end)
|> Enum.map(&elem(&1, 0))
|> Kernel.++([start_spot])
|> Enum.map(fn spot ->
Graph.get_shortest_path(graph, spot, end_spot)
end)
|> Enum.reject(&is_nil/1)
|> Enum.map(
&(&1
|> length
|> Kernel.-(1))
)
|> Enum.min()