Powered by AppSignal & Oban Pro

Advent of code day 11

2023/livebooks/day-11.livemd

Advent of code day 11

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

Setup input

example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")
defmodule Combinations do
  def combinations(_, 0), do: [[]]
  def combinations([], _), do: []
  
  def combinations([h | t], r) do
    (for combo <- combinations(t, r - 1), do: [h | combo]) ++ combinations(t, r)
  end
end
lines =
  example
  |> Kino.Input.read()
  |> String.split("\n", trim: true)


grid =
  Enum.map(lines, fn line ->
    line
    |> String.split("", trim: true)
    |> List.to_tuple()
  end)
  |> List.to_tuple()

total_cols = tuple_size(elem(grid, 0)) - 1
total_rows = (lines |> Enum.count()) - 1

empty_rows=
  grid
  |> Tuple.to_list()
  |> Enum.with_index()
  |> Enum.map(fn {row, i} ->
    if Tuple.to_list(row) |> Enum.all?(&amp;Kernel.==(&amp;1, ".")), do: i, else: nil
  end)
  |> Enum.reject(&amp;Kernel.==(&amp;1, nil))

empty_cols =
  grid
  |> Tuple.to_list()
  |> Enum.map(&amp;Tuple.to_list/1)
  |> Enum.zip_with(&amp;Function.identity/1)
  |> Enum.with_index()
  |> Enum.map(fn {row, i} ->
    if row |> Enum.all?(&amp;Kernel.==(&amp;1, ".")), do: i, else: nil
  end)
  |> Enum.reject(&amp;Kernel.==(&amp;1, nil))

points =
  for r <- 0..total_rows, c <- 0..total_cols, elem(grid, r) |> elem(c) == "#" do
    {r, c}
  end

Part 01 & 02

combs = Combinations.combinations(points, 2)
expansion_factor = 1000000

Enum.reduce(combs, 0, fn [{r1, c1}, {r2, c2}], total ->

  empty_rows_between = 
    Enum.count(empty_rows, fn r -> r > min(r1, r2) and r < max(r1, r2) end)
  
  empty_cols_between = 
    Enum.count(empty_cols, fn c -> c > min(c1, c2) and c < max(c1, c2) end)
  
  base_distance = abs(r1 - r2) + abs(c1 - c2)
  
  expansion = (empty_rows_between + empty_cols_between) * (expansion_factor - 1)
  
  base_distance + expansion + total
end)