Powered by AppSignal & Oban Pro

Day 11

notebooks/day11.livemd

Day 11

Mix.install([
  {:req, "~> 0.4.5"},
  {:kino, "~> 0.11.3"},
  {:nx, "~> 0.6.4"}
])

Input

input =
  Req.get!(
    "https://adventofcode.com/2023/day/11/input",
    headers: [{"Cookie", ~s"session=#{System.fetch_env!("LB_AOC_SESSION")}"}]
  ).body

Kino.Text.new(input, terminal: true)

Part 1

sky =
  for line <- String.split(input, "\n", trim: true) do
    for char <- String.graphemes(line) do
      if char == "#", do: 1, else: 0
    end
  end

sky_tensor = Nx.tensor(sky, type: :u8, names: [:y, :x])
empty_ys = Nx.any(sky_tensor, axes: [:x]) |> Nx.logical_not() |> Nx.to_list()
empty_xs = Nx.any(sky_tensor, axes: [:y]) |> Nx.logical_not() |> Nx.to_list()

pad_ys =
  empty_ys
  |> Enum.with_index()
  |> Enum.flat_map(fn {empty, index} -> List.duplicate(index, empty + 1) end)
  |> Nx.tensor(type: :u8)

pad_xs =
  empty_xs
  |> Enum.with_index()
  |> Enum.flat_map(fn {empty, index} -> List.duplicate(index, empty + 1) end)
  |> Nx.tensor(type: :u8)

big_sky =
  sky_tensor
  |> Nx.take(pad_ys, axis: :y)
  |> Nx.take(pad_xs, axis: :x)

galaxies =
  for {line, y} <- big_sky |> Nx.to_list() |> Enum.with_index(),
      {galaxy, x} <- Enum.with_index(line),
      reduce: [] do
    acc -> if galaxy == 1, do: [{y, x} | acc], else: acc
  end

pairs =
  for {{y1, x1}, i} <- Enum.with_index(galaxies),
      {y2, x2} <- Enum.drop(galaxies, i + 1) do
    [[y1, x1], [y2, x2]]
  end
  |> Nx.tensor(type: :s64)

Nx.abs(Nx.subtract(pairs[[.., 0, 0]], pairs[[.., 1, 0]]))
|> Nx.add(Nx.abs(Nx.subtract(pairs[[.., 0, 1]], pairs[[.., 1, 1]])))
|> Nx.sum()

Part 2

galaxies =
  for {line, y} <- sky |> Enum.with_index(),
      {galaxy, x} <- Enum.with_index(line),
      reduce: [] do
    acc -> if galaxy == 1, do: [{y, x} | acc], else: acc
  end

y_indexes =
  empty_ys
  |> Enum.with_index()
  |> Enum.flat_map(fn
    {1, i} -> [i]
    _ -> []
  end)

x_indexes =
  empty_xs
  |> Enum.with_index()
  |> Enum.flat_map(fn
    {1, i} -> [i]
    _ -> []
  end)

galaxies =
  for {y, x} <- galaxies do
    sy = Enum.count(y_indexes, &amp;(&amp;1 < y))
    sx = Enum.count(x_indexes, &amp;(&amp;1 < x))
    {y + 999_999 * sy, x + 999_999 * sx}
  end

pairs =
  for {{y1, x1}, i} <- Enum.with_index(galaxies),
      {y2, x2} <- Enum.drop(galaxies, i + 1) do
    [[y1, x1], [y2, x2]]
  end
  |> Nx.tensor(type: :s64)

Nx.abs(Nx.subtract(pairs[[.., 0, 0]], pairs[[.., 1, 0]]))
|> Nx.add(Nx.abs(Nx.subtract(pairs[[.., 0, 1]], pairs[[.., 1, 1]])))
|> Nx.sum()