Day 04
Mix.install([:kino_aoc])
Kino.configure(inspect: [charlists: :as_lists])
Input
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "4", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
parsed = puzzle_input
|> String.split("\n")
|> Stream.with_index()
|> Enum.map(fn {line, iy} ->
{
iy,
line
|> String.split("", trim: true)
|> Stream.with_index()
|> Enum.map(fn {char, ix} -> {ix, char} end)
|> Map.new()
}
end)
|> Map.new()
Part 1
defmodule Part1 do
def count_matches(parsed) do
Enum.reduce(parsed, 0, fn {iy, line}, acc ->
acc + Enum.reduce(line, 0, fn
{ix, "X"}, acc2 -> acc2 + matches_xmas?(parsed, iy, ix)
_, acc2 -> acc2
end)
end)
end
def matches_xmas?(parsed, iy, ix) do
directions = [
{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}
]
Enum.reduce(directions, 0, fn {dy, dx}, acc ->
acc + (if parsed[iy + dy][ix + dx] == "M" and
parsed[iy + 2*dy][ix + 2*dx] == "A" and
parsed[iy + 3*dy][ix + 3*dx] == "S", do: 1, else: 0)
end)
end
end
Part1.count_matches(parsed)
Part 2
defmodule Part2 do
def count_matches(parsed) do
Enum.reduce(parsed, 0, fn {iy, line}, acc ->
acc + Enum.reduce(line, 0, fn {ix, char}, acc2 ->
acc2 + if char == "A" and matches_xmas?(parsed, iy, ix), do: 1, else: 0
end)
end)
end
def matches_xmas?(parsed, iy, ix) do
directions = [
{1, 1}, {1, -1}, {-1, 1}, {-1, -1}
]
2 <= Enum.reduce(directions, 0, fn {dy, dx}, acc ->
acc + if parsed[iy + dy][ix + dx] == "M" and parsed[iy - dy][ix - dx] == "S", do: 1, else: 0
end)
end
end
Part2.count_matches(parsed)