1
0
Fork 0
advent-of-code/2024/lib/2024/8.ex
2024-12-08 08:57:36 -05:00

59 lines
1.5 KiB
Elixir

import AOC
import AOC.Prelude
aoc 2024, 8 do
def p1(input) do
input
|> map_grid()
|> count_antinodes(&antinodes_for_tower_pair/1)
end
def p2(input) do
grid = map_grid(input)
count_antinodes(grid, &resonant_harmonics_antinodes_for_tower_pair(&1, grid))
end
##
defp count_antinodes(grid, antinodes_for_tower_fun) do
grid
|> find_tower_pairs()
|> Enum.map(&elem(&1, 0))
|> Enum.flat_map(antinodes_for_tower_fun)
|> Enum.filter(&in_bounds?(grid, &1))
|> Enum.uniq()
|> Enum.count()
end
defp find_tower_pairs(grid) do
tower_locaions = Map.reject(grid, &match?({_, "."}, &1))
for {pos_a, t} <- tower_locaions, {pos_b, ^t} <- tower_locaions, pos_a != pos_b, into: %{} do
{[pos_a, pos_b]
|> Enum.sort()
|> List.to_tuple(), t}
end
end
defp antinodes_for_tower_pair({pos_a, pos_b}) do
d = delta(pos_a, pos_b)
[sub_delta(pos_a, d), add_delta(pos_b, d)]
end
defp resonant_harmonics_antinodes_for_tower_pair({pos_a, pos_b}, grid) do
d = delta(pos_a, pos_b)
sub_stream = pos_a |> Stream.iterate(&sub_delta(&1, d)) |> Stream.take_while(&in_bounds?(grid, &1))
add_stream = pos_b |> Stream.iterate(&add_delta(&1, d)) |> Stream.take_while(&in_bounds?(grid, &1))
sub_stream
|> Stream.concat(add_stream)
|> Enum.to_list()
end
defp delta({x1, y1}, {x2, y2}), do: {x2 - x1, y2 - y1}
defp add_delta({x, y}, {xd, yd}), do: {x + xd, y + yd}
defp sub_delta({x, y}, {xd, yd}), do: {x - xd, y - yd}
end