mirror of
https://github.com/Xevion/exercism.git
synced 2025-12-05 23:14:54 -06:00
91 lines
2.4 KiB
Elixir
91 lines
2.4 KiB
Elixir
defmodule RobotSimulator do
|
|
defmodule Robot, do: defstruct([:position, :direction])
|
|
|
|
@directions [:north, :east, :south, :west]
|
|
@turns %{"R" => 1, "L" => -1}
|
|
|
|
defguardp is_direction(direction) when direction in [:north, :east, :south, :west]
|
|
|
|
defguardp is_position(position)
|
|
when is_tuple(position) and tuple_size(position) == 2 and
|
|
is_integer(elem(position, 0)) and is_integer(elem(position, 1))
|
|
|
|
@doc """
|
|
Create a Robot Simulator given an initial direction and position.
|
|
|
|
Valid directions are: `:north`, `:east`, `:south`, `:west`
|
|
"""
|
|
@spec create(direction :: atom, position :: {integer, integer}) :: any
|
|
def create(direction \\ :north, position \\ {0, 0})
|
|
|
|
def create(direction, _position) when not is_direction(direction),
|
|
do: {:error, "invalid direction"}
|
|
|
|
def create(_direction, position) when not is_position(position),
|
|
do: {:error, "invalid position"}
|
|
|
|
def create(direction, position) do
|
|
%Robot{position: position, direction: direction}
|
|
end
|
|
|
|
@doc """
|
|
Simulate the robot's movement given a string of instructions.
|
|
|
|
Valid instructions are: "R" (turn right), "L", (turn left), and "A" (advance)
|
|
"""
|
|
@spec simulate(robot :: any, instructions :: String.t()) :: any
|
|
def simulate(robot, ""), do: robot
|
|
|
|
def simulate(
|
|
%Robot{position: position, direction: direction} = robot,
|
|
<<head::bytes-size(1)>> <> tail
|
|
) do
|
|
case head do
|
|
"A" ->
|
|
simulate(%Robot{robot | position: get_change(position, direction)}, tail)
|
|
|
|
"L" ->
|
|
simulate(%Robot{robot | direction: get_turn(head, direction)}, tail)
|
|
|
|
"R" ->
|
|
simulate(%Robot{robot | direction: get_turn(head, direction)}, tail)
|
|
|
|
_ ->
|
|
{:error, "invalid instruction"}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Return the robot's direction.
|
|
|
|
Valid directions are: `:north`, `:east`, `:south`, `:west`
|
|
"""
|
|
@spec direction(robot :: any) :: atom
|
|
def direction(robot) do
|
|
robot.direction
|
|
end
|
|
|
|
@doc """
|
|
Return the robot's position.
|
|
"""
|
|
@spec position(robot :: any) :: {integer, integer}
|
|
def position(robot) do
|
|
robot.position
|
|
end
|
|
|
|
def get_turn(turn, direction) do
|
|
@directions
|
|
|> Enum.fetch(rem(Enum.find_index(@directions, &(&1 == direction)) + @turns[turn], 4))
|
|
|> elem(1)
|
|
end
|
|
|
|
def get_change({x, y}, direction) do
|
|
case direction do
|
|
:north -> {x, y + 1}
|
|
:east -> {x + 1, y}
|
|
:south -> {x, y - 1}
|
|
:west -> {x - 1, y}
|
|
end
|
|
end
|
|
end
|