aoc/23/elixir/lib/days/day11.ex
2023-12-11 15:04:33 +01:00

74 lines
1.8 KiB
Elixir

defmodule AOC.Day11 do
use AOC.Day, day: 11
def parse_input(lines) do
Enum.map(lines, &String.to_charlist/1)
end
def part1(image), do: calculate_distance_sum(image, 2)
def part2(image), do: calculate_distance_sum(image, 1_000_000)
def calculate_distance_sum(image, scaler) do
empty_space = find_empty_space(image)
find_galaxy_positions(image)
|> expand_galaxy_positions(empty_space, scaler)
|> calculate_shortest_paths()
|> Enum.sum()
end
def find_empty_space(image) do
empty_rows = find_empty_rows(image)
empty_columns =
image
|> List.zip()
|> Enum.map(&Tuple.to_list/1)
|> find_empty_rows()
{empty_rows, empty_columns}
end
def find_empty_rows(image) do
image
|> Enum.with_index()
|> Enum.filter(fn {row, _} -> Enum.all?(row, &(&1 == ?.)) end)
|> Enum.map(&elem(&1, 1))
end
def find_galaxy_positions(image) do
image
|> Enum.map(fn row ->
row
|> Enum.with_index()
|> Enum.filter(fn {space, _} -> space == ?# end)
|> Enum.map(&elem(&1, 1))
end)
|> Enum.with_index()
|> Enum.flat_map(fn {xs, y} ->
Enum.map(xs, &{y, &1})
end)
end
def expand_galaxy_positions(galaxy_positions, {empty_rows, empty_columns}, scaler) do
Enum.map(galaxy_positions, fn {y, x} ->
shift_y = Enum.count(empty_rows, &(&1 < y))
shift_x = Enum.count(empty_columns, &(&1 < x))
{y + shift_y * (scaler - 1), x + shift_x * (scaler - 1)}
end)
end
def calculate_shortest_paths(galaxy_positions) do
for g1 <- galaxy_positions, g2 <- galaxy_positions do
[g1, g2]
end
|> Enum.reject(fn [g1, g2] -> g1 == g2 end)
|> Enum.map(&Enum.sort/1)
|> Enum.uniq()
|> Enum.map(fn [{y1, x1}, {y2, x2}] ->
abs(y1 - y2) + abs(x1 - x2)
end)
end
end