Rock Paper Scissors
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
Setup
Ensure you type the ea
keyboard shortcut to evaluate all Elixir cells before starting. Alternatively you can evaluate the Elixir cells as you read.
Create the Perfect AI
In the Elixir cell below, you’re going to create the perfect AI for rock paper scissors.
flowchart LR
scissors --beats--> paper --beats--> rock --beats--> scissors
You are only allowed to use boolean operators &&
, ==
, and ||
and the match operator =
.
Remember that you can conditionally return a value with:
player_choice = :rock
ai_choice = player_choice == :rock && :paper
Given a player_choice
of either :rock
, :paper
, or :scissors
determining the winning
ai_choice
.
Replace nil
with your answer. Change player_choice
to :rock
, :paper
, and :scissors
to ensure
your solution works correctly.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "Exercise" do
try do
Process.flag(:trap_exit, true)
player_choice = :rock
ai_choice =
(player_choice == :scissors && :rock) ||
(player_choice == :rock && :paper) ||
(player_choice == :paper && :scissors)
case player_choice do
:rock ->
assert ai_choice === :paper,
"when player_choice is :rock, ai_choice should be :paper."
:paper ->
assert ai_choice === :scissors,
"when player_choice is :paper, ai_choice should be :scissors."
:scissors ->
assert ai_choice === :rock,
"when player_choice is :scissors, ai_choice should be :rock."
end
catch
error ->
flunk("""
Your solution threw the following error:
#{inspect(error)}
""")
:exit, {error, {GenServer, message_type, [_pid, message, _timeout]}} ->
flunk("""
GenServer crashed with the following error:
#{inspect(error)}
When it recieved: #{inspect(message)} #{message_type}
Likely you need to define the corresponding handler for #{inspect(message)}.
Ensure you defined a `handle_call/3`, `handle_info/2`, or `handle_cast/2` or appropriate handler function.
def handle_call(:message, _from, state) do
...
end
Then ensure you call `GenServer.call/2`, `GenServer.cast/2`, or otherwise send the message correctly.
GenServer.call(pid, :message)
""")
:exit, error ->
flunk("""
Unhandled exit with the following error:
#{inspect(error)}
""")
after
# all warnings and errors are printed to the previous Kino Frame
# to avoid cluttering the test results display.
Process.sleep(10)
Kino.render(Kino.Markdown.new("### Test Results
"))
end
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
# Unfortunately, this results in duplication of warnings.
player_choice = :rock
ai_choice =
(player_choice == :scissors && :rock) ||
(player_choice == :rock && :paper) ||
(player_choice == :paper && :scissors)
Create Two Player Rock Paper Scissors
In the Elixir cell below, you’re going to create a two player game of rock paper scissors.
As earlier, you should only use the &&
, =
, ===
, and ||
operators.
Given player1_choice
and player2_choice
are either :rock
, :paper
, or :scissors
.
Determine the winner
as either :player1
or :player2
.
flowchart LR
p1c[player_1_choice]
p2c[player_2_choice]
w[winner]
p1[:player1]
p2[:player2]
p1c --> w
p2c --> w
w --> p1
w --> p2
Replace nil
with your answer.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "Exercise" do
try do
Process.flag(:trap_exit, true)
# Will be either :rock, :paper, or :scissors
player1_choice = Utils.random(:rock_paper_scissors)
# Will be either :rock, :paper, or :scissors
player2_choice = Utils.random(:rock_paper_scissors)
winner =
(player1_choice == :scissors && player2_choice == :rock && :player2) ||
(player1_choice == :rock && player2_choice == :paper && :player2) ||
(player1_choice == :paper && player2_choice == :scissors && :player2) ||
(player1_choice == player2_choice && :draw) ||
:player1
case {player1_choice, player2_choice} do
{:rock, :scissors} -> assert winner == :player1
{:paper, :rock} -> assert winner == :player1
{:scissors, :paper} -> assert winner == :player1
{:scissors, :rock} -> assert winner == :player2
{:rock, :paper} -> assert winner == :player2
{:paper, :scissors} -> assert winner == :player2
_ -> assert winner == :draw
end
catch
error ->
flunk("""
Your solution threw the following error:
#{inspect(error)}
""")
:exit, {error, {GenServer, message_type, [_pid, message, _timeout]}} ->
flunk("""
GenServer crashed with the following error:
#{inspect(error)}
When it recieved: #{inspect(message)} #{message_type}
Likely you need to define the corresponding handler for #{inspect(message)}.
Ensure you defined a `handle_call/3`, `handle_info/2`, or `handle_cast/2` or appropriate handler function.
def handle_call(:message, _from, state) do
...
end
Then ensure you call `GenServer.call/2`, `GenServer.cast/2`, or otherwise send the message correctly.
GenServer.call(pid, :message)
""")
:exit, error ->
flunk("""
Unhandled exit with the following error:
#{inspect(error)}
""")
after
# all warnings and errors are printed to the previous Kino Frame
# to avoid cluttering the test results display.
Process.sleep(10)
Kino.render(Kino.Markdown.new("### Test Results
"))
end
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
# Unfortunately, this results in duplication of warnings.
# Will be either :rock, :paper, or :scissors
player1_choice = Utils.random(:rock_paper_scissors)
# Will be either :rock, :paper, or :scissors
player2_choice = Utils.random(:rock_paper_scissors)
winner =
(player1_choice == :scissors && player2_choice == :rock && :player2) ||
(player1_choice == :rock && player2_choice == :paper && :player2) ||
(player1_choice == :paper && player2_choice == :scissors && :player2) ||
(player1_choice == player2_choice && :draw) ||
:player1
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 rock paper scissors exercise"