Initial commit

This commit is contained in:
Danil Negrienko 2023-12-17 00:26:14 -05:00
commit 59d97be20c
89 changed files with 3184 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
elixir/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,21 @@
{
"authors": [
"jiegillet"
],
"contributors": [
"angelikatyborska"
],
"files": {
"solution": [
"lib/darts.ex"
],
"test": [
"test/darts_test.exs"
],
"example": [
".meta/example.ex"
]
},
"blurb": "Write a function that returns the earned points in a single toss of a Darts game.",
"source": "Inspired by an exercise created by a professor Della Paolera in Argentina"
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"darts","id":"1062d062de474a2ab65b96bb7027ec45","url":"https://exercism.org/tracks/elixir/exercises/darts","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/darts/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
darts-*.tar

75
elixir/darts/HELP.md Normal file
View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/darts.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

7
elixir/darts/HINTS.md Normal file
View File

@ -0,0 +1,7 @@
# Hints
## General
- The distance of a point `(x, y)` from the center of the target `(0, 0)` can be calculated with `sqrt(x*x + y *y)`
- You can calculate the square root of `x` by raising it to the power of `1/2`. In other words, `sqrt(x) == pow(x, 0.5)`

51
elixir/darts/README.md Normal file
View File

@ -0,0 +1,51 @@
# Darts
Welcome to Darts on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Instructions
Write a function that returns the earned points in a single toss of a Darts game.
[Darts][darts] is a game where players throw darts at a [target][darts-target].
In our particular instance of the game, the target rewards 4 different amounts of points, depending on where the dart lands:
![Our dart scoreboard with values from a complete miss to a bullseye](https://assets.exercism.org/images/exercises/darts/darts-scoreboard.svg)
- If the dart lands outside the target, player earns no points (0 points).
- If the dart lands in the outer circle of the target, player earns 1 point.
- If the dart lands in the middle circle of the target, player earns 5 points.
- If the dart lands in the inner circle of the target, player earns 10 points.
The outer circle has a radius of 10 units (this is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1.
Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0).
Write a function that given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), returns the correct amount earned by a dart landing at that point.
## Credit
The scoreboard image was created by [habere-et-dispertire][habere-et-dispertire] using [Inkscape][inkscape].
[darts]: https://en.wikipedia.org/wiki/Darts
[darts-target]: https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg
[concentric]: https://mathworld.wolfram.com/ConcentricCircles.html
[cartesian-coordinates]: https://www.mathsisfun.com/data/cartesian-coordinates.html
[real-numbers]: https://www.mathsisfun.com/numbers/real-numbers.html
[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire
[inkscape]: https://en.wikipedia.org/wiki/Inkscape
## Source
### Created by
- @jiegillet
### Contributed to by
- @angelikatyborska
### Based on
Inspired by an exercise created by a professor Della Paolera in Argentina

17
elixir/darts/lib/darts.ex Normal file
View File

@ -0,0 +1,17 @@
defmodule Darts do
@type position :: {number, number}
@doc """
Calculate the score of a single dart hitting a target
"""
@spec score(position) :: integer
def score({x, y}) do
in_radius = (x ** 2 + y ** 2) ** 0.5
cond do
in_radius <= 1 -> 10
in_radius <= 5 -> 5
in_radius <= 10 -> 1
true -> 0
end
end
end

28
elixir/darts/mix.exs Normal file
View File

@ -0,0 +1,28 @@
defmodule Darts.MixProject do
use Mix.Project
def project do
[
app: :darts,
version: "0.1.0",
# elixir: "~> 1.8",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,68 @@
defmodule DartsTest do
use ExUnit.Case
# @tag :pending
test "Missed target" do
assert Darts.score({-9, 9}) == 0
end
# @tag :pending
test "On the outer circle" do
assert Darts.score({0, 10}) == 1
end
# @tag :pending
test "On the middle circle" do
assert Darts.score({-5, 0}) == 5
end
# @tag :pending
test "On the inner circle" do
assert Darts.score({0, -1}) == 10
end
# @tag :pending
test "Exactly on centre" do
assert Darts.score({0, 0}) == 10
end
# @tag :pending
test "Near the centre" do
assert Darts.score({-0.1, -0.1}) == 10
end
# @tag :pending
test "Just within the inner circle" do
assert Darts.score({0.7, 0.7}) == 10
end
# @tag :pending
test "Just outside the inner circle" do
assert Darts.score({0.8, -0.8}) == 5
end
# @tag :pending
test "Just within the middle circle" do
assert Darts.score({-3.5, 3.5}) == 5
end
# @tag :pending
test "Just outside the middle circle" do
assert Darts.score({-3.6, -3.6}) == 1
end
# @tag :pending
test "Just within the outer circle" do
assert Darts.score({-7.0, 7.0}) == 1
end
# @tag :pending
test "Just outside the outer circle" do
assert Darts.score({7.1, -7.1}) == 0
end
# @tag :pending
test "Asymmetric position between the inner and middle circles" do
assert Darts.score({0.5, -4}) == 5
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)

View File

@ -0,0 +1,24 @@
{
"authors": [
"angelikatyborska"
],
"contributors": [
"neenjaw"
],
"files": {
"solution": [
"lib/freelancer_rates.ex"
],
"test": [
"test/freelancer_rates_test.exs"
],
"exemplar": [
".meta/exemplar.ex"
]
},
"language_versions": ">=1.10",
"forked_from": [
"javascript/freelancer-rates"
],
"blurb": "Learn about integers and floating point numbers by helping a freelancer communicate with a project manager about billing."
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"freelancer-rates","id":"25db5ef05b9b40a09965866b08a13f3f","url":"https://exercism.org/tracks/elixir/exercises/freelancer-rates","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/freelancer-rates/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
numbers-*.tar

View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/freelancer_rates.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

View File

@ -0,0 +1,30 @@
# Hints
## General
- Read about basic arithmetic in the official [Getting Started guide][getting-started-basic-arithmetic].
- Browse the [`Float`][float-functions] and [`Kernel`][kernel-arithmetic-operators] modules to learn about functions and operators that work with floats.
## 1. Calculate the daily rate given an hourly rate
- [Basic arithmetic operations][kernel-arithmetic-operators] where one argument is an integer, and the other is a float, will return a float.
## 2. Calculate a discounted price
- [Basic arithmetic operations][kernel-arithmetic-operators] where one argument is an integer, and the other is a float, will return a float.
## 3. Calculate the monthly rate, given an hourly rate and a discount
- There is a [built-in function][kernel-trunc] for changing floats to integers.
- There is a [built-in function][float-ceil] for rounding floats up.
## 4. Calculate the number of workdays given a budget, hourly rate and discount
- There is a [built-in function][float-floor] for rounding floats down with desired precision.
[getting-started-basic-arithmetic]: https://elixir-lang.org/getting-started/basic-types.html#basic-arithmetic
[kernel-arithmetic-operators]: https://hexdocs.pm/elixir/Kernel.html#*/2
[kernel-trunc]: https://hexdocs.pm/elixir/Kernel.html#trunc/1
[float-functions]: https://hexdocs.pm/elixir/Float.html#functions
[float-ceil]: https://hexdocs.pm/elixir/Float.html#ceil/2
[float-floor]: https://hexdocs.pm/elixir/Float.html#floor/2

View File

@ -0,0 +1,125 @@
# Freelancer Rates
Welcome to Freelancer Rates on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Integers
There are two different kinds of numbers in Elixir - integers and floats.
Integers are whole numbers.
```elixir
integer = 3
# => 3
```
## Floating Point Numbers
Floats are numbers with one or more digits behind the decimal separator. They use the 64-bit double precision floating-point format.
```elixir
float = 3.45
# => 3.45
```
### Working with numbers
In the [`Integer`][integer-functions] and [`Float`][float-functions] modules you can find some useful functions for working with those types. Basic arithmetic operators are defined in the [`Kernel`][kernel-arithmetic-operators] module.
### Conversion
Integers and floats can be mixed together in a single arithmetic expression. Using a float in an expression ensures the result will be a float too.
```elixir
2 * 3
# => 6
2 * 3.0
# => 6.0
```
However, when doing division, the result will always be a float, even if only integers are used.
```elixir
6 / 2
# => 3.0
```
To convert a float to an integer, you can discard the decimal part with [`trunc/1`][trunc-1].
[integer-functions]: https://hexdocs.pm/elixir/Integer.html#functions
[float-functions]: https://hexdocs.pm/elixir/Float.html#functions
[kernel-arithmetic-operators]: https://hexdocs.pm/elixir/Kernel.html#*/2
[trunc-1]: https://hexdocs.pm/elixir/Kernel.html#trunc/1
## Instructions
In this exercise you'll be writing code to help a freelancer communicate with a project manager by providing a few utilities to quickly calculate daily and
monthly rates, optionally with a given discount.
We first establish a few rules between the freelancer and the project manager:
- The daily rate is 8 times the hourly rate.
- A month has 22 billable days.
Sometimes, the freelancer is offering to apply a discount on their daily rate (for example for their most loyal customers or for non-for-profit customers).
Discounts are modeled as fractional numbers representing percentage, for example `25.0` (25%).
## 1. Calculate the daily rate given an hourly rate
Implement a function to calculate the daily rate given an hourly rate:
```elixir
FreelancerRates.daily_rate(60)
# => 480.0
```
The returned daily rate should be a float.
## 2. Calculate a discounted price
Implement a function to calculate the price after a discount.
```elixir
FreelancerRates.apply_discount(150, 10)
# => 135.0
```
The returned value should always be a float, not rounded in any way.
## 3. Calculate the monthly rate, given an hourly rate and a discount
Implement a function to calculate the monthly rate, and apply a discount:
```elixir
FreelancerRates.monthly_rate(77, 10.5)
# => 12130
```
The returned monthly rate should be rounded up (take the ceiling) to the nearest integer.
## 4. Calculate the number of workdays given a budget, hourly rate and discount
Implement a function that takes a budget, an hourly rate, and a discount, and calculates how many days of work that covers.
```elixir
FreelancerRates.days_in_budget(20000, 80, 11.0)
# => 35.1
```
The returned number of days should be rounded down (take the floor) to one decimal place.
## Source
### Created by
- @angelikatyborska
### Contributed to by
- @neenjaw

View File

@ -0,0 +1,28 @@
defmodule FreelancerRates do
def daily_rate(hourly_rate) do
8.0 * hourly_rate
end
def monthly_rate(hourly_rate) do
22.0 * daily_rate(hourly_rate)
end
def monthly_rate(hourly_rate, discount) do
hourly_rate
|> monthly_rate()
|> apply_discount(discount)
|> ceil()
end
def apply_discount(before_discount, discount) do
before_discount - (before_discount * (discount / 100))
end
def days_in_budget(budget, hourly_rate, discount) do
hourly_rate
|> daily_rate()
|> apply_discount(discount)
|> then(fn rate -> budget / rate end)
|> Float.floor(1)
end
end

View File

@ -0,0 +1,28 @@
defmodule FreelancerRates.MixProject do
use Mix.Project
def project do
[
app: :freelancer_rates,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,89 @@
defmodule FreelancerRatesTest do
use ExUnit.Case
describe "daily_rate/1" do
@tag task_id: 1
test "it's the hourly_rate times 8" do
assert FreelancerRates.daily_rate(50) == 400.0
end
@tag task_id: 1
test "it always returns a float" do
assert FreelancerRates.daily_rate(60) === 480.0
end
@tag task_id: 1
test "it does not round" do
assert FreelancerRates.daily_rate(55.1) == 440.8
end
end
describe "apply_discount/2" do
@tag task_id: 2
test "a discount of 10% leaves 90% of the original price" do
assert FreelancerRates.apply_discount(140.0, 10) == 126.0
end
@tag task_id: 2
test "it always returns a float" do
assert FreelancerRates.apply_discount(100, 10) == 90.0
end
@tag task_id: 2
test "it doesn't round" do
assert_in_delta FreelancerRates.apply_discount(111.11, 13.5), 96.11015, 0.000001
end
end
describe "monthly_rate/2" do
@tag task_id: 3
test "it's the daily_rate times 22" do
assert FreelancerRates.monthly_rate(62, 0.0) == 10_912
end
@tag task_id: 3
test "it always returns an integer" do
assert FreelancerRates.monthly_rate(70, 0.0) === 12_320
end
@tag task_id: 3
test "the result is rounded up" do
# 11_052.8
assert FreelancerRates.monthly_rate(62.8, 0.0) == 11_053
# 11_475.2
assert FreelancerRates.monthly_rate(65.2, 0.0) == 11_476
end
@tag task_id: 3
test "gives a discount" do
# 11_792 - 12% * 11_792 = 10_376.96
assert FreelancerRates.monthly_rate(67, 12.0) == 10_377
end
end
describe "days_in_budget/3" do
@tag task_id: 4
test "it's the budget divided by the daily rate" do
assert FreelancerRates.days_in_budget(1_600, 50, 0.0) == 4
end
@tag task_id: 4
test "it always returns a float" do
assert FreelancerRates.days_in_budget(520, 65, 0.0) === 1.0
end
@tag task_id: 4
test "it rounds down to one decimal place" do
# 10.02273
assert FreelancerRates.days_in_budget(4_410, 55, 0.0) == 10.0
# 10.18182
assert FreelancerRates.days_in_budget(4_480, 55, 0.0) == 10.1
end
@tag task_id: 4
test "it applies the discount" do
# 1.25
assert FreelancerRates.days_in_budget(480, 60, 20) == 1.2
end
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true, seed: 0)

View File

@ -0,0 +1,34 @@
{
"authors": [],
"contributors": [
"angelikatyborska",
"Cohen-Carlisle",
"dalexj",
"devonestes",
"George-Hudson",
"hanmd82",
"lpil",
"neenjaw",
"parkerl",
"rawkode",
"rubysolo",
"sotojuan",
"Teapane",
"Thrillberg",
"waiting-for-dev"
],
"files": {
"solution": [
"lib/hello_world.ex"
],
"test": [
"test/hello_world_test.exs"
],
"example": [
".meta/example.ex"
]
},
"blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".",
"source": "This is an exercise to introduce users to using Exercism",
"source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program"
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"hello-world","id":"340d85562fad435f8086f4f8ab9cd916","url":"https://exercism.org/tracks/elixir/exercises/hello-world","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/hello-world/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
hello_world-*.tar

View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/hello_world.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

View File

@ -0,0 +1,45 @@
# Hello World
Welcome to Hello World on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
## Instructions
The classical introductory exercise.
Just say "Hello, World!".
["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment.
The objectives are simple:
- Modify the provided code so that it produces the string "Hello, World!".
- Run the test suite and make sure that it succeeds.
- Submit your solution and check it at the website.
If everything goes well, you will be ready to fetch your first real exercise.
[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
## Source
### Contributed to by
- @angelikatyborska
- @Cohen-Carlisle
- @dalexj
- @devonestes
- @George-Hudson
- @hanmd82
- @lpil
- @neenjaw
- @parkerl
- @rawkode
- @rubysolo
- @sotojuan
- @Teapane
- @Thrillberg
- @waiting-for-dev
### Based on
This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program

View File

@ -0,0 +1,9 @@
defmodule HelloWorld do
@doc """
Simply returns "Hello, World!"
"""
@spec hello :: String.t()
def hello do
"Hello, World!"
end
end

View File

@ -0,0 +1,28 @@
defmodule HelloWorld.MixProject do
use Mix.Project
def project do
[
app: :hello_world,
version: "0.1.0",
# elixir: "~> 1.8",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,7 @@
defmodule HelloWorldTest do
use ExUnit.Case
test "says 'Hello, World!'" do
assert HelloWorld.hello() == "Hello, World!"
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)

View File

@ -0,0 +1,24 @@
{
"authors": [
"neenjaw"
],
"contributors": [
"fireproofsocks"
],
"files": {
"solution": [
"lib/language_list.ex"
],
"test": [
"test/language_list_test.exs"
],
"exemplar": [
".meta/exemplar.ex"
]
},
"language_versions": ">=1.10",
"forked_from": [
"clojure/tracks-on-tracks-on-tracks"
],
"blurb": "Learn about lists by keeping track of the programming languages you're currently learning on Exercism."
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"language-list","id":"1fc6fd5b991141188a10438edd755faa","url":"https://exercism.org/tracks/elixir/exercises/language-list","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/language-list/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
strings-*.tar

View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/language_list.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

View File

@ -0,0 +1,35 @@
# Hints
## General
- Use the built-in [(linked) list type][list].
## 1. Define a function to return an empty language list
- The function needs to return `[]`.
## 2. Define a function to add a language to the list
- An element can be prepended to a list using `|`.
## 3. Define a function to remove a language from the list
- Elixir [provides a function][tl] to return a list with the first item removed.
## 4. Define a function to return the first item in the list
- Elixir [provides a function][hd] to get the first item from a list.
## 5. Define a function to return how many languages are in the list
- Elixir [provides a function][length] to count the length of a list.
## 6. Define a function to determine if the list includes a functional language
- Your function should return a boolean value indicating whether `"Elixir"` is a member of the list. Elixir [provides a function][in] to test list membership.
[list]: https://elixir-lang.org/getting-started/basic-types.html#linked-lists
[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1
[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1
[length]: https://hexdocs.pm/elixir/Kernel.html#length/1
[in]: https://hexdocs.pm/elixir/Kernel.html#in/2

View File

@ -0,0 +1,140 @@
# Language List
Welcome to Language List on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Lists
Lists are built-in to the Elixir language. They are considered a basic type, denoted by square brackets. Lists may be empty or hold any number of items of any type. For example:
```elixir
empty_list = []
one_item_list = [1]
two_item_list = [1, 2]
multiple_type_list = [1, :pi, 3.14, "four"]
```
Elixir implements lists as a linked list, where each node stores two values: the first item and another list with all the remaining items. The first item in the list is referred to as the _head_ and the remaining list of items is called the _tail_. We can use this notation in code:
```elixir
# [1] represented in [head | tail] notation
[1 | []]
# [1, 2, 3] represented in [head | tail] notation
[1 | [2 | [3 | []]]]
```
We can use _`[head | tail]`_ notation to prepend elements to a list:
```elixir
# Suppose
list = [2, 1]
[3, 2, 1] == [3 | list]
# => true
```
There are several functions in the `Kernel` module for working with lists, as well as the whole `List` module.
```elixir
# Check if 1 is a member of the list
1 in [1, 2, 3, 4]
# => true
```
## Instructions
In this exercise you need to implement some functions to manipulate a list of programming languages.
## 1. Define a function to return an empty language list
Define the `new/0` function that takes no arguments and returns an empty list.
```elixir
LanguageList.new()
# => []
```
## 2. Define a function to add a language to the list
Define the `add/2` function that takes 2 arguments (a _language list_ and a string literal of a _language_). It should return the resulting list with the new language prepended to the given list.
```elixir
language_list = LanguageList.new()
# => []
language_list = LanguageList.add(language_list, "Clojure")
# => ["Clojure"]
language_list = LanguageList.add(language_list, "Haskell")
# => ["Haskell", "Clojure"]
```
## 3. Define a function to remove a language from the list
Define the `remove/1` function that takes 1 argument (a _language list_). It should return the list without the first item. Assume the list will always have at least one item.
```elixir
language_list = LanguageList.new()
# => []
language_list = LanguageList.add(language_list, "Clojure")
# => ["Clojure"]
language_list = LanguageList.add(language_list, "Haskell")
# => ["Haskell", "Clojure"]
language_list = LanguageList.remove(language_list)
# => ["Clojure"]
```
## 4. Define a function to return the first item in the list
Define the `first/1` function that takes 1 argument (a _language list_). It should return the first language in the list. Assume the list will always have at least one item.
```elixir
language_list = LanguageList.new()
# => []
language_list = LanguageList.add(language_list, "Elm")
# => ["Elm"]
language_list = LanguageList.add(language_list, "Prolog")
# => ["Prolog", "Elm"]
LanguageList.first(language_list)
# => "Prolog"
```
## 5. Define a function to return how many languages are in the list
Define the `count/1` function that takes 1 argument (a _language list_). It should return the number of languages in the list.
```elixir
language_list = LanguageList.new()
# => []
language_list = LanguageList.add(language_list, "Elm")
# => ["Elm"]
language_list = LanguageList.add(language_list, "Prolog")
# => ["Prolog", "Elm"]
LanguageList.count(language_list)
# => 2
```
## 6. Define a function to determine if the list includes a functional language
Define the `functional_list?/1` function which takes 1 argument (a _language list_). It should return a boolean value. It should return true if _"Elixir"_ is one of the languages in the list.
```elixir
language_list = LanguageList.new()
# => []
language_list = LanguageList.add(language_list, "Elixir")
# => ["Elixir"]
LanguageList.functional_list?(language_list)
# => true
```
## Source
### Created by
- @neenjaw
### Contributed to by
- @fireproofsocks

View File

@ -0,0 +1,13 @@
defmodule LanguageList do
def new(), do: []
def add(list, language), do: [language | list]
def remove(list), do: tl(list)
def first(list), do: hd(list)
def count(list), do: length(list)
def functional_list?(list), do: "Elixir" in list
end

View File

@ -0,0 +1,28 @@
defmodule LanguageList.MixProject do
use Mix.Project
def project do
[
app: :language_list,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,116 @@
defmodule LanguageListTest do
use ExUnit.Case
describe "new/0" do
@tag task_id: 1
test "new list" do
assert LanguageList.new() == []
end
end
describe "add/2" do
@tag task_id: 2
test "add a language to a list" do
language = "Elixir"
list = [language]
assert LanguageList.new() |> LanguageList.add(language) == list
end
@tag task_id: 2
test "add several languages to a list" do
list =
LanguageList.new()
|> LanguageList.add("Clojure")
|> LanguageList.add("Haskell")
|> LanguageList.add("Erlang")
|> LanguageList.add("F#")
|> LanguageList.add("Elixir")
assert list == ["Elixir", "F#", "Erlang", "Haskell", "Clojure"]
end
end
describe "remove/1" do
@tag task_id: 3
test "add then remove results in empty list" do
list =
LanguageList.new()
|> LanguageList.add("Elixir")
|> LanguageList.remove()
assert list == []
end
@tag task_id: 3
test "adding two languages, when removed, removes first item" do
list =
LanguageList.new()
|> LanguageList.add("F#")
|> LanguageList.add("Elixir")
|> LanguageList.remove()
assert list == ["F#"]
end
end
describe "first/1" do
@tag task_id: 4
test "add one language, then get the first" do
assert LanguageList.new() |> LanguageList.add("Elixir") |> LanguageList.first() == "Elixir"
end
@tag task_id: 4
test "add a few languages, then get the first" do
first =
LanguageList.new()
|> LanguageList.add("Elixir")
|> LanguageList.add("Prolog")
|> LanguageList.add("F#")
|> LanguageList.first()
assert first == "F#"
end
end
describe "count/1" do
@tag task_id: 5
test "the count of a new list is 0" do
assert LanguageList.new() |> LanguageList.count() == 0
end
@tag task_id: 5
test "the count of a one-language list is 1" do
count =
LanguageList.new()
|> LanguageList.add("Elixir")
|> LanguageList.count()
assert count == 1
end
@tag task_id: 5
test "the count of a multiple-item list is equal to its length" do
count =
LanguageList.new()
|> LanguageList.add("Elixir")
|> LanguageList.add("Prolog")
|> LanguageList.add("F#")
|> LanguageList.count()
assert count == 3
end
end
describe "functional_list?/1" do
@tag task_id: 6
test "a functional language list" do
assert LanguageList.functional_list?(["Clojure", "Haskell", "Erlang", "F#", "Elixir"])
end
@tag task_id: 6
test "not a functional language list" do
refute LanguageList.functional_list?(["Java", "C", "JavaScript"])
end
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true, seed: 0)

View File

@ -0,0 +1,24 @@
{
"authors": [
"neenjaw"
],
"contributors": [
"angelikatyborska"
],
"files": {
"solution": [
"lib/lasagna.ex"
],
"test": [
"test/lasagna_test.exs"
],
"exemplar": [
".meta/exemplar.ex"
]
},
"language_versions": ">=1.10",
"forked_from": [
"csharp/lucians-luscious-lasagna"
],
"blurb": "Learn about the basics of Elixir by following a lasagna recipe."
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"lasagna","id":"88d20645e744455789c938d6243dee99","url":"https://exercism.org/tracks/elixir/exercises/lasagna","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/lasagna/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
basics-*.tar

75
elixir/lasagna/HELP.md Normal file
View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/lasagna.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

44
elixir/lasagna/HINTS.md Normal file
View File

@ -0,0 +1,44 @@
# Hints
## General
- An [integer value][integers] can be defined as one or more consecutive digits.
- [String][string] literals are a sequence of characters surrounded by double quotes.
## 1. Define the expected oven time in minutes
- You need to define a [function][functions] without any arguments.
- You need to return an [integer][integers].
## 2. Calculate the remaining oven time in minutes
- You need to define a [function][functions] with a single argument.
- You have to [implicitly return an integer][return] from a function.
- The function's argument is an [integer][integers].
- You can use the [mathematical operator for subtraction][operators] to subtract values.
## 3. Calculate the preparation time in minutes
- You need to define a [function][functions] with a single argument.
- You have to [implicitly return an integer][return] from a function.
- The function's argument is an [integer][integers].
- You can use the [mathematical operator for multiplication][operators] to multiply values.
## 4. Calculate the total working time in minutes
- You need to define a [function][functions] with two arguments.
- You have to [implicitly return an integer][return] from a function.
- The function's argument is an [integer][integers].
- You can invoke one of the other functions you've defined previously.
- You can use the [mathematical operator for addition][operators] to add values.
## 5. Create a notification that the lasagna is ready
- You need to define a [function][functions] without any arguments.
- You need to return a [string][string].
[functions]: https://elixir-lang.org/getting-started/modules-and-functions.html#named-functions
[return]: https://stackoverflow.com/questions/37445838/returning-values-in-elixir
[operators]: https://elixir-lang.org/getting-started/basic-types.html#basic-arithmetic
[integers]: https://elixir-lang.org/getting-started/basic-types.html
[string]: https://elixir-lang.org/getting-started/basic-types.html#strings

169
elixir/lasagna/README.md Normal file
View File

@ -0,0 +1,169 @@
# Lasagna
Welcome to Lasagna on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Basics
### Variables
Elixir is a dynamically-typed language, meaning that the type of a variable is only checked at runtime. Using the match `=` operator, we can bind a value of any type to a variable name:
```elixir
count = 1 # Bound an integer value of 1
count = 2 # You may re-bind variables
count = false # You may re-bind any type to a variable
message = "Success!" # Strings can be created by enclosing characters within double quotes
```
### Modules
Elixir is a [functional-programming language][functional-programming] and requires all named functions to be defined in a _module_. The `defmodule` keyword is used to define a module. All modules are available to all other modules at runtime and do not require an _access modifier_ to make them visible to other parts of the program. A _module_ is analogous to a _class_ in other programming languages.
```elixir
defmodule Calculator do
# ...
end
```
### Named functions
_Named Functions_ must be defined in a module. The `def` keyword is used to define a _public_ named function.
Each function can have zero or more arguments. The value of the last expression in a function is always _implicitly returned_.
```elixir
defmodule Calculator do
def add(x, y) do
x + y
end
end
```
Invoking a function is done by specifying its module and function name and passing arguments for each of the function's arguments.
```elixir
sum = Calculator.add(1, 2)
# => 3
```
The `defp` keyword can be used instead of `def` to define a _private_ function. Private functions can only be used from within the same module that defined them.
When invoking a function inside the same module where it's defined, the module name can be omitted.
You may also write short functions using a one-line syntax (note the comma `,` and the colon `:` around the keyword `do`).
```elixir
defmodule Calculator do
def subtract(x, y) do
private_subtract(x, y)
end
defp private_subtract(x, y), do: x - y
end
difference = Calculator.subtract(7, 2)
# => 5
difference = Calculator.private_subtract(7, 2)
# => ** (UndefinedFunctionError) function Calculator.private_subtract/2 is undefined or private
# Calculator.private_subtract(7, 2)
```
### Arity of functions
It is common to refer to functions with their _arity_. The _arity_ of a function is the number of arguments it accepts.
```elixir
# add/3 because this function has three arguments, thus an arity of 3
def add(x, y, z) do
x + y + z
end
```
### Naming conventions
Module names should use `PascalCase`. A module name must start with an uppercase letter `A-Z` and can contain letters `a-zA-Z`, numbers `0-9`, and underscores `_`.
Variable and function names should use `snake_case`. A variable or function name must start with a lowercase letter `a-z` or an underscore `_`, can contain letters `a-zA-Z`, numbers `0-9`, and underscores `_`, and might end with a question mark `?` or an exclamation mark `!`.
### Standard library
Elixir has a very rich and well-documented standard library. The documentation is available online at [hexdocs.pm/elixir][docs]. Save this link somewhere - you will use it a lot!
Most built-in data types have a corresponding module that offers functions for working with that data type, e.g. there's the `Integer` module for integers, `String` module for strings, `List` module for lists and so on.
A notable module is the `Kernel` module. It provides the basic capabilities on top of which the rest of the standard library is built, like arithmetic operators, control-flow macros, and much more. Functions for the `Kernel` module are automatically imported, so you can use them without the `Kernel.` prefix.
### Code comments
Comments can be used to leave notes for other developers reading the source code. Single line comments in Elixir are preceded by `#`.
[functional-programming]: https://en.wikipedia.org/wiki/Functional_programming
[docs]: https://hexdocs.pm/elixir/Kernel.html#content
## Instructions
In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book.
You have five tasks, all related to the time spent cooking the lasagna.
## 1. Define the expected oven time in minutes
Define the `Lasagna.expected_minutes_in_oven/0` function that does not take any arguments and returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40:
```elixir
Lasagna.expected_minutes_in_oven()
# => 40
```
## 2. Calculate the remaining oven time in minutes
Define the `Lasagna.remaining_minutes_in_oven/1` function that takes the actual minutes the lasagna has been in the oven as an argument and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task.
```elixir
Lasagna.remaining_minutes_in_oven(30)
# => 10
```
## 3. Calculate the preparation time in minutes
Define the `Lasagna.preparation_time_in_minutes/1` function that takes the number of layers you added to the lasagna as an argument and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare.
```elixir
Lasagna.preparation_time_in_minutes(2)
# => 4
```
## 4. Calculate the total working time in minutes
Define the `Lasagna.total_time_in_minutes/2` function that takes two arguments: the first argument is the number of layers you added to the lasagna, and the second argument is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment.
```elixir
Lasagna.total_time_in_minutes(3, 20)
# => 26
```
## 5. Create a notification that the lasagna is ready
Define the `Lasagna.alarm/0` function that does not take any arguments and returns a message indicating that the lasagna is ready to eat.
```elixir
Lasagna.alarm()
# => "Ding!"
```
## Source
### Created by
- @neenjaw
### Contributed to by
- @angelikatyborska

View File

@ -0,0 +1,19 @@
defmodule Lasagna do
def expected_minutes_in_oven(), do: 40
def remaining_minutes_in_oven(minutes) do
expected_minutes_in_oven() - minutes
end
def preparation_time_in_minutes(layers) do
layers * 2
end
def total_time_in_minutes(layers, duration) do
preparation_time_in_minutes(layers) + duration
end
def alarm() do
"Ding!"
end
end

28
elixir/lasagna/mix.exs Normal file
View File

@ -0,0 +1,28 @@
defmodule Lasagna.MixProject do
use Mix.Project
def project do
[
app: :lasagna,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,44 @@
defmodule LasagnaTest do
use ExUnit.Case
doctest Lasagna
@tag task_id: 1
test "expected minutes in oven" do
assert Lasagna.expected_minutes_in_oven() === 40
end
@tag task_id: 2
test "remaining minutes in oven" do
assert Lasagna.remaining_minutes_in_oven(25) === 15
end
@tag task_id: 2
test "remaining minutes in oven, a few minutes later" do
assert Lasagna.remaining_minutes_in_oven(30) === 10
end
@tag task_id: 3
test "preparation time in minutes for one layer" do
assert Lasagna.preparation_time_in_minutes(1) === 2
end
@tag task_id: 3
test "preparation time in minutes for multiple layers" do
assert Lasagna.preparation_time_in_minutes(4) === 8
end
@tag task_id: 4
test "total time in minutes for one layer" do
assert Lasagna.total_time_in_minutes(1, 30) === 32
end
@tag task_id: 4
test "total time in minutes for multiple layers" do
assert Lasagna.total_time_in_minutes(4, 8) === 16
end
@tag task_id: 5
test "notification message" do
assert Lasagna.alarm() === "Ding!"
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true, seed: 0)

View File

@ -0,0 +1,22 @@
{
"authors": [
"neenjaw"
],
"files": {
"solution": [
"lib/log_level.ex"
],
"test": [
"test/log_level_test.exs"
],
"exemplar": [
".meta/exemplar.ex"
]
},
"language_versions": ">=1.10",
"forked_from": [
"csharp/logs-logs-logs"
],
"icon": "log-levels",
"blurb": "Learn about atoms and the cond conditional expression by aggregating application logs."
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"log-level","id":"51d3c4c93e0b4f5482f5f444b6af0121","url":"https://exercism.org/tracks/elixir/exercises/log-level","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/log-level/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
cond-*.tar

75
elixir/log-level/HELP.md Normal file
View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/log_level.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

20
elixir/log-level/HINTS.md Normal file
View File

@ -0,0 +1,20 @@
# Hints
## General
- The [atom type is described here][atom].
## 1. Determine the log label
- You can use the [`cond/1` special form][cond] to elegantly handle the various log codes.
- You can use [equality operators][equality] to compare integers for strict type equality.
- There is a [way to specify a default branch][cond] in a cond expression that can be used to catch unspecified cases.
## 2. Send an alert
- You can use the [`cond/1` special form][cond] to decide if an alert should be sent.
- You can use [equality operators][equality] to compare atoms for equality.
[equality]: https://elixir-lang.org/getting-started/basic-operators.html
[atom]: https://elixir-lang.org/getting-started/basic-types.html#atoms
[cond]: https://elixir-lang.org/getting-started/case-cond-and-if.html#cond

View File

@ -0,0 +1,84 @@
# Log Level
Welcome to Log Level on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Atoms
Elixir's `atom` type represents a fixed constant. An atom's value is simply its own name. This gives us a type-safe way to interact with data. Atoms can be defined as follows:
```elixir
# All atoms are preceded with a ':' then follow with alphanumeric snake-cased characters
variable = :an_atom
```
_Atoms_ are internally represented by an integer in a lookup table, which are set automatically. It is not possible to change this internal value.
## Cond
Often, we want to write code that can branch based on a condition. While there are many ways to do this in Elixir, one of the simplest ways is using `cond/1`.
At its simplest, `cond` follows the first path that evaluates to `true` with one or more branches:
```elixir
cond do
x > 10 -> :this_might_be_the_way
y < 7 -> :or_that_might_be_the_way
true -> :this_is_the_default_way
end
```
If no path evaluates to `true`, an error is raised by the runtime.
## Instructions
You are running a system that consists of a few applications producing many logs. You want to write a small program that will aggregate those logs and give them labels according to their severity level. All applications in your system use the same log codes, but some of the legacy applications don't support all the codes.
| Log code | Log label | Supported in legacy apps? |
|-----------------------| --------- | ------------------------- |
| 0 | trace | no |
| 1 | debug | yes |
| 2 | info | yes |
| 3 | warning | yes |
| 4 | error | yes |
| 5 | fatal | no |
| other / not supported | unknown | - |
## 1. Determine the log label
Implement the `LogLevel.to_label/2` function. It should take an integer code and a boolean flag telling you if the log comes from a legacy app, and return the label of a log line as an atom.
Log codes not specified in the table should return an _unknown_ label. Log codes specified in the table as not supported in legacy apps should also return an _unknown_ label if the log came from a legacy app.
```elixir
LogLevel.to_label(0, false)
# => :trace
LogLevel.to_label(0, true)
# => :unknown
```
## 2. Send an alert
Somebody has to be notified when unexpected things happen.
Implement the `LogLevel.alert_recipient/2` function to determine to whom the alert needs to be sent. The function should take an integer code and a boolean flag telling you if the log comes from a legacy app, and return the name of the recipient as an atom.
Use the `LogLevel.to_label/2` function from the previous task. If the log label is _error_ or _fatal_, send the alert to the _ops_ team. If you receive a log with an _unknown_ label from a legacy system, send the alert to the _dev1_ team, other unknown labels should be sent to the _dev2_ team. All other log labels can be safely ignored by returning _false_.
```elixir
LogLevel.alert_recipient(-1, true)
# => :dev1
LogLevel.alert_recipient(0, false)
# => false
```
## Source
### Created by
- @neenjaw

View File

@ -0,0 +1,47 @@
defmodule LogLevel do
@doc """
Log code Log label Supported in legacy apps?
0 trace no
1 debug yes
2 info yes
3 warning yes
4 error yes
5 fatal no
other unknown -
case {level, legacy?} do
{0, false} -> :trace
{1, _} -> :debug
{2, _} -> :info
{3, _} -> :warning
{4, _} -> :error
{5, false} -> :fatal
_ -> :unknown
end
"""
def to_label(level, legacy?) do
cond do
level == 0 and not legacy? -> :trace
level == 1 -> :debug
level == 2 -> :info
level == 3 -> :warning
level == 4 -> :error
level == 5 and not legacy? -> :fatal
true -> :unknown
end
end
@doc """
If the log label is error or fatal, send the alert to the ops team. If you receive a log with an unknown label from a legacy system, send the alert to the dev1 team, other unknown labels should be sent to the dev2 team. All other log labels can be safely ignored by returning false.
"""
def alert_recipient(level, legacy?) do
label = to_label(level, legacy?)
cond do
label in [:error, :fatal] -> :ops
label == :unknown and legacy? -> :dev1
label == :unknown -> :dev2
true -> false
end
end
end

28
elixir/log-level/mix.exs Normal file
View File

@ -0,0 +1,28 @@
defmodule LogLevel.MixProject do
use Mix.Project
def project do
[
app: :log_level,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,101 @@
defmodule LogLevelTest do
use ExUnit.Case
describe "LogLevel.to_label/2" do
@tag task_id: 1
test "level 0 has label trace only in a non-legacy app" do
assert LogLevel.to_label(0, false) == :trace
assert LogLevel.to_label(0, true) == :unknown
end
@tag task_id: 1
test "level 1 has label debug" do
assert LogLevel.to_label(1, false) == :debug
assert LogLevel.to_label(1, true) == :debug
end
@tag task_id: 1
test "level 2 has label info" do
assert LogLevel.to_label(2, false) == :info
assert LogLevel.to_label(2, true) == :info
end
@tag task_id: 1
test "level 3 has label warning" do
assert LogLevel.to_label(3, false) == :warning
assert LogLevel.to_label(3, true) == :warning
end
@tag task_id: 1
test "level 4 has label error" do
assert LogLevel.to_label(4, false) == :error
assert LogLevel.to_label(4, true) == :error
end
@tag task_id: 1
test "level 5 has label fatal only in a non-legacy app" do
assert LogLevel.to_label(5, false) == :fatal
assert LogLevel.to_label(5, true) == :unknown
end
@tag task_id: 1
test "level 6 has label unknown" do
assert LogLevel.to_label(6, false) == :unknown
assert LogLevel.to_label(6, true) == :unknown
end
@tag task_id: 1
test "level -1 has label unknown" do
assert LogLevel.to_label(-1, false) == :unknown
assert LogLevel.to_label(-1, true) == :unknown
end
end
describe "LogLevel.alert_recipient/2" do
@tag task_id: 2
test "fatal code sends alert to ops" do
assert LogLevel.alert_recipient(5, false) == :ops
end
@tag task_id: 2
test "error code sends alert to ops" do
assert LogLevel.alert_recipient(4, false) == :ops
assert LogLevel.alert_recipient(4, true) == :ops
end
@tag task_id: 2
test "unknown code sends alert to dev team 1 for a legacy app" do
assert LogLevel.alert_recipient(6, true) == :dev1
assert LogLevel.alert_recipient(0, true) == :dev1
assert LogLevel.alert_recipient(5, true) == :dev1
end
@tag task_id: 2
test "unknown code sends alert to dev team 2" do
assert LogLevel.alert_recipient(6, false) == :dev2
end
@tag task_id: 2
test "trace code does not send alert" do
assert LogLevel.alert_recipient(0, false) == false
end
@tag task_id: 2
test "debug code does not send alert" do
assert LogLevel.alert_recipient(1, false) == false
assert LogLevel.alert_recipient(1, true) == false
end
@tag task_id: 2
test "info code does not send alert" do
assert LogLevel.alert_recipient(2, false) == false
assert LogLevel.alert_recipient(2, true) == false
end
@tag task_id: 2
test "warning code does not send alert" do
assert LogLevel.alert_recipient(3, false) == false
assert LogLevel.alert_recipient(3, true) == false
end
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true, seed: 0)

View File

@ -0,0 +1,21 @@
{
"authors": [
"neenjaw"
],
"contributors": [
"Cohen-Carlisle"
],
"files": {
"solution": [
"lib/rules.ex"
],
"test": [
"test/rules_test.exs"
],
"exemplar": [
".meta/exemplar.ex"
]
},
"language_versions": ">=1.10",
"blurb": "Learn about booleans by implementing the rules of the Pac-Man game."
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"pacman-rules","id":"cbbe0dc834ef4a5ebbb5c7cb5c59c76d","url":"https://exercism.org/tracks/elixir/exercises/pacman-rules","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/pacman-rules/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
booleans-*.tar

View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/rules.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

View File

@ -0,0 +1,28 @@
# Hints
## General
- Don't worry about how the arguments are derived, just focus on combining the arguments to return the intended result.
## 1. Define if pac-man can eat a ghost
- The function must return a [boolean][boolean] value.
- You can use the [boolean][boolean] operator [`and/2`][boolean-function] to combine the arguments for a result.
## 2. Define if pac-man scores
- The function must return a [boolean][boolean] value.
- You can use the [boolean][boolean] operator [`or/2`][boolean-function] to combine the arguments for a result.
## 3. Define if pac-man loses
- The function must return a [boolean][boolean] value.
- You can use the [boolean][boolean] operators [`and/2`][boolean-function] and [`not/1`][boolean-function] to combine the arguments for a result.
## 4. Define if pac-man wins
- The function must return a [boolean][boolean] value.
- You can use the [boolean][boolean] operators [`and/2`][boolean-function] and [`not/1`][boolean-function] to combine the arguments and results of one of the previously implemented functions.
[boolean]: https://elixir-lang.org/getting-started/basic-types.html#booleans
[boolean-function]: https://elixir-lang.org/getting-started/basic-operators.html

View File

@ -0,0 +1,91 @@
# Pacman Rules
Welcome to Pacman Rules on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Booleans
Elixir represents true and false values with the boolean type. There are only two values: `true` and `false`. These values can be bound to a variable:
```elixir
true_variable = true
false_variable = false
```
We can evaluate strict boolean expressions using the `and/2`, `or/2`, and `not/1` operators.
```elixir
true_variable = true and true
false_variable = true and false
true_variable = false or true
false_variable = false or false
true_variable = not false
false_variable = not true
```
When writing a function that returns a boolean value, it is idiomatic to end the function name with a `?`. The same convention can be used for variables that store boolean values.
```elixir
def either_true?(a?, b?) do
a? or b?
end
```
## Instructions
In this exercise, you need to translate some rules from the classic game Pac-Man into Elixir functions.
You have four rules to translate, all related to the game states.
> Don't worry about how the arguments are derived, just focus on combining the arguments to return the intended result.
## 1. Define if Pac-Man eats a ghost
Define the `Rules.eat_ghost?/2` function that takes two arguments (_if Pac-Man has a power pellet active_ and _if Pac-Man is touching a ghost_) and returns a boolean value if Pac-Man is able to eat the ghost. The function should return true only if Pac-Man has a power pellet active and is touching a ghost.
```elixir
Rules.eat_ghost?(false, true)
# => false
```
## 2. Define if Pac-Man scores
Define the `Rules.score?/2` function that takes two arguments (_if Pac-Man is touching a power pellet_ and _if Pac-Man is touching a dot_) and returns a boolean value if Pac-Man scored. The function should return true if Pac-Man is touching a power pellet or a dot.
```elixir
Rules.score?(true, true)
# => true
```
## 3. Define if Pac-Man loses
Define the `Rules.lose?/2` function that takes two arguments (_if Pac-Man has a power pellet active_ and _if Pac-Man is touching a ghost_) and returns a boolean value if Pac-Man loses. The function should return true if Pac-Man is touching a ghost and does not have a power pellet active.
```elixir
Rules.lose?(false, true)
# => true
```
## 4. Define if Pac-Man wins
Define the `Rules.win?/3` function that takes three arguments (_if Pac-Man has eaten all of the dots_, _if Pac-Man has a power pellet active_, and _if Pac-Man is touching a ghost_) and returns a boolean value if Pac-Man wins. The function should return true if Pac-Man has eaten all of the dots and has not lost based on the arguments defined in part 3.
```elixir
Rules.win?(false, true, false)
# => false
```
## Source
### Created by
- @neenjaw
### Contributed to by
- @Cohen-Carlisle

View File

@ -0,0 +1,11 @@
defmodule Rules do
def eat_ghost?(power_pellet_active?, touching_ghost?), do: power_pellet_active? and touching_ghost?
def score?(touching_power_pellet?, touching_dot?), do: touching_power_pellet? or touching_dot?
def lose?(power_pellet_active?, touching_ghost?), do: not power_pellet_active? and touching_ghost?
def win?(has_eaten_all_dots?, power_pellet_active?, touching_ghost?) do
has_eaten_all_dots? and not lose?(power_pellet_active?, touching_ghost?)
end
end

View File

@ -0,0 +1,28 @@
defmodule Rules.MixProject do
use Mix.Project
def project do
[
app: :pacman_rules,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,76 @@
defmodule RulesTest do
use ExUnit.Case
describe "eat_ghost?/2" do
@tag task_id: 1
test "ghost gets eaten" do
assert Rules.eat_ghost?(true, true)
end
@tag task_id: 1
test "ghost does not get eaten because no power pellet active" do
refute Rules.eat_ghost?(false, true)
end
@tag task_id: 1
test "ghost does not get eaten because not touching ghost" do
refute Rules.eat_ghost?(true, false)
end
@tag task_id: 1
test "ghost does not get eaten because no power pellet is active, even if not touching ghost" do
refute Rules.eat_ghost?(false, false)
end
end
describe "score?/2" do
@tag task_id: 2
test "score when eating dot" do
assert Rules.score?(false, true)
end
@tag task_id: 2
test "score when eating power pellet" do
assert Rules.score?(true, false)
end
@tag task_id: 2
test "no score when nothing eaten" do
refute Rules.score?(false, false)
end
end
describe "lose?/2" do
@tag task_id: 3
test "lose if touching a ghost without a power pellet active" do
assert Rules.lose?(false, true)
end
@tag task_id: 3
test "don't lose if touching a ghost with a power pellet active" do
refute Rules.lose?(true, true)
end
@tag task_id: 3
test "don't lose if not touching a ghost" do
refute Rules.lose?(true, false)
end
end
describe "win?/3" do
@tag task_id: 4
test "win if all dots eaten" do
assert Rules.win?(true, false, false)
end
@tag task_id: 4
test "don't win if all dots eaten, but touching a ghost" do
refute Rules.win?(true, false, true)
end
@tag task_id: 4
test "win if all dots eaten and touching a ghost with a power pellet active" do
assert Rules.win?(true, true, true)
end
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true, seed: 0)

View File

@ -0,0 +1,18 @@
{
"authors": [
"neenjaw"
],
"files": {
"solution": [
"lib/secrets.ex"
],
"test": [
"test/secrets_test.exs"
],
"exemplar": [
".meta/exemplar.ex"
]
},
"language_versions": ">=1.10",
"blurb": "Learn about bit manipulation and anonymous functions by writing the software for an encryption device."
}

View File

@ -0,0 +1 @@
{"track":"elixir","exercise":"secrets","id":"baa7ad210ba049e6be7ec6f9c548a06a","url":"https://exercism.org/tracks/elixir/exercises/secrets","handle":"negrienko","is_requester":true,"auto_approve":false}

View File

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
elixir/secrets/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
anonymous_functions-*.tar

75
elixir/secrets/HELP.md Normal file
View File

@ -0,0 +1,75 @@
# Help
## Running the tests
From the terminal, change to the base directory of the exercise then execute the tests with:
```bash
$ mix test
```
This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs`
Documentation:
* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html)
* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html)
## Pending tests
In test suites of practice exercises, all but the first test have been tagged to be skipped.
Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command:
```bash
$ mix test --include pending
```
Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`.
```elixir
# ExUnit.configure(exclude: :pending, trace: true)
```
## Useful `mix test` options
* `test/<FILE>.exs:LINENUM` - runs only a single test, the test from `<FILE>.exs` whose definition is on line `LINENUM`
* `--failed` - runs only tests that failed the last time they ran
* `--max-failures` - the suite stops evaluating tests when this number of test failures
is reached
* `--seed 0` - disables randomization so the tests in a single file will always be ran
in the same order they were defined in
## Submitting your solution
You can submit your solution using the `exercism submit lib/secrets.ex` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Elixir track's documentation](https://exercism.org/docs/tracks/elixir)
- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/elixir/resources) out there where answers might be found.

47
elixir/secrets/HINTS.md Normal file
View File

@ -0,0 +1,47 @@
# Hints
## General
- Make use of [anonymous functions][anon-fns].
- Use a [closure][closure] to reference the variable from the outer scope.
## 1. Create an adder
- Return an anonymous function which adds the argument from the anonymous function to the argument passed in to `Secret.secret_add/1`.
## 2. Create a subtractor
- Return an anonymous function which subtracts the argument passed in to `Secret.secret_subtract/1` from the argument from the anonymous function.
## 3. Create a multiplier
- Return an anonymous function which multiplies the argument from the anonymous function to the argument passed in to `Secret.secret_multiply/1`.
## 4. Create a divider
- Return an anonymous function which divides the argument from the anonymous function by the argument passed in to `Secret.secret_divide/1`.
- Make use of [integer division][div].
## 5. Create an "and"-er
- Return an anonymous function which performs a [bitwise _and_][bitwise-wiki] operation using the argument passed in to the anonymous function and the argument passed in to `Secret.secret_and/1`
- Functions in the [Bitwise module][bitwise-hexdocs] may be of use.
- If you are running Elixir version 1.9 or lower, you will need to call `require Bitwise` at the beginning of the module definition to be able to use the _Bitwise_ module.
## 6. Create an "xor"-er
- Return an anonymous function which performs a [bitwise _xor_][bitwise-wiki] operation using the argument passed in to the anonymous function and the argument passed in to `Secret.secret_xor/1`
- Functions in the [Bitwise module][bitwise-hexdocs] may be of use.
- If you are running Elixir version 1.9 or lower, you will need to call `require Bitwise` at the beginning of the module definition to be able to use the _Bitwise_ module.
## 7. Create a function combiner
- Return an anonymous function which [composes the functions][fn-composition] passed in to `Secret.secret_combine/2`.
- Use a `.` before `()` when calling an anonymous function.
[anon-fns]: https://elixir-lang.org/getting-started/basic-types.html#anonymous-functions
[bitwise-hexdocs]: https://hexdocs.pm/elixir/Bitwise.html
[bitwise-wiki]: https://en.wikipedia.org/wiki/Bitwise_operation
[closure]: https://en.wikipedia.org/wiki/Closure_(computer_programming)
[div]: https://hexdocs.pm/elixir/Kernel.html#div/2
[fn-composition]: https://en.wikipedia.org/wiki/Function_composition_(computer_science)

155
elixir/secrets/README.md Normal file
View File

@ -0,0 +1,155 @@
# Secrets
Welcome to Secrets on Exercism's Elixir Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
## Introduction
## Anonymous Functions
Functions are treated as first class citizens in Elixir. This means that:
- Named and anonymous functions can be assigned to variables.
- Named and anonymous functions can be passed around like data as arguments and return values.
- Anonymous functions can be created dynamically.
Anonymous functions, in contrast to named functions, don't have a static reference available to them, they are only available if they are assigned to a variable or immediately invoked.
We might use anonymous functions to:
- Hide data using lexical scope (also known as a closure).
- Dynamically create functions at run-time.
Anonymous functions start with the reserved word `fn`, the arguments are separated from the body of the function with the `->` token, and they are finished with an `end`. As with named functions, the last expression in the function is _implicitly returned_ to the calling function.
To invoke a function reference, you must use a `.` between the reference variable and the list of arguments:
```elixir
function_variable = fn param ->
param + 1
end
function_variable.(1)
# => 2
```
You can even use short hand capture notation to make this more concise:
```elixir
variable = &(&1 + 1)
variable.(1)
# => 2
```
## Bit Manipulation
Elixir supports many functions for working with bits found in the _Bitwise module_.
- `band/2`: bitwise AND
- `bsl/2`: bitwise SHIFT LEFT
- `bsr/2`: bitwise SHIFT RIGHT
- `bxor/2`: bitwise XOR
- `bor/2`: bitwise OR
- `bnot/1`: bitwise NOT
Here is an example how to use a bitwise function:
```elixir
Bitwise.bsl(1, 3)
# => 8
```
All bitwise functions only work on integers.
If you are running Elixir version 1.9 or lower, you will need to call `require Bitwise` at the beginning of the module definition to be able to use the _Bitwise_ module.
## Instructions
In this exercise, you've been tasked with writing the software for an encryption device that works by performing transformations on data. You need a way to flexibly create complicated functions by combining simpler functions together.
For each task, return an anonymous function that can be invoked from the calling scope.
All functions should expect integer arguments. Integers are also suitable for performing bitwise operations in Elixir.
## 1. Create an adder
Implement `Secrets.secret_add/1`. It should return a function which takes one argument and adds to it the argument passed in to `secret_add`.
```elixir
adder = Secrets.secret_add(2)
adder.(2)
# => 4
```
## 2. Create a subtractor
Implement `Secrets.secret_subtract/1`. It should return a function which takes one argument and subtracts the secret passed in to `secret_subtract` from that argument.
```elixir
subtractor = Secrets.secret_subtract(2)
subtractor.(3)
# => 1
```
## 3. Create a multiplier
Implement `Secrets.secret_multiply/1`. It should return a function which takes one argument and multiplies it by the secret passed in to `secret_multiply`.
```elixir
multiplier = Secrets.secret_multiply(7)
multiplier.(3)
# => 21
```
## 4. Create a divider
Implement `Secrets.secret_divide/1`. It should return a function which takes one argument and divides it by the secret passed in to `secret_divide`.
```elixir
divider = Secrets.secret_divide(3)
divider.(32)
# => 10
```
Make use of integer division so the output is compatible with the other functions' expected input.
## 5. Create an "and"-er
Implement `Secrets.secret_and/1`. It should return a function which takes one argument and performs a bitwise _and_ operation on it and the secret passed in to `secret_and`.
```elixir
ander = Secrets.secret_and(1)
ander.(2)
# => 0
```
## 6. Create an "xor"-er
Implement `Secrets.secret_xor/1`. It should return a function which takes one argument and performs a bitwise _xor_ operation on it and the secret passed in to `secret_xor`.
```elixir
xorer = Secrets.secret_xor(1)
xorer.(3)
# => 2
```
## 7. Create a function combiner
Implement `Secrets.secret_combine/2`. It should return a function which takes one argument and applies to it the two functions passed in to `secret_combine` in order.
```elixir
multiply = Secrets.secret_multiply(7)
divide = Secrets.secret_divide(3)
combined = Secrets.secret_combine(multiply, divide)
combined.(6)
# => 14
```
## Source
### Created by
- @neenjaw

View File

@ -0,0 +1,29 @@
defmodule Secrets do
def secret_add(secret) do
&(&1 + secret)
end
def secret_subtract(secret) do
&(&1 - secret)
end
def secret_multiply(secret) do
&(&1 * secret)
end
def secret_divide(secret) do
&(div(&1, secret))
end
def secret_and(secret) do
&(Bitwise.band(secret, &1))
end
def secret_xor(secret) do
&(Bitwise.bxor(secret, &1))
end
def secret_combine(secret_function1, secret_function2) do
&(secret_function2.(secret_function1.(&1)))
end
end

28
elixir/secrets/mix.exs Normal file
View File

@ -0,0 +1,28 @@
defmodule Secrets.MixProject do
use Mix.Project
def project do
[
app: :secrets,
version: "0.1.0",
# elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

View File

@ -0,0 +1,179 @@
defmodule SecretsTest do
use ExUnit.Case
describe "secret_add" do
@tag task_id: 1
test "add 3" do
add = Secrets.secret_add(3)
assert add.(3) === 6
end
@tag task_id: 1
test "add 6" do
add = Secrets.secret_add(6)
assert add.(9) === 15
end
end
describe "secret_subtract" do
@tag task_id: 2
test "subtract 3" do
subtract = Secrets.secret_subtract(3)
assert subtract.(6) === 3
end
@tag task_id: 2
test "subtract 6" do
subtract = Secrets.secret_subtract(6)
assert subtract.(3) === -3
end
end
describe "secret_multiply" do
@tag task_id: 3
test "multiply by 3" do
multiply = Secrets.secret_multiply(3)
assert multiply.(6) === 18
end
@tag task_id: 3
test "multiply by 6" do
multiply = Secrets.secret_multiply(6)
assert multiply.(7) === 42
end
end
describe "secret_divide" do
@tag task_id: 4
test "divide by 3" do
divide = Secrets.secret_divide(3)
assert divide.(6) === 2
end
@tag task_id: 4
test "divide by 6" do
divide = Secrets.secret_divide(6)
assert divide.(7) === 1
end
end
describe "secret_and" do
@tag task_id: 5
test "2 and 1" do
ander = Secrets.secret_and(1)
assert ander.(2) === 0
end
@tag task_id: 5
test "7 and 7" do
ander = Secrets.secret_and(7)
assert ander.(7) === 7
end
end
describe "secret_xor" do
@tag task_id: 6
test "2 xor 1" do
xorer = Secrets.secret_xor(1)
assert xorer.(2) === 3
end
@tag task_id: 6
test "7 xor 7" do
xorer = Secrets.secret_xor(7)
assert xorer.(7) === 0
end
end
describe "secret_combine" do
@tag task_id: 7
test "5 add 10 then subtract 5" do
f = Secrets.secret_add(10)
g = Secrets.secret_subtract(5)
h = Secrets.secret_combine(f, g)
assert h.(5) === 10
end
@tag task_id: 7
test "100 multiply by 2 then subtract 20" do
f = Secrets.secret_multiply(2)
g = Secrets.secret_subtract(20)
h = Secrets.secret_combine(f, g)
assert h.(100) === 180
end
@tag task_id: 7
test "100 divide by 10 then add 10" do
f = Secrets.secret_divide(10)
g = Secrets.secret_add(10)
h = Secrets.secret_combine(f, g)
assert h.(100) === 20
end
@tag task_id: 7
test "32 divide by 3 then add 5" do
f = Secrets.secret_divide(3)
g = Secrets.secret_add(5)
h = Secrets.secret_combine(f, g)
assert h.(32) === 15
end
@tag task_id: 7
test "7 and 3 then and 5" do
f = Secrets.secret_and(3)
g = Secrets.secret_and(5)
h = Secrets.secret_combine(f, g)
assert h.(7) === 1
end
@tag task_id: 7
test "7 and 7 then and 7" do
f = Secrets.secret_and(7)
g = Secrets.secret_and(7)
h = Secrets.secret_combine(f, g)
assert h.(7) === 7
end
@tag task_id: 7
test "4 xor 1 then xor 2" do
f = Secrets.secret_xor(1)
g = Secrets.secret_xor(2)
h = Secrets.secret_combine(f, g)
assert h.(4) === 7
end
@tag task_id: 7
test "7 xor 7 then xor 7" do
f = Secrets.secret_xor(7)
g = Secrets.secret_xor(7)
h = Secrets.secret_combine(f, g)
assert h.(7) === 7
end
@tag task_id: 7
test "4 add 3 then xor 7" do
f = Secrets.secret_add(3)
g = Secrets.secret_xor(7)
h = Secrets.secret_combine(f, g)
assert h.(4) === 0
end
@tag task_id: 7
test "81 divide by 9 then and 7" do
f = Secrets.secret_divide(9)
g = Secrets.secret_and(7)
h = Secrets.secret_combine(f, g)
assert h.(81) === 1
end
end
end

View File

@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true, seed: 0)