Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.9", override: true},
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"}
])
Ensure you type the ea
keyboard shortcut to evaluate all Elixir cells before starting. Alternatively you can evaluate the Elixir cells as you read.
We're going to create a bomb defusal game.
There will be multiple bombs that need to be defused. If any of the bombs go off the entire game will be reset.
A BombSupervisor
will supervise three Bomb
s. If any of the bombs detonate, every bomb detonates.
flowchart
S[BombSupervisor]
C1[Bomb]
C2[Bomb]
C3[Bomb]
S --> C1
S --> C2
S --> C3
That means when a Bomb
process dies, the BombSupervisor
will restart every Bomb
process.
Using the command line, create a new supervised project in the projects
folder called bomb_defusal
.
mix new bomb_defusal --sup
Dialyzer, Credo, and ExDoc are optional for this project.
Create a Bomb
GenServer. It should start as a minimal GenServer with no functionality.
Configure the BombSupervisor to start in application.ex
.
It should start with 3 Bomb
GenServers as children.
Send a Bomb
an :explode
message. It should handle the message by terminating.
The BombSupervisor
should automatically restart all of the Bomb
processes.
We will defuse bombs by sending them a :cut
message with a :red
, :white
, or :black
wire.
When a Bomb
is initialized, it should store a randomized wire of either :red
, :white
, or :black
in
it's state as the correct wire to defuse the bomb.
If the wire from the :cut
message is correct, defuse the bomb.
A defused bomb will no longer terminal when sent the :explode
message.
Add a Timer
GenServer under the BombSupervisor
tree.
The Timer
should store a 5
minute timer which decrements every second.
Every time a :cut
message is sent to a bomb with an incorrect value, the Timer
should decrement by 30
seconds.
When the Timer
reaches 0
it should terminate the BombSupervisor
which should automatically restart under
the application supervisor.
file_name = Path.basename(Regex.replace(~r/#.+/, __ENV__.file, ""), ".livemd")
progress_path = __DIR__ <> "/../progress.json"
existing_progress = File.read!(progress_path) |> Jason.decode!()
default = Map.get(existing_progress, file_name, false)
form =
Kino.Control.form(
[
completed: input = Kino.Input.checkbox("Mark As Completed", default: default)
],
report_changes: true
)
Task.async(fn ->
for %{data: %{completed: completed}} <- Kino.Control.stream(form) do
File.write!(progress_path, Jason.encode!(Map.put(existing_progress, file_name, completed)))
end
end)
form
Run the following in your command line from the curriculum folder to track and save your progress in a Git commit.
Ensure that you do not already have undesired or unrelated changes by running git status
or by checking the source control tab in Visual Studio Code.
$ git checkout solutions
$ git checkout -b bomb-defusal-exercise
$ git add .
$ git commit -m "finish bomb defusal exercise"
$ git push origin bomb-defusal-exercise
Create a pull request from your bomb-defusal-exercise
branch to your solutions
branch.
Please do not create a pull request to the DockYard Academy repository as this will spam our PR tracker.
DockYard Academy Students Only:
Notify your instructor by including @BrooklinJazz
in your PR description to get feedback.
You (or your instructor) may merge your PR into your solutions branch after review.
If you are interested in joining the next academy cohort, sign up here to receive more news when it is available.