Skip to content

Instantly share code, notes, and snippets.

@code-shoily
Last active December 13, 2022 04:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save code-shoily/a9e2790210409d80aa1df29d70695cee to your computer and use it in GitHub Desktop.
Save code-shoily/a9e2790210409d80aa1df29d70695cee to your computer and use it in GitHub Desktop.
Advent of Code 2022/15 LiveBook attempt 1

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: 900, height: 250)
  |> Vl.layers([
    Vl.new()
    |> Vl.data_from_values(
      Enum.map(
        map,
        fn {{x, y}, h} -> %{"x" => y, "y" => x, "h" => ?z - h} 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: 2, 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" => -10})
  Process.sleep(10)
end

:ok
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
solution_1 = (paths |> Enum.map(&length/1) |> Enum.min()) - 1
Vl.new(width: 900, height: 250)
|> Vl.layers([
  Vl.new()
  |> Vl.data_from_values(
    Enum.map(
      map,
      fn {{x, y}, h} -> %{"x" => y, "y" => x, "h" => ?z - h} end
    )
  )
  |> Vl.mark(:rect, opacity: 1)
  |> 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)
  | 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 * -20} 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
])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment