defmodule MarsExplorer.InstructionsInterpreter do @moduledoc """ Module responsible for interpreting the exploration instructions """ @grid_regex ~r/\A(\d) (\d)\z/ @place_regex ~r/\A(\d) (\d) (N|E|S|W)\z/ @movements_regex ~r/^(L|M|R)+$/ @directions %{ "N" => :north, "E" => :east, "W" => :west, "S" => :south } @doc """ Interprets instructions from a instructions list. ## Examples iex> alias MarsExplorer.InstructionsInterpreter MarsExplorer.InstructionsInterpreter iex> instructions = ["5 5", "1 2 N", "LMLMLMLMM", "3 3 E", "MMRMMRMRRM"] ["5 5", "1 2 N", "LMLMLMLMM", "3 3 E", "MMRMMRMRRM"] iex> instructions |> InstructionsInterpreter.interpret() [ {:grid, %{north: 5, east: 5}}, {:place, %{north: 2, east: 1, direction: :north}}, [ :turn_left, :move, :turn_left, :move, :turn_left, :move, :turn_left, :move, :move ], {:place, %{north: 3, east: 3, direction: :east}}, [ :move, :move, :turn_right, :move, :move, :turn_right, :move, :turn_right, :turn_right, :move ] ] """ def interpret(instructions) do instructions |> Enum.map(&classify_instruction/1) |> Enum.map(&do_interpret/1) end defp classify_instruction(instruction) do %{ grid: String.match?(instruction, @grid_regex), place: String.match?(instruction, @place_regex), movements: String.match?(instruction, @movements_regex), instruction: instruction } end defp do_interpret(%{grid: true, instruction: instruction}) do to_integer = &String.to_integer/1 [_command, east, north] = Regex.run(@grid_regex, instruction) {:grid, %{east: to_integer.(east), north: to_integer.(north)}} end defp do_interpret(%{place: true, instruction: instruction}) do to_integer = &String.to_integer/1 [_command, east, north, direction] = Regex.run(@place_regex, instruction) {:place, %{east: to_integer.(east), north: to_integer.(north), direction: @directions[direction]}} end defp do_interpret(%{movements: true, instruction: instruction}) do instruction |> String.graphemes() |> Enum.map(&movement/1) end defp do_interpret(%{instruction: instruction}), do: {:invalid, instruction} defp movement("L"), do: :turn_left defp movement("R"), do: :turn_right defp movement("M"), do: :move end