Fun Formulas
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.
Fun Formulas
As developer’s it’s our job to translate business requirements into something that the computer understands.
These exercises will have you convert a common formula into an Elixir program.
Percentage
Let’s say we’re building a program with a loading bar.
Users download items, and you need to display the current percentage that the download has finished.
You can calculate the percentage with $\frac{completed\ items}{total\ items}\times100$
In the Elixir cell below, calculate the percentage given completed_items
and total_items
.
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)
completed_items = 10
total_items = 100
percentage = completed_items / total_items * 100
assert total_items >= completed_items,
"total_items should always be more than completed items, please reset the exercise"
assert percentage <= 100,
"percentage should be a float between 0 and 100. Please check the formula entered."
assert percentage == completed_items / total_items * 100
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.
completed_items = 10
total_items = 100
percentage = completed_items / total_items * 100
Given a random number of completed_items and total_items, calculate the percentage.
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)
completed_items = Utils.random(1..100)
total_items = Utils.random(completed_items..100)
percentage = completed_items / total_items * 100
assert total_items >= completed_items,
"total_items should always be more than completed items, please reset the exercise"
assert percentage <= 100,
"percentage should be a float between 0 and 100. Please check the formula entered."
assert percentage == completed_items / total_items * 100
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.
completed_items = Utils.random(1..100)
total_items = Utils.random(completed_items..100)
percentage = completed_items / total_items * 100
Rocket Ship
We’re building a rocket ship app to teach people about physics.
Users can enter the mass
and acceleration
of a ship to visualize the force
generated.
Given that ${mass} * {acceleration} = force$, calculate force. 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)
mass = 10
acceleration = 2
force = mass * acceleration
assert force == 20
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.
mass = 10
acceleration = 2
force = mass * acceleration
What Do You Tip?
Let’s build a program to determine how much you should tip your server when you buy a meal.
The formula for calculating a tip is $cost\ of\ the\ meal * tip\ rate = tip\ amount$ where tip_rate
is the rate you
would like to tip as a decimal. so 15%
would be 0.15
and 20%
would be 0.2
.
In the Elixir cell below, Use floats to set the cost_of_the_meal
to represent $55.50
and the tip_rate
to represent 20%
.
Then calculate the tip_amount
.
Replace nil
with your answers.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "Exercise" do
try do
Process.flag(:trap_exit, true)
cost_of_the_meal = 55.50
tip_rate = 0.20
tip_amount = 55.50 * 0.20
assert tip_rate == 0.20, "tip rate should be 0.2"
assert cost_of_the_meal == 55.5, "cost_of_the_meal should be 55.5"
assert tip_amount === cost_of_the_meal * tip_rate,
"tip_amount should be cost_of_the_meal * tip_rate"
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.
cost_of_the_meal = 55.50
tip_rate = 0.20
tip_amount = 55.50 * 0.20
Pythagorean Theorum
To calculate the longest side of a triangle we use $a^2 + b^2 = c^2$
First, given a
and b
, calculate c_square
where c_square
is $c^2$.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "Exercise" do
try do
Process.flag(:trap_exit, true)
a = 10
b = 10
c_square = a ** 2 + b ** 2
assert c_square == 10 ** 2 + 10 ** 2,
"The answer is not correct, please check the formula entered."
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.
a = 10
b = 10
c_square = a ** 2 + b ** 2
Bonus!
This is a bonus challenge that requires going beyond what you’ve already learned.
You need to figure out how to find the square root of a number in Elixir.
Given c_square
, calculate c
. 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)
c_square = 200
c = :math.sqrt(c_square)
assert c == :math.sqrt(200)
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.
c_square = 200
c = :math.sqrt(c_square)
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 fun formulas exercise"