Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Traffic Light Server

traffic_light_server.livemd

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

Return Home Report An Issue

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 over cast 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 five TrafficLightServers.
  • Define a current_lights/1 function that returns the current light of each TrafficLightServer.
  • Define a transition/1 function that transitions one of the five lights (in order, from beginning to end).
  • Prefer call over cast 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"