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

Untitled notebook

2023/elixir/day-11.livemd

Untitled notebook

Mix.install([
  {:kino, "~> 0.14.1"}
])

Part 1

input = Kino.Input.textarea("input")
input
|> Kino.Input.read()
|> String.split("\n")
|> Enum.with_index(0)
|> Enum.flat_map(fn {line, r} ->
  line
  |> String.to_charlist()
  |> Enum.with_index(0)
  |> Enum.filter(&match?({?#, _}, &1))
  |> Enum.map(fn {_, c} -> {r, c} end)
end)
defmodule Day11 do
  def input_to_space(input) do
    galaxies = galaxies(input)
    space_size = space_size(input)

    {galaxies, space_size}
  end

  defp galaxies(input) do
    input
    |> String.split("\n")
    |> Enum.with_index(0)
    |> Enum.flat_map(fn {line, r} ->
      line
      |> String.to_charlist()
      |> Enum.with_index(0)
      |> Enum.filter(&match?({?#, _}, &1))
      |> Enum.map(fn {_, c} -> {r, c} end)
    end)
  end

  defp space_size(input) do
    input
    |> String.split("\n")
    |> then(fn [l | _] = lines ->
      col = String.length(l)
      row = length(lines)
      {row, col}
    end)
  end

  def expand_universe({galaxies, {rows, cols} = space_size}, scale \\ 2) do
    {empty_rows, empty_cols} = empty_spaces({galaxies, space_size})

    expanded_galaxies = 
    for {r, c} <- galaxies do
      row_expanded = empty_rows |> Enum.count(&amp; &amp;1 < r) |> Kernel.*(scale - 1)
      col_expanded = empty_cols |> Enum.count(&amp; &amp;1 < c) |> Kernel.*(scale - 1)
      {r + row_expanded, c + col_expanded}
    end

    new_space_size = {rows + Enum.count(empty_rows), cols + Enum.count(empty_cols)}
    {expanded_galaxies, new_space_size}
  end

  defp empty_spaces({galaxies, space_size}) do
    {row, col} = space_size
    rows = galaxies |> Enum.map(&amp;elem(&amp;1, 0))
    cols = galaxies |> Enum.map(&amp;elem(&amp;1, 1))

    empty_rows = Enum.to_list(0..row-1) -- rows
    empty_cols = Enum.to_list(0..col-1) -- cols

    {empty_rows, empty_cols}
  end

  def find_shortest_paths({galaxies, _space_size}) do
    galaxies
    |> Enum.with_index()
    |> Enum.reduce(%{}, fn {{sr, sc}, i}, acc ->
      galaxies
      |> Enum.drop(i + 1)
      |> Enum.reduce(acc, fn {tr, tc}, acc ->
        dist = abs(tr - sr) + abs(tc - sc)
        Map.put(acc, {{sr, sc}, {tr, tc}}, dist)
      end)
    end)
  end
end

input
|> Kino.Input.read()
|> Day11.input_to_space()
|> Day11.expand_universe()
|> Day11.find_shortest_paths()
|> Map.values()
|> Enum.sum()

Part 2

input
|> Kino.Input.read()
|> Day11.input_to_space()
|> Day11.expand_universe(1000000)
|> Day11.find_shortest_paths()
|> Map.values()
|> Enum.sum()