Day 12
Mix.install([
{:vega_lite, "~> 0.1.6"},
{:kino_vega_lite, "~> 0.1.7"}
])
alias VegaLite, as: Vl
Part 1
kino_input = Kino.Input.textarea("Enter the input")
raw_input = Kino.Input.read(kino_input)
defmodule Solution do
def grid2d(data, tx \\ &Function.identity/1) do
for {row, row_idx} <- Enum.with_index(data),
{cell, col_idx} <- Enum.with_index(row),
into: %{} do
{{row_idx, col_idx}, tx.(cell)}
end
end
def parse(data) do
map =
data
|> String.split("\n", trim: true)
|> Enum.map(&String.graphemes/1)
|> grid2d(fn char -> :binary.first(char) end)
source = elem(Enum.find(map, fn {_, v} -> v == ?S end), 0)
destination = elem(Enum.find(map, fn {_, v} -> v == ?E end), 0)
map = %{map | source => ?a, destination => ?z}
{map, source, destination}
end
def to_digraph(grid) do
graph = :digraph.new()
Enum.reduce(grid, graph, fn {{x, y}, _}, _ ->
[{x - 1, y}, {x + 1, y}, {x, y - 1}, {x, y + 1}]
|> Enum.filter(&Map.has_key?(grid, &1))
|> Enum.map(fn point ->
unless grid[point] - grid[{x, y}] > 1 do
{{x, y}, point}
end
end)
|> Enum.reject(&is_nil/1)
|> Enum.each(fn {v1, v2} ->
:digraph.add_vertex(graph, v1)
:digraph.add_vertex(graph, v2)
:digraph.add_edge(graph, v1, v2)
end)
end)
graph
end
end
{map, source, destination} = Solution.parse(raw_input)
graph = Solution.to_digraph(map)
path = :digraph.get_short_path(graph, source, destination)
:ok
path_chart =
Vl.new(width: 800, height: 200)
|> Vl.layers([
Vl.new()
|> Vl.data_from_values(
Enum.map(
map,
fn {{x, y}, h} ->
case {x, y} do
^destination -> %{"x" => y, "y" => x, "h" => 30}
_ -> %{"x" => y, "y" => x, "h" => ?z - h}
end
end
)
)
|> Vl.mark(:rect, opacity: 0.9)
|> Vl.encode_field(:x, "x", type: :nominal, axis: nil)
|> Vl.encode_field(:y, "y", type: :nominal, axis: nil)
|> Vl.encode(:color, field: "h", type: :quantitative),
Vl.new()
|> Vl.mark(:point, opacity: 1, size: 1, color: :red)
|> Vl.encode_field(:x, "x", type: :nominal, axis: nil)
|> Vl.encode_field(:y, "y", type: :nominal, axis: nil)
|> Vl.encode(:color, field: "h", type: :quantitative)
])
|> Kino.VegaLite.new()
|> Kino.render()
for {x, y} <- path do
Kino.VegaLite.push(path_chart, %{"x" => y, "y" => x, "h" => -25})
Process.sleep(10)
end
:ok
Solution Part 1
solution_1 = length(path) - 1
Part 2
sources = Enum.map(Enum.filter(map, fn {_, v} -> v == ?a end), &elem(&1, 0))
paths =
sources
|> Enum.map(fn source ->
:digraph.get_short_path(graph, source, destination)
end)
|> Enum.filter(& &1)
:ok
Vl.new(width: 800, height: 200)
|> Vl.layers(
for path <- paths do
Vl.new()
|> Vl.data_from_values(
path
|> Enum.with_index()
|> Enum.map(fn {{x, y}, h} -> %{"x" => y, "y" => x, "h" => h} end)
)
|> Vl.mark(:point, opacity: 1, size: 2)
|> Vl.encode_field(:x, "x", type: :nominal, axis: nil)
|> Vl.encode_field(:y, "y", type: :nominal, axis: nil)
|> Vl.encode(:color, field: "h", type: :quantitative)
end
)
Solution Part II
solution_2 = (paths |> Enum.map(&length/1) |> Enum.min()) - 1