85 lines
2.3 KiB
Elixir
85 lines
2.3 KiB
Elixir
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
|