Skip to content

Commit

Permalink
End of Chapter 7
Browse files Browse the repository at this point in the history
  • Loading branch information
radar committed Jul 27, 2019
1 parent ee4f6ac commit 175f80c
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 1 deletion.
14 changes: 14 additions & 0 deletions lib/toy_robot/application.ex
@@ -0,0 +1,14 @@
defmodule ToyRobot.Application do
use Application

def start(_type, _args) do
children = [
ToyRobot.Game.PlayerSupervisor
]

# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: ToyRobot.Supervisor]
Supervisor.start_link(children, opts)
end
end
Empty file added lib/toy_robot/game/game.ex
Empty file.
46 changes: 46 additions & 0 deletions lib/toy_robot/game/player.ex
@@ -0,0 +1,46 @@
defmodule ToyRobot.Game.Player do
use GenServer

alias ToyRobot.{Robot, Simulation, Table}

def start(robot) do
GenServer.start(__MODULE__, robot)
end

def start_link([position: position, name: name]) do
GenServer.start_link(__MODULE__, position, name: process_name(name))
end

def init(position) do
simulation = %Simulation{
table: %Table{
north_boundary: 4,
east_boundary: 4,
},
robot: struct(Robot, position)
}

{:ok, simulation}
end

def process_name(name) do
{:via, Registry, {ToyRobot.Game.PlayerRegistry, name}}
end

def report(player) do
GenServer.call(player, :report)
end

def move(player) do
GenServer.call(player, :move)
end

def handle_call(:report, _from, simulation) do
{:reply, simulation |> Simulation.report, simulation}
end

def handle_call(:move, _from, simulation) do
{:ok, new_simulation} = simulation |> Simulation.move()
{:reply, new_simulation, new_simulation}
end
end
29 changes: 29 additions & 0 deletions lib/toy_robot/game/player_supervisor.ex
@@ -0,0 +1,29 @@
defmodule ToyRobot.Game.PlayerSupervisor do
use DynamicSupervisor

alias ToyRobot.Game.Player

def start_link(args) do
DynamicSupervisor.start_link(__MODULE__, args, name: __MODULE__)
end

def init(_args) do
Registry.start_link(keys: :unique, name: ToyRobot.Game.PlayerRegistry)
DynamicSupervisor.init(strategy: :one_for_one)
end

def start_child(position, name) do
DynamicSupervisor.start_child(
__MODULE__,
{Player, [position: position, name: name]}
)
end

def move(name) do
name |> Player.process_name() |> Player.move()
end

def report(name) do
name |> Player.process_name() |> Player.report()
end
end
3 changes: 2 additions & 1 deletion mix.exs
Expand Up @@ -15,7 +15,8 @@ defmodule ToyRobot.MixProject do
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
extra_applications: [:logger],
mod: {ToyRobot.Application, []}
]
end

Expand Down
34 changes: 34 additions & 0 deletions test/toy_robot/game/player_supervisor_test.exs
@@ -0,0 +1,34 @@
defmodule ToyRobot.Game.PlayerSupervisorTest do
use ExUnit.Case, async: true

alias ToyRobot.Game.PlayerSupervisor

test "starts a game child process" do
starting_position = %{north: 0, east: 0, facing: :north}
{:ok, player} = PlayerSupervisor.start_child(starting_position, "Izzy")

[{registered_player, _}] = Registry.lookup(ToyRobot.Game.PlayerRegistry, "Izzy")
assert registered_player == player
end

test "starts a registry" do
registry = Process.whereis(ToyRobot.Game.PlayerRegistry)
assert registry
end

test "moves a robot forward" do
starting_position = %{north: 0, east: 0, facing: :north}
{:ok, _player} = PlayerSupervisor.start_child(starting_position, "Charlie")
%{robot: %{north: north}} = PlayerSupervisor.move("Charlie")

assert north == 1
end

test "reports a robot's location" do
starting_position = %{north: 0, east: 0, facing: :north}
{:ok, _player} = PlayerSupervisor.start_child(starting_position, "Davros")
%{north: north} = PlayerSupervisor.report("Davros")

assert north == 0
end
end
40 changes: 40 additions & 0 deletions test/toy_robot/game/player_test.exs
@@ -0,0 +1,40 @@
defmodule ToyRobot.Game.PlayerTest do
use ExUnit.Case, async: true

alias ToyRobot.Game.Player
alias ToyRobot.Robot

describe "report" do
setup do
starting_position = %{north: 0, east: 0, facing: :north}
{:ok, player} = Player.start(starting_position)
%{player: player}
end

test "shows the current position of the robot", %{player: player} do
assert Player.report(player) == %Robot{
north: 0,
east: 0,
facing: :north
}
end
end

describe "move" do
setup do
starting_position = %{north: 0, east: 0, facing: :north}
{:ok, player} = Player.start(starting_position)
%{player: player}
end

test "moves the robot forward one space", %{player: player} do
%{robot: robot} = Player.move(player)

assert robot == %Robot{
north: 1,
east: 0,
facing: :north
}
end
end
end

0 comments on commit 175f80c

Please sign in to comment.