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

Advent of Code 2024 - Day 10

2024/day-10.livemd

Advent of Code 2024 - Day 10

Mix.install([
  {:kino, github: "livebook-dev/kino"},
  {:libgraph, "~> 0.16.0"},
])

kino_input = Kino.Input.textarea("Please paste your input file: ")

Part 1

input = Kino.Input.read(kino_input)

input
|> String.split("\n", trim: true)
|> Enum.with_index()
|> Enum.reduce(%{}, fn {row, row_index}, map ->
  row
  |> String.graphemes()
  |> Enum.with_index()
  |> Enum.reduce(map, fn {char, column_index}, acc ->
    case Integer.parse(char) do
      {digit, ""} ->
        Map.put(acc, {column_index, row_index}, digit)
      _ -> acc
    end
  end)
end)
|> then(fn digit_positions ->
  graph =
    digit_positions
    |> Enum.reduce(Graph.new(type: :directed), fn {coords, _}, g ->
      g |> Graph.add_vertex(coords)
    end)

  graph =
    Enum.reduce(digit_positions, graph, fn {{x1, y1} = coords1, n}, g ->
      [{x1, y1 - 1}, {x1, y1 + 1}, {x1 - 1, y1}, {x1 + 1, y1}]
      |> Enum.reduce(g, fn coords2, acc ->
        if Map.get(digit_positions, coords2) == n + 1 do
          Graph.add_edge(acc, coords1, coords2)
        else
          acc
        end
      end)
    end)

  positions_0 = 
    digit_positions
    |> Enum.filter(&elem(&1, 1) == 0)
    |> Enum.map(&elem(&1, 0))
  
  positions_9 = 
    digit_positions
    |> Enum.filter(&elem(&1, 1) == 9)
    |> Enum.map(&elem(&1, 0))

  for start <- positions_0,
    dest <- positions_9,
    Graph.get_paths(graph, start, dest) != [],
    reduce: 0,
    do: (sum -> sum + 1)
end)

Part 2

input = Kino.Input.read(kino_input)

input
|> String.split("\n", trim: true)
|> Enum.with_index()
|> Enum.reduce(%{}, fn {row, row_index}, map ->
  row
  |> String.graphemes()
  |> Enum.with_index()
  |> Enum.reduce(map, fn {char, column_index}, acc ->
    case Integer.parse(char) do
      {digit, ""} ->
        Map.put(acc, {column_index, row_index}, digit)
      _ -> acc
    end
  end)
end)
|> then(fn digit_positions ->
  graph =
    digit_positions
    |> Enum.reduce(Graph.new(type: :directed), fn {coords, _}, g ->
      g |> Graph.add_vertex(coords)
    end)

  graph =
    Enum.reduce(digit_positions, graph, fn {{x1, y1} = coords1, n}, g ->
      [{x1, y1 - 1}, {x1, y1 + 1}, {x1 - 1, y1}, {x1 + 1, y1}]
      |> Enum.reduce(g, fn coords2, acc ->
        if Map.get(digit_positions, coords2) == n + 1 do
          Graph.add_edge(acc, coords1, coords2)
        else
          acc
        end
      end)
    end)

  positions_0 = 
    digit_positions
    |> Enum.filter(&amp;elem(&amp;1, 1) == 0)
    |> Enum.map(&amp;elem(&amp;1, 0))
  
  positions_9 = 
    digit_positions
    |> Enum.filter(&amp;elem(&amp;1, 1) == 9)
    |> Enum.map(&amp;elem(&amp;1, 0))

  for start <- positions_0,
    dest <- positions_9,
    paths = Graph.get_paths(graph, start, dest),
    reduce: 0,
    do: (sum -> sum + length(paths))
end)