d08
Section
defmodule D08 do
def parse(input) do
for {line, row} <- Enum.with_index(String.split(input, "\n", trim: true)),
{char, col} <- Enum.with_index(String.to_charlist(line)),
reduce: {%{}, 0, 0} do
{frequencies, height, width} ->
frequencies =
if char == ?. do
frequencies
else
Map.update(frequencies, char, [{row, col}], &[{row, col} | &1])
end
{frequencies, max(height, row + 1), max(width, col + 1)}
end
end
def in_bounds?({r, c}, height, width) do
r >= 0 and c >= 0 and r < height and c < width
end
def part1(frequencies, height, width) do
Map.values(frequencies)
|> Enum.flat_map(fn antennas ->
for {ar, ac} = a <- antennas,
{br, bc} = b <- antennas,
a < b do
{dr, dc} = {br - ar, bc - ac}
Enum.filter([{ar - dr, ac - dc}, {br + dr, bc + dc}], &D08.in_bounds?(&1, height, width))
end
|> List.flatten()
end)
|> Enum.uniq()
|> Enum.count()
end
def part2(frequencies, height, width) do
Map.values(frequencies)
|> Enum.flat_map(fn antennas ->
for {ar, ac} = a <- antennas,
{br, bc} = b <- antennas,
a < b do
{dr, dc} = {br - ar, bc - ac}
Stream.concat(
Stream.iterate(b, fn {r, c} -> {r - dr, c - dc} end)
|> Stream.take_while(&D08.in_bounds?(&1, height, width)),
Stream.iterate(b, fn {r, c} -> {r + dr, c + dc} end)
|> Stream.take_while(&D08.in_bounds?(&1, height, width))
)
|> Enum.to_list()
end
|> List.flatten()
end)
|> Enum.uniq()
|> Enum.count()
end
end
ExUnit.start()
defmodule D08.Test do
use ExUnit.Case
test "sample" do
sample = "............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............
"
{frequencies, height, width} = D08.parse(sample)
assert 14 == D08.part1(frequencies, height, width)
assert 34 == D08.part2(frequencies, height, width)
end
end
ExUnit.run()
input = File.read!(__DIR__ <> "/input")
{frequencies, height, width} = D08.parse(input)
D08.part1(frequencies, height, width)
D08.part2(frequencies, height, width)