my-solutions/advent-of-code-2023/elixir/day_08/lib/navigator.ex

86 lines
2.3 KiB
Elixir
Raw Permalink Normal View History

defmodule Navigator do
@doc """
Count steps for the first part.
# Examples
iex> Navigator.count_steps(["R"], %{"AAA" => ["AAA", "ZZZ"], "ZZZ" => ["ZZZ", "ZZZ"]})
1
"""
@spec count_steps(list(String.t()), map()) :: integer()
def count_steps(instructions, maps) do
count_steps(instructions, instructions, maps, "AAA", 0)
end
defp count_steps(full_instruction_list, [dir | next_instructions], maps, state, steps) do
new_state = pick_destination(maps[state], dir)
case new_state do
"ZZZ" ->
steps + 1
_ ->
# Go to the beginning of the list of instructions if we are at the end.
next_instructions =
case next_instructions do
[] -> full_instruction_list
_ -> next_instructions
end
count_steps(full_instruction_list, next_instructions, maps, new_state, steps + 1)
end
end
@doc """
Count steps for the second part.
# Examples
iex> Navigator.count_ghost_steps(["R"], %{"BBA" => ["BBA", "BBZ"], "BBZ" => ["BBZ", "BBZ"]})
1
"""
def count_ghost_steps(instructions, maps) do
maps
|> Map.keys()
|> Stream.filter(fn x -> String.ends_with?(x, "A") end)
|> Stream.map(fn x -> count_ghost_steps(instructions, instructions, maps, x, 0) end)
# compute least common multiple
|> Enum.reduce(1, fn x, acc -> Math.lcm(x, acc) end)
end
defp count_ghost_steps(full_instruction_list, [dir | next_instructions], maps, state, steps) do
new_state = pick_destination(maps[state], dir)
if String.ends_with?(new_state, "Z") do
steps + 1
else
# Go to the beginning of the list of instructions if we are at the end.
next_instructions =
case next_instructions do
[] -> full_instruction_list
_ -> next_instructions
end
count_ghost_steps(full_instruction_list, next_instructions, maps, new_state, steps + 1)
end
end
@doc """
Pick destination.
# Examples
iex> Navigator.pick_destination(["AAA", "BBB"], "L")
"AAA"
iex> Navigator.pick_destination(["AAA", "BBB"], "R")
"BBB"
"""
def pick_destination(destinations, direction) do
case direction do
"L" -> hd(destinations)
"R" -> hd(tl(destinations))
end
end
end