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

Advent of Code 2023 - Day 11

2023/11.livemd

Advent of Code 2023 - Day 11

Mix.install([
  {:kino, "~> 0.11.0"},
  {:kino_aoc, github: "ljgago/kino_aoc"}
])

Input

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "11", System.fetch_env!("LB_AOC_SESSION"))
universe =
  puzzle_input
  |> String.split("\n", trim: true)
  |> Enum.map(&String.split(&1, "", trim: true))
expand_rows = fn input ->
  input
  |> Enum.flat_map(fn line ->
    if Enum.all?(line, &(&1 == "." or &1 == "X")) do
      [Enum.map(0..Enum.count(line), fn _ -> "X" end)]
    else
      [line]
    end
  end)
end

to_map = fn list ->
  list
  |> Enum.with_index()
  |> Map.new(fn {v, k} -> {k, v} end)
end

universe =
  universe
  |> expand_rows.()
  |> Enum.zip_with(&Function.identity/1)
  |> expand_rows.()
  |> Enum.zip_with(&Function.identity/1)
  |> Enum.map(to_map)
  |> to_map.()
galaxies =
  for {y, row} <- universe, {x, space} <- row, reduce: [] do
    acc -> if space == "#", do: [{x, y} | acc], else: acc
  end
pairs =
  for a <- galaxies, b <- galaxies, a != b do
    if a < b, do: {a, b}, else: {b, a}
  end
  |> Enum.uniq()

Part 1

defmodule Universe do
  def sum_distances(universe, galaxy_pairs, size) do
    for {a, b} <- galaxy_pairs, reduce: 0 do
      acc -> acc + distance(universe, a, b, size)
    end
  end

  defp distance(universe, {x1, y1}, {x2, y2}, size) do
    x_expansions = Enum.count(x1..x2, fn x -> universe[y1][x] == "X" end)
    y_expansions = Enum.count(y1..y2, fn y -> universe[y][x2] == "X" end)
    x_distance = abs(x1 - x2) - x_expansions + x_expansions * size
    y_distance = abs(y1 - y2) - y_expansions + y_expansions * size

    x_distance + y_distance
  end
end

Universe.sum_distances(universe, pairs, 2)

Part 2

Universe.sum_distances(universe, pairs, 1_000_000)

Run in Livebook