Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 12

2022/day-12.livemd

Day 12

Mix.install([
  {:kino, "~> 0.7.0"},
  {:libgraph, "~> 0.16.0"}
])

example_input =
  Kino.Input.textarea("example input:")
  |> Kino.render()

real_input = Kino.Input.textarea("real input:")

Common

defmodule Heightmap do
  def graph(map) do
    for {coord, height} <- map, neighbor <- neighbors(coord), reduce: Graph.new() do
      graph ->
        if map[neighbor] <= height + 1 do
          Graph.add_edge(graph, coord, neighbor)
        else
          graph
        end
    end
  end

  defp neighbors({i, j}) do
    [
      {i, j + 1},
      {i + 1, j},
      {i, j - 1},
      {i - 1, j}
    ]
  end

  def new(rows) do
    for {row, i} <- Enum.with_index(rows),
        {col, j} <- Enum.with_index(row),
        reduce: {%{}, nil, nil} do
      {map, s, e} ->
        case col do
          ?S -> {Map.put(map, {i, j}, ?a), {i, j}, e}
          ?E -> {Map.put(map, {i, j}, ?z), s, {i, j}}
          height -> {Map.put(map, {i, j}, height), s, e}
        end
    end
  end
end

parse = fn input ->
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&amp;to_charlist/1)
end

Part 1

{map, s, e} =
  real_input
  |> then(parse)
  |> Heightmap.new()

Heightmap.graph(map)
|> Graph.dijkstra(s, e)
|> length()
|> Kernel.-(1)

Part 2

{map, _, e} =
  real_input
  |> then(parse)
  |> Heightmap.new()

graph = Heightmap.graph(map)

map
|> Enum.flat_map(&amp;if(elem(&amp;1, 1) == ?a, do: [elem(&amp;1, 0)], else: []))
|> Enum.flat_map(fn s ->
  case Graph.dijkstra(graph, s, e) do
    nil -> []
    list -> [length(list) - 1]
  end
end)
|> Enum.sort()
|> hd()