74 lines
1.8 KiB
Elixir
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
|