Current section
Files
Jump to
Current section
Files
lib/exploration.ex
defmodule MarsExplorer.Exploration do
@moduledoc """
Module responsible for managing a exploration
"""
alias MarsExplorer.{Probe, Exploration, HighlandGrid}
defstruct [:grid, :probe]
@type placement :: %{
north: integer,
east: integer,
direction: :west | :north | :south | :east
}
@type t :: %__MODULE__{
grid: MarsExplorer.HighlandGrid.t(),
probe: MarsExplorer.Probe.t()
}
@doc """
Places a probe on a grid
## Examples
When the probe is placed in a valid position
iex> alias MarsExplorer.{Probe, Exploration, HighlandGrid}
[MarsExplorer.Probe, MarsExplorer.Exploration, MarsExplorer.HighlandGrid]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> Exploration.place(grid, %{north: 0, east: 0, direction: :north})
{
:ok,
%Exploration{
grid: grid,
probe: %Probe{north: 0, east: 0, direction: :north}
}
}
When the probe is placed in a invalid position
iex> alias MarsExplorer.{Exploration, HighlandGrid}
[MarsExplorer.Exploration, MarsExplorer.HighlandGrid]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> Exploration.place(grid, %{north: 6, east: 6, direction: :north})
{:error, :invalid_placement}
"""
@spec place(HighlandGrid.t(), placement()) :: {:ok, t()} | {:error, :invalid_placement}
def place(grid, placement) do
if grid |> HighlandGrid.valid_position?(placement) do
{
:ok,
%Exploration{
grid: grid,
probe: struct(Probe, placement)
}
}
else
{:error, :invalid_placement}
end
end
@doc """
Moves the probe forward one unit in the direction that it is facing, unless that position is past the limits of the grid.
## Examples
### A valid movement
iex> alias MarsExplorer.{Probe, HighlandGrid, Exploration}
[MarsExplorer.Probe, MarsExplorer.HighlandGrid, MarsExplorer.Exploration]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> exploration = %Exploration{
...> grid: grid,
...> probe: %Probe{north: 0, east: 0, direction: :north}
...> }
iex> exploration |> Exploration.move
{:ok, %Exploration{
grid: grid,
probe: %Probe{north: 1, east: 0, direction: :north}
}}
### An invalid movement:
iex> alias MarsExplorer.{Probe, HighlandGrid, Exploration}
[MarsExplorer.Probe, MarsExplorer.HighlandGrid, MarsExplorer.Exploration]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> exploration = %Exploration{
...> grid: grid,
...> probe: %Probe{north: 5, east: 0, direction: :north}
...> }
iex> exploration |> Exploration.move()
{:error, :at_grid_limit}
"""
@spec move(t()) :: {:ok, t()} | {:error, :at_grid_limit}
def move(%{probe: probe, grid: grid} = exploration) do
with moved_probe <- probe |> Probe.move(),
true <- grid |> HighlandGrid.valid_position?(moved_probe) do
{:ok, %{exploration | probe: moved_probe}}
else
false -> {:error, :at_grid_limit}
end
end
@doc """
Turns the probe left.
## Examples
iex> alias MarsExplorer.{Probe, HighlandGrid, Exploration}
[MarsExplorer.Probe, MarsExplorer.HighlandGrid, MarsExplorer.Exploration]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> exploration = %Exploration{
...> grid: grid,
...> probe: %Probe{north: 0, east: 0, direction: :north}
...> }
iex> exploration |> Exploration.turn_left
{:ok, %Exploration{
grid: grid,
probe: %Probe{north: 0, east: 0, direction: :west}
}}
"""
@spec turn_left(t()) :: {:ok, t()}
def turn_left(%Exploration{probe: probe} = exploration) do
{:ok, %{exploration | probe: probe |> Probe.turn_left()}}
end
@doc """
Turns the probe left.
## Examples
iex> alias MarsExplorer.{Probe, HighlandGrid, Exploration}
[MarsExplorer.Probe, MarsExplorer.HighlandGrid, MarsExplorer.Exploration]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> exploration = %Exploration{
...> grid: grid,
...> probe: %Probe{north: 0, east: 0, direction: :north}
...> }
iex> exploration |> Exploration.turn_right
{:ok, %Exploration{
grid: grid,
probe: %Probe{north: 0, east: 0, direction: :east}
}}
"""
@spec turn_right(t()) :: {:ok, t()}
def turn_right(%Exploration{probe: probe} = exploration) do
{:ok, %{exploration | probe: probe |> Probe.turn_right()}}
end
@doc """
Returns the probe's current position.
## Examples
iex> alias MarsExplorer.{Probe, HighlandGrid, Exploration}
[MarsExplorer.Probe, MarsExplorer.HighlandGrid, MarsExplorer.Exploration]
iex> grid = HighlandGrid.build(%{north: 5, east: 5})
%HighlandGrid{north_limit: 5, east_limit: 5}
iex> exploration = %Exploration{
...> grid: grid,
...> probe: %Probe{north: 0, east: 0, direction: :north}
...> }
iex> exploration |> Exploration.report
%Probe{north: 0, east: 0, direction: :north}
"""
@spec report(t()) :: {:ok, Probe.t()}
def report(%Exploration{probe: probe}), do: probe
end