Advent of Code 2024 - Day 6
Mix.install([
{:kino_aoc, "~> 0.1.7"},
{:libgraph, "~> 0.16.0"}
])
Preparation
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "6", System.fetch_env!("LB_AOC_SESSION"))
input =
puzzle_input
|> String.split("\n")
|> Enum.map(&String.to_charlist/1)
obstacles =
for {row, i} <- Enum.with_index(input, 1),
{?#, j} <- Enum.with_index(row, 1),
into: MapSet.new(),
do: {i, j}
guard_i = Enum.find_index(input, & ?^ in &1)
guard_j = input |> Enum.at(guard_i) |> Enum.find_index(& &1 == ?^)
guard = {guard_i + 1, guard_j + 1}
imax = length(input)
jmax = length(hd(input))
Part 1
watched =
{guard, {-1, 0}}
|> Stream.iterate(fn {{i, j}, {di, dj}} ->
if {i + di, j + dj} in obstacles do
{{i, j}, {dj, -di}}
else
{{i + di, j + dj}, {di, dj}}
end
end)
|> Enum.reduce_while(MapSet.new(), fn {{i, j}, _dir} = state, seen ->
cond do
i == 0 -> {:halt, seen}
i > imax -> {:halt, seen}
j == 0 -> {:halt, seen}
j > jmax -> {:halt, seen}
state in seen -> {:halt, seen}
true -> {:cont, MapSet.put(seen, state)}
end
end)
|> Enum.map(&elem(&1, 0))
|> Enum.uniq()
length(watched)
Part 2
watched
|> List.delete(guard)
|> Task.async_stream(fn new_obstacle ->
obstacles = MapSet.put(obstacles, new_obstacle)
{guard, {-1, 0}}
|> Stream.iterate(fn {{i, j}, {di, dj}} ->
if {i + di, j + dj} in obstacles do
{{i, j}, {dj, -di}}
else
{{i + di, j + dj}, {di, dj}}
end
end)
|> Enum.reduce_while(MapSet.new(), fn {{i, j}, _dir} = state, seen ->
cond do
i == 0 -> {:halt, 0}
i > imax -> {:halt, 0}
j == 0 -> {:halt, 0}
j > jmax -> {:halt, 0}
state in seen -> {:halt, 1}
true -> {:cont, MapSet.put(seen, state)}
end
end)
end, ordered: false)
|> Stream.map(&elem(&1, 1))
|> Enum.sum()