Traffic Light Server
Mix.install([
{:kino, github: "livebook-dev/kino", override: true},
{:kino_lab, "~> 0.1.0-dev", github: "jonatanklosko/kino_lab"},
{:vega_lite, "~> 0.1.4"},
{:kino_vega_lite, "~> 0.1.1"},
{:benchee, "~> 0.1"},
{:ecto, "~> 3.7"},
{:math, "~> 0.7.0"},
{:faker, "~> 0.17.0"},
{:utils, path: "#{__DIR__}/../utils"},
{:tested_cell, git: "https://github.com/BrooklinJazz/tested_cell"}
])
Navigation
Traffic Light Server
You’re going to create a TrafficLightServer
GenServer
that mimics a traffic light.
-
Create a
TrafficLightServer
which stores the state of the traffic light:red
,:green
, or:yellow
. It should start as:green
. -
Define a
current_light/1
function which returns the current light color. -
Define a
transition/1
function which transitions the current light from its current color to the next color. -
Prefer
call
overcast
to avoid concurrency issues.
flowchart LR
Green --> Yellow --> Red --> Green
style Green fill:lightgreen
style Yellow fill:lightyellow
style Red fill:lightcoral
````
For example:
= TrafficLightServer.start_link([])
:green = TrafficLightServer.current_light(pid)
:yellow = TrafficLightServer.transition(pid) :yellow = TrafficLightServer.current_light(pid)
:red = TrafficLightServer.transition(pid) :red = TrafficLightServer.current_light(pid)
:green = TrafficLightServer.transition(pid) :green = TrafficLightServer.current_light(pid)
Enter your answer in the Elixir cell below.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "" do
defmodule TrafficLightServer do
end
assert Kernel.function_exported?(TrafficLightServer, :start_link, 1),
"Ensure you define a start_link/1 function which accepts a list of options."
assert Kernel.function_exported?(TrafficLightServer, :init, 1),
"Ensure you define an init/1 function which returns `{:ok, initial_state}`"
assert {:ok, pid} = TrafficLightServer.start_link([])
assert Kernel.function_exported?(TrafficLightServer, :current_light, 1),
"Ensure you define a current_light/1 function which accepts a pid"
assert :green == TrafficLightServer.current_light(pid)
assert Kernel.function_exported?(TrafficLightServer, :transition, 1),
"Ensure you define a transition/1 function which accepts a pid"
TrafficLightServer.transition(pid)
assert :yellow == TrafficLightServer.current_light(pid)
TrafficLightServer.transition(pid)
assert :red == TrafficLightServer.current_light(pid)
TrafficLightServer.transition(pid)
assert :green == TrafficLightServer.current_light(pid)
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
defmodule TrafficLightServer do
end
You may find the following commented cell useful for testing your solution.
# {:ok, pid} = TrafficLightServer.start_link([])
# :green = TrafficLightServer.current_light(pid)
# :yellow = TrafficLightServer.transition(pid)
# :yellow = TrafficLightServer.current_light(pid)
# :red = TrafficLightServer.transition(pid)
# :red = TrafficLightServer.current_light(pid)
# :green = TrafficLightServer.transition(pid)
# :green = TrafficLightServer.current_light(pid)
TrafficGrid
You’re going to create a TrafficGrid
GenServer
that manages five TrafficLightServers
.
-
Create a
TrafficGrid
which stores the pids of fiveTrafficLightServers
. -
Define a
current_lights/1
function that returns the current light of eachTrafficLightServer
. -
Define a
transition/1
function that transitions one of the five lights (in order, from beginning to end). -
Prefer
call
overcast
to avoid concurrency issues.
flowchart
TG[TrafficGrid]
TLS1[TrafficLightServer]
TLS2[TrafficLightServer]
TLS3[TrafficLightServer]
TLS4[TrafficLightServer]
TLS5[TrafficLightServer]
G1[Green]
G2[Green]
G3[Green]
G4[Green]
G5[Green]
Y1[Yellow]
Y2[Yellow]
Y3[Yellow]
Y4[Yellow]
Y5[Yellow]
R1[Red]
R2[Red]
R3[Red]
R4[Red]
R5[Red]
TG --> TLS1
TG --> TLS2
TG --> TLS3
TG --> TLS4
TG --> TLS5
TLS1 --> G1 --> Y1 --> R1 --> G1
TLS2 --> G2 --> Y2 --> R2 --> G2
TLS3 --> G3 --> Y3 --> R3 --> G3
TLS4 --> G4 --> Y4 --> R4 --> G4
TLS5 --> G5 --> Y5 --> R5 --> G5
style G1 fill:lightgreen
style G2 fill:lightgreen
style G3 fill:lightgreen
style G4 fill:lightgreen
style G5 fill:lightgreen
style Y1 fill:lightyellow
style Y2 fill:lightyellow
style Y3 fill:lightyellow
style Y4 fill:lightyellow
style Y5 fill:lightyellow
style R1 fill:lightcoral
style R2 fill:lightcoral
style R3 fill:lightcoral
style R4 fill:lightcoral
style R5 fill:lightcoral
For example:
{:ok, pid} = TrafficGrid.start_link([])
# all lights start green
[:green, :green, :green, :green, :green] = TrafficGrid.current_lights(pid)
# transition the first light from green to yellow
[:yellow, :green, :green, :green, :green] = TrafficGrid.transition(pid)
[:yellow, :green, :green, :green, :green] = TrafficGrid.current_lights(pid)
# transition the second light from green to yellow
[:yellow, :yellow, :green, :green, :green] = TrafficGrid.transition(pid)
[:yellow, :yellow, :green, :green, :green] = TrafficGrid.current_lights(pid)
# transition the third light from green to yellow
[:yellow, :yellow, :yellow, :green, :green] = TrafficGrid.transition(pid)
[:yellow, :yellow, :yellow, :green, :green] = TrafficGrid.current_lights(pid)
# transition the fourth light from green to yellow
[:yellow, :yellow, :yellow, :yellow, :green] = TrafficGrid.transition(pid)
[:yellow, :yellow, :yellow, :yellow, :green] = TrafficGrid.current_lights(pid)
# transition the fifth light from green to yellow
[:yellow, :yellow, :yellow, :yellow, :yellow] = TrafficGrid.transition(pid)
[:yellow, :yellow, :yellow, :yellow, :yellow] = TrafficGrid.current_lights(pid)
# transition the first light from yellow to red
[:red, :yellow, :yellow, :yellow, :yellow] = TrafficGrid.transition(pid)
[:red, :yellow, :yellow, :yellow, :yellow] = TrafficGrid.current_lights(pid)
# ... etc
Enter your answer in the Elixir cell below.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "" do
defmodule TrafficGrid do
end
assert Kernel.function_exported?(TrafficGrid, :start_link, 1),
"Ensure you define a start_link/1 function which accepts a list of options."
assert Kernel.function_exported?(TrafficGrid, :init, 1),
"Ensure you define an init/1 function which returns `{:ok, initial_state}`"
assert {:ok, pid} = TrafficGrid.start_link([])
assert Kernel.function_exported?(TrafficGrid, :current_lights, 1),
"Ensure you define a current_lights/1 function which accepts a pid"
assert [:green, :green, :green, :green, :green] == TrafficGrid.current_lights(pid)
assert Kernel.function_exported?(TrafficGrid, :transition, 1),
"Ensure you define a transition/1 function which accepts a pid"
assert [:yellow, :green, :green, :green, :green] == TrafficGrid.transition(pid)
assert [:yellow, :green, :green, :green, :green] == TrafficGrid.current_lights(pid)
assert [:yellow, :yellow, :green, :green, :green] == TrafficGrid.transition(pid)
assert [:yellow, :yellow, :green, :green, :green] == TrafficGrid.current_lights(pid)
assert [:yellow, :yellow, :yellow, :green, :green] == TrafficGrid.transition(pid)
assert [:yellow, :yellow, :yellow, :green, :green] == TrafficGrid.current_lights(pid)
assert [:yellow, :yellow, :yellow, :yellow, :green] == TrafficGrid.transition(pid)
assert [:yellow, :yellow, :yellow, :yellow, :green] == TrafficGrid.current_lights(pid)
assert [:yellow, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.transition(pid)
assert [:yellow, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.current_lights(pid)
assert [:red, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.transition(pid)
assert [:red, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.current_lights(pid)
assert [:red, :red, :yellow, :yellow, :yellow] == TrafficGrid.transition(pid)
assert [:red, :red, :yellow, :yellow, :yellow] == TrafficGrid.current_lights(pid)
assert [:red, :red, :red, :yellow, :yellow] == TrafficGrid.transition(pid)
assert [:red, :red, :red, :yellow, :yellow] == TrafficGrid.current_lights(pid)
assert [:red, :red, :red, :red, :yellow] == TrafficGrid.transition(pid)
assert [:red, :red, :red, :red, :yellow] == TrafficGrid.current_lights(pid)
assert [:red, :red, :red, :red, :red] == TrafficGrid.transition(pid)
assert [:red, :red, :red, :red, :red] == TrafficGrid.current_lights(pid)
assert [:green, :red, :red, :red, :red] == TrafficGrid.transition(pid)
assert [:green, :red, :red, :red, :red] == TrafficGrid.current_lights(pid)
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
defmodule TrafficGrid do
end
You may find the following commented cell useful for testing your solution.
# {:ok, pid} = TrafficGrid.start_link([])
# [:green, :green, :green, :green, :green] == TrafficGrid.current_lights(pid)
# [:yellow, :green, :green, :green, :green] == TrafficGrid.transition(pid)
# [:yellow, :green, :green, :green, :green] == TrafficGrid.current_lights(pid)
# [:yellow, :yellow, :green, :green, :green] == TrafficGrid.transition(pid)
# [:yellow, :yellow, :green, :green, :green] == TrafficGrid.current_lights(pid)
# [:yellow, :yellow, :yellow, :green, :green] == TrafficGrid.transition(pid)
# [:yellow, :yellow, :yellow, :green, :green] == TrafficGrid.current_lights(pid)
# [:yellow, :yellow, :yellow, :yellow, :green] == TrafficGrid.transition(pid)
# [:yellow, :yellow, :yellow, :yellow, :green] == TrafficGrid.current_lights(pid)
# [:yellow, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.transition(pid)
# [:yellow, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.current_lights(pid)
# [:red, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.transition(pid)
# [:red, :yellow, :yellow, :yellow, :yellow] == TrafficGrid.current_lights(pid)
# [:red, :red, :yellow, :yellow, :yellow] == TrafficGrid.transition(pid)
# [:red, :red, :yellow, :yellow, :yellow] == TrafficGrid.current_lights(pid)
# [:red, :red, :red, :yellow, :yellow] == TrafficGrid.transition(pid)
# [:red, :red, :red, :yellow, :yellow] == TrafficGrid.current_lights(pid)
# [:red, :red, :red, :red, :yellow] == TrafficGrid.transition(pid)
# [:red, :red, :red, :red, :yellow] == TrafficGrid.current_lights(pid)
# [:red, :red, :red, :red, :red] == TrafficGrid.transition(pid)
# [:red, :red, :red, :red, :red] == TrafficGrid.current_lights(pid)
# [:green, :red, :red, :red, :red] == TrafficGrid.transition(pid)
# [:green, :red, :red, :red, :red] == TrafficGrid.current_lights(pid)
Commit Your Progress
Run the following in your command line from the project folder to track and save your progress in a Git commit.
$ git add .
$ git commit -m "finish traffic light server exercise"