Advent of Code - Day 8
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Problem
https://adventofcode.com/2024/day/8
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "8", System.fetch_env!("LB_AOC_SESSION"))
example_input = "............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............"
defmodule Day8 do
def antennas(map) do
map
|> Map.filter(fn {_,v} -> v != "." && v != "#" end)
|> Enum.group_by(fn {_,v} -> v end)
end
def pairs(antennas) do
for i <- antennas, j <- antennas, i != j, do: [i,j]
end
def find_antinodes(map, cb) do
antennas(map) |> Enum.flat_map(fn {_, antennas} ->
pairs(antennas)
|> Enum.flat_map(fn p ->
cb.(p, map)
end)
end) |> MapSet.new()
end
def antinodes([{a_pos, _}, {b_pos, _}], map) do
{dx, dy} = delta_pos(a_pos, b_pos)
{ax, ay} = a_pos
{bx, by} = b_pos
[
{ax + dx, ay + dy},
{bx - dx, by - dy}
] |> Enum.map(fn p ->
if Map.get(map, p) do
p
end
end)
|> Enum.filter(fn x -> x != nil end)
end
def compute_bounds(map) do
Enum.reduce(map, %{xmax: 0, ymax: 0}, fn {{x, y}, _}, acc ->
%{xmax: max(acc.xmax, x), ymax: max(acc.ymax, y)}
end)
end
def antinodes2([{a_pos, _}, {b_pos, _}], map) do
bounds = compute_bounds(map)
{dx, dy} = delta_pos(a_pos, b_pos)
{ax, ay} = a_pos
yiter = ceil(bounds.ymax / dy)
xiter = ceil(bounds.xmax / dx)
bound = max(yiter, xiter)
Enum.reduce(-bound..bound, [], fn magnitude, acc ->
pt = {ax + (magnitude*dx), ay + (magnitude*dy)}
if Map.get(map, pt) do
acc ++ [pt]
else
acc
end
end)
end
def delta_pos({ax, ay}, {bx, by}) do
{ax - bx, ay - by}
end
def parse(str) do
str
|> String.split("\n", trim: true)
|> Enum.with_index()
|> Enum.flat_map(fn {row, y} ->
row
|> String.graphemes()
|> Enum.with_index()
|> Enum.map(fn {char, x} -> {{x, y}, char} end)
end)
|> Enum.into(%{})
end
def solve_part1(str) do
parse(str) |> find_antinodes(&antinodes(&1,&2)) |> MapSet.size()
end
def solve_part2(str) do
parse(str) |> find_antinodes(&antinodes2(&1,&2)) |> MapSet.size()
end
end
Day8.solve_part1(example_input)
Day8.solve_part1(puzzle_input)
Part 2
example2 = "T....#....
...T......
.T....#...
.........#
..#.......
..........
...#......
..........
....#.....
.........."
Day8.antennas(Day8.parse(example2))
Day8.solve_part2(example2)
Day8.solve_part2(example_input)
Day8.solve_part2(puzzle_input)