Compare commits
100 Commits
5c704aa88f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 95c9a93dec | |||
| cbeda5d38b | |||
| 5f594b12e3 | |||
| ab3508e9fc | |||
| a33fa3295c | |||
| 2cb2de4caf | |||
| 79f77f009a | |||
| 1a4c55bdaf | |||
| 6bcb4db837 | |||
| d9bc141e51 | |||
| d00a9787f9 | |||
| 2b764143c4 | |||
| b21db6b2f9 | |||
| 64030231bf | |||
| 7856986097 | |||
| 4e5b4dceeb | |||
| 00a1a882dd | |||
| 58eac331ab | |||
| 44ca0cb19b | |||
| 34e04eff6a | |||
| 22d545194e | |||
| 379e523c04 | |||
| 0c3373b87e | |||
| 1224cca405 | |||
| 7b3e6d3216 | |||
| 2eb14fcd40 | |||
| 643a41d53c | |||
| 2b1e10247b | |||
| 81b389528e | |||
| 721b4e4ed6 | |||
| c2e651cd5a | |||
| 0aef8da6d9 | |||
| e0d8231e91 | |||
| 1610d6caf3 | |||
| 66f0e9c6f8 | |||
| 9425fd5368 | |||
| 15ab62c4f1 | |||
| 1ae69450e8 | |||
| 320bdc1286 | |||
| 780dc17b36 | |||
| 6e761f7041 | |||
| 8fbd81ed9d | |||
| dad68cb89f | |||
| 8d8a30b39c | |||
| 9adeef7c61 | |||
| 26a8976b52 | |||
| 8a0b02049f | |||
| c7b7989ccd | |||
| 146d1d3f89 | |||
| b5a8d35513 | |||
| 15f39c5c5b | |||
| 79c17a8c59 | |||
| 140299f646 | |||
| fcc4ddb61c | |||
| eb76c60826 | |||
| 10cfc2215b | |||
| b62fcbc5ea | |||
| 4c3da6abe4 | |||
| fd86d9545f | |||
| e0c8beb31f | |||
| 22b46519fd | |||
| d46a9b8e9a | |||
| 4265743d75 | |||
| af9641f4e9 | |||
| e950cc6d90 | |||
| c625ecedd6 | |||
| 3c7f1d64f5 | |||
| bb65cd30cc | |||
| def44c9d46 | |||
| 5203753bd5 | |||
| 3ab71444f5 | |||
| b4e1570ba6 | |||
| 5704073c97 | |||
| 8a0a02f996 | |||
| ed251fd37d | |||
| 7ae168f5ea | |||
| d1b894006c | |||
| 0c15aedc09 | |||
| c62233f40f | |||
| eab9b54f20 | |||
| af3b5c40f8 | |||
| e2e3430ef8 | |||
| cd5d83851d | |||
| 3b19351ce4 | |||
| 42bdf9694e | |||
| 776a104f19 | |||
| 833fe9c0f5 | |||
| ec644472b3 | |||
| f324155864 | |||
| 2465a18235 | |||
| db731118fc | |||
| 9d03ff01dc | |||
| 3001618707 | |||
| 53d94ff371 | |||
| 7332230435 | |||
| b69dc97356 | |||
| a4a5085d00 | |||
| 5f3aa01e4d | |||
| b8a7845967 | |||
| 5cc59f9234 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -23,4 +23,6 @@ Icon
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
.apdisk
|
||||
|
||||
.vscode
|
||||
35
elixir/acronym/.exercism/config.json
Normal file
35
elixir/acronym/.exercism/config.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"authors": [
|
||||
"Teapane"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"Cohen-Carlisle",
|
||||
"dalexj",
|
||||
"devonestes",
|
||||
"gmile",
|
||||
"henrik",
|
||||
"jwworth",
|
||||
"lpil",
|
||||
"martinsvalin",
|
||||
"neenjaw",
|
||||
"parkerl",
|
||||
"rubysolo",
|
||||
"sotojuan",
|
||||
"waiting-for-dev"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/acronym.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/acronym_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Convert a long phrase to its acronym.",
|
||||
"source": "Julien Vanier",
|
||||
"source_url": "https://github.com/monkbroc"
|
||||
}
|
||||
1
elixir/acronym/.exercism/metadata.json
Normal file
1
elixir/acronym/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"acronym","id":"6e61a6a0f47e4396aad6d4854fe80fb4","url":"https://exercism.org/tracks/elixir/exercises/acronym","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/acronym/.formatter.exs
Normal file
4
elixir/acronym/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/acronym/.gitignore
vendored
Normal file
24
elixir/acronym/.gitignore
vendored
Normal 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").
|
||||
acronym-*.tar
|
||||
|
||||
75
elixir/acronym/HELP.md
Normal file
75
elixir/acronym/HELP.md
Normal 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/acronym.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.
|
||||
49
elixir/acronym/README.md
Normal file
49
elixir/acronym/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Acronym
|
||||
|
||||
Welcome to Acronym on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Convert a phrase to its acronym.
|
||||
|
||||
Techies love their TLA (Three Letter Acronyms)!
|
||||
|
||||
Help generate some jargon by writing a program that converts a long name like Portable Network Graphics to its acronym (PNG).
|
||||
|
||||
Punctuation is handled as follows: hyphens are word separators (like whitespace); all other punctuation can be removed from the input.
|
||||
|
||||
For example:
|
||||
|
||||
| Input | Output |
|
||||
| ------------------------- | ------ |
|
||||
| As Soon As Possible | ASAP |
|
||||
| Liquid-crystal display | LCD |
|
||||
| Thank George It's Friday! | TGIF |
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @Teapane
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @Cohen-Carlisle
|
||||
- @dalexj
|
||||
- @devonestes
|
||||
- @gmile
|
||||
- @henrik
|
||||
- @jwworth
|
||||
- @lpil
|
||||
- @martinsvalin
|
||||
- @neenjaw
|
||||
- @parkerl
|
||||
- @rubysolo
|
||||
- @sotojuan
|
||||
- @waiting-for-dev
|
||||
|
||||
### Based on
|
||||
|
||||
Julien Vanier - https://github.com/monkbroc
|
||||
14
elixir/acronym/lib/acronym.ex
Normal file
14
elixir/acronym/lib/acronym.ex
Normal file
@@ -0,0 +1,14 @@
|
||||
defmodule Acronym do
|
||||
@doc """
|
||||
Generate an acronym from a string.
|
||||
"This is a string" => "TIAS"
|
||||
"""
|
||||
@spec abbreviate(String.t()) :: String.t()
|
||||
def abbreviate(string) do
|
||||
string
|
||||
|> String.split([" ", "-", "_"], trim: true)
|
||||
|> Enum.map(&String.first/1)
|
||||
|> Enum.join()
|
||||
|> String.upcase()
|
||||
end
|
||||
end
|
||||
28
elixir/acronym/mix.exs
Normal file
28
elixir/acronym/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule Acronym.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :acronym,
|
||||
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
|
||||
49
elixir/acronym/test/acronym_test.exs
Normal file
49
elixir/acronym/test/acronym_test.exs
Normal file
@@ -0,0 +1,49 @@
|
||||
defmodule AcronymTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test "it produces acronyms from title case" do
|
||||
assert Acronym.abbreviate("Portable Networks Graphic") === "PNG"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces acronyms from lower case" do
|
||||
assert Acronym.abbreviate("Ruby on Rails") === "ROR"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it ignores punctuation" do
|
||||
assert Acronym.abbreviate("First in, First out") === "FIFO"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces acronyms from phrases with acronyms" do
|
||||
assert Acronym.abbreviate("GNU Image Manipulation Program") === "GIMP"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces acronyms ignoring punctuation and casing" do
|
||||
assert Acronym.abbreviate("Complementary Metal-Oxide semiconductor") === "CMOS"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces a very long abbreviation" do
|
||||
assert Acronym.abbreviate(
|
||||
"Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me"
|
||||
) === "ROTFLSHTMDCOALM"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces acronyms from phrases with consecutive delimiters" do
|
||||
assert Acronym.abbreviate("Something - I made up from thin air") === "SIMUFTA"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces acronyms from phrases with apostrophes" do
|
||||
assert Acronym.abbreviate("Halley's Comet") === "HC"
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "it produces acronyms from phrases with underscore emphasis" do
|
||||
assert Acronym.abbreviate("The Road _Not_ Taken") === "TRNT"
|
||||
end
|
||||
end
|
||||
2
elixir/acronym/test/test_helper.exs
Normal file
2
elixir/acronym/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
27
elixir/all-your-base/.exercism/config.json
Normal file
27
elixir/all-your-base/.exercism/config.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"authors": [
|
||||
"ananthamapod"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"ChristianTovar",
|
||||
"Cohen-Carlisle",
|
||||
"devonestes",
|
||||
"neenjaw",
|
||||
"parkerl",
|
||||
"sotojuan",
|
||||
"ybod"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/all_your_base.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/all_your_base_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Convert a number, represented as a sequence of digits in one base, to any other base."
|
||||
}
|
||||
1
elixir/all-your-base/.exercism/metadata.json
Normal file
1
elixir/all-your-base/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"all-your-base","id":"98d3bf453a6d4f1383988013aadb22c0","url":"https://exercism.org/tracks/elixir/exercises/all-your-base","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/all-your-base/.formatter.exs
Normal file
4
elixir/all-your-base/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/all-your-base/.gitignore
vendored
Normal file
24
elixir/all-your-base/.gitignore
vendored
Normal 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").
|
||||
all_your_base-*.tar
|
||||
|
||||
75
elixir/all-your-base/HELP.md
Normal file
75
elixir/all-your-base/HELP.md
Normal 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/all_your_base.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.
|
||||
55
elixir/all-your-base/README.md
Normal file
55
elixir/all-your-base/README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# All Your Base
|
||||
|
||||
Welcome to All Your Base on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Convert a number, represented as a sequence of digits in one base, to any other base.
|
||||
|
||||
Implement general base conversion.
|
||||
Given a number in base **a**, represented as a sequence of digits, convert it to base **b**.
|
||||
|
||||
## Note
|
||||
|
||||
- Try to implement the conversion yourself.
|
||||
Do not use something else to perform the conversion for you.
|
||||
|
||||
## About [Positional Notation][positional-notation]
|
||||
|
||||
In positional notation, a number in base **b** can be understood as a linear combination of powers of **b**.
|
||||
|
||||
The number 42, _in base 10_, means:
|
||||
|
||||
`(4 * 10^1) + (2 * 10^0)`
|
||||
|
||||
The number 101010, _in base 2_, means:
|
||||
|
||||
`(1 * 2^5) + (0 * 2^4) + (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (0 * 2^0)`
|
||||
|
||||
The number 1120, _in base 3_, means:
|
||||
|
||||
`(1 * 3^3) + (1 * 3^2) + (2 * 3^1) + (0 * 3^0)`
|
||||
|
||||
I think you got the idea!
|
||||
|
||||
_Yes. Those three numbers above are exactly the same. Congratulations!_
|
||||
|
||||
[positional-notation]: https://en.wikipedia.org/wiki/Positional_notation
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @ananthamapod
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @ChristianTovar
|
||||
- @Cohen-Carlisle
|
||||
- @devonestes
|
||||
- @neenjaw
|
||||
- @parkerl
|
||||
- @sotojuan
|
||||
- @ybod
|
||||
31
elixir/all-your-base/lib/all_your_base.ex
Normal file
31
elixir/all-your-base/lib/all_your_base.ex
Normal file
@@ -0,0 +1,31 @@
|
||||
defmodule AllYourBase do
|
||||
@doc """
|
||||
Given a number in input base, represented as a sequence of digits, converts it to output base,
|
||||
or returns an error tuple if either of the bases are less than 2
|
||||
"""
|
||||
|
||||
@spec convert(list, integer, integer) :: {:ok, list} | {:error, String.t()}
|
||||
def convert(_digits, input_base, _output_base) when input_base < 2,
|
||||
do: {:error, "input base must be >= 2"}
|
||||
|
||||
def convert(_digits, _input_base, output_base) when output_base < 2,
|
||||
do: {:error, "output base must be >= 2"}
|
||||
|
||||
def convert([0 | digits], input_base, output_base), do: convert(digits, input_base, output_base)
|
||||
|
||||
def convert(digits, input_base, output_base) do
|
||||
unless Enum.all?(digits, &valid_digit?(&1, input_base)) do
|
||||
{:error, "all digits must be >= 0 and < input base"}
|
||||
else
|
||||
result =
|
||||
digits
|
||||
|> Integer.undigits(input_base)
|
||||
|> Integer.digits(output_base)
|
||||
|
||||
{:ok, result}
|
||||
end
|
||||
end
|
||||
|
||||
defp valid_digit?(digit, base) when digit >= 0 and digit < base, do: true
|
||||
defp valid_digit?(_digit, _base), do: false
|
||||
end
|
||||
28
elixir/all-your-base/mix.exs
Normal file
28
elixir/all-your-base/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule AllYourBase.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :all_your_base,
|
||||
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
|
||||
109
elixir/all-your-base/test/all_your_base_test.exs
Normal file
109
elixir/all-your-base/test/all_your_base_test.exs
Normal file
@@ -0,0 +1,109 @@
|
||||
defmodule AllYourBaseTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test "convert single bit one to decimal" do
|
||||
assert AllYourBase.convert([1], 2, 10) == {:ok, [1]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert binary to single decimal" do
|
||||
assert AllYourBase.convert([1, 0, 1], 2, 10) == {:ok, [5]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert single decimal to binary" do
|
||||
assert AllYourBase.convert([5], 10, 2) == {:ok, [1, 0, 1]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert binary to multiple decimal" do
|
||||
assert AllYourBase.convert([1, 0, 1, 0, 1, 0], 2, 10) == {:ok, [4, 2]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert decimal to binary" do
|
||||
assert AllYourBase.convert([4, 2], 10, 2) == {:ok, [1, 0, 1, 0, 1, 0]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert trinary to hexadecimal" do
|
||||
assert AllYourBase.convert([1, 1, 2, 0], 3, 16) == {:ok, [2, 10]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert hexadecimal to trinary" do
|
||||
assert AllYourBase.convert([2, 10], 16, 3) == {:ok, [1, 1, 2, 0]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert 15-bit integer" do
|
||||
assert AllYourBase.convert([3, 46, 60], 97, 73) == {:ok, [6, 10, 45]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert empty list" do
|
||||
assert AllYourBase.convert([], 2, 10) == {:ok, [0]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert single zero" do
|
||||
assert AllYourBase.convert([0], 10, 2) == {:ok, [0]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert multiple zeros" do
|
||||
assert AllYourBase.convert([0, 0, 0], 10, 2) == {:ok, [0]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert leading zeros" do
|
||||
assert AllYourBase.convert([0, 6, 0], 7, 10) == {:ok, [4, 2]}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert first base is one" do
|
||||
assert AllYourBase.convert([0], 1, 10) == {:error, "input base must be >= 2"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert first base is zero" do
|
||||
assert AllYourBase.convert([], 0, 10) == {:error, "input base must be >= 2"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert first base is negative" do
|
||||
assert AllYourBase.convert([1], -2, 10) == {:error, "input base must be >= 2"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert negative digit" do
|
||||
assert AllYourBase.convert([1, -1, 1, 0, 1, 0], 2, 10) ==
|
||||
{:error, "all digits must be >= 0 and < input base"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert invalid positive digit" do
|
||||
assert AllYourBase.convert([1, 2, 1, 0, 1, 0], 2, 10) ==
|
||||
{:error, "all digits must be >= 0 and < input base"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert second base is one" do
|
||||
assert AllYourBase.convert([1, 0, 1, 0, 1, 0], 2, 1) == {:error, "output base must be >= 2"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert second base is zero" do
|
||||
assert AllYourBase.convert([7], 10, 0) == {:error, "output base must be >= 2"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert second base is negative" do
|
||||
assert AllYourBase.convert([1], 2, -7) == {:error, "output base must be >= 2"}
|
||||
end
|
||||
|
||||
# @tag :pending
|
||||
test "convert both bases are negative" do
|
||||
assert AllYourBase.convert([1], -2, -7) == {:error, "input base must be >= 2"}
|
||||
end
|
||||
end
|
||||
2
elixir/all-your-base/test/test_helper.exs
Normal file
2
elixir/all-your-base/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
37
elixir/allergies/.exercism/config.json
Normal file
37
elixir/allergies/.exercism/config.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"authors": [
|
||||
"rubysolo"
|
||||
],
|
||||
"contributors": [
|
||||
"andrewsardone",
|
||||
"angelikatyborska",
|
||||
"Cohen-Carlisle",
|
||||
"dalexj",
|
||||
"devonestes",
|
||||
"ggpasqualino",
|
||||
"jinyeow",
|
||||
"lpil",
|
||||
"martinsvalin",
|
||||
"meadsteve",
|
||||
"montague",
|
||||
"neenjaw",
|
||||
"parkerl",
|
||||
"sotojuan",
|
||||
"Teapane",
|
||||
"waiting-for-dev"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/allergies.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/allergies_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies.",
|
||||
"source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
|
||||
"source_url": "https://turing.edu"
|
||||
}
|
||||
1
elixir/allergies/.exercism/metadata.json
Normal file
1
elixir/allergies/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"allergies","id":"0f056a8c570349d4b0832bbf025c5c86","url":"https://exercism.org/tracks/elixir/exercises/allergies","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/allergies/.formatter.exs
Normal file
4
elixir/allergies/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/allergies/.gitignore
vendored
Normal file
24
elixir/allergies/.gitignore
vendored
Normal 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").
|
||||
allergies-*.tar
|
||||
|
||||
75
elixir/allergies/HELP.md
Normal file
75
elixir/allergies/HELP.md
Normal 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/allergies.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.
|
||||
61
elixir/allergies/README.md
Normal file
61
elixir/allergies/README.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Allergies
|
||||
|
||||
Welcome to Allergies on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies.
|
||||
|
||||
An allergy test produces a single numeric score which contains the information about all the allergies the person has (that they were tested for).
|
||||
|
||||
The list of items (and their value) that were tested are:
|
||||
|
||||
- eggs (1)
|
||||
- peanuts (2)
|
||||
- shellfish (4)
|
||||
- strawberries (8)
|
||||
- tomatoes (16)
|
||||
- chocolate (32)
|
||||
- pollen (64)
|
||||
- cats (128)
|
||||
|
||||
So if Tom is allergic to peanuts and chocolate, he gets a score of 34.
|
||||
|
||||
Now, given just that score of 34, your program should be able to say:
|
||||
|
||||
- Whether Tom is allergic to any one of those allergens listed above.
|
||||
- All the allergens Tom is allergic to.
|
||||
|
||||
Note: a given score may include allergens **not** listed above (i.e. allergens that score 256, 512, 1024, etc.).
|
||||
Your program should ignore those components of the score.
|
||||
For example, if the allergy score is 257, your program should only report the eggs (1) allergy.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @rubysolo
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @andrewsardone
|
||||
- @angelikatyborska
|
||||
- @Cohen-Carlisle
|
||||
- @dalexj
|
||||
- @devonestes
|
||||
- @ggpasqualino
|
||||
- @jinyeow
|
||||
- @lpil
|
||||
- @martinsvalin
|
||||
- @meadsteve
|
||||
- @montague
|
||||
- @neenjaw
|
||||
- @parkerl
|
||||
- @sotojuan
|
||||
- @Teapane
|
||||
- @waiting-for-dev
|
||||
|
||||
### Based on
|
||||
|
||||
Exercise by the JumpstartLab team for students at The Turing School of Software and Design. - https://turing.edu
|
||||
27
elixir/allergies/lib/allergies.ex
Normal file
27
elixir/allergies/lib/allergies.ex
Normal file
@@ -0,0 +1,27 @@
|
||||
defmodule Allergies do
|
||||
@allergens %{
|
||||
"eggs" => 1,
|
||||
"peanuts" => 2,
|
||||
"shellfish" => 4,
|
||||
"strawberries" => 8,
|
||||
"tomatoes" => 16,
|
||||
"chocolate" => 32,
|
||||
"pollen" => 64,
|
||||
"cats" => 128
|
||||
}
|
||||
|
||||
@doc """
|
||||
List the allergies for which the corresponding flag bit is true.
|
||||
"""
|
||||
@spec list(non_neg_integer) :: [String.t()]
|
||||
def list(flags) do
|
||||
for {allergen, mask} <- @allergens, allergic_to?(mask, flags), do: allergen
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns whether the corresponding flag bit in 'flags' is set for the item.
|
||||
"""
|
||||
@spec allergic_to?(non_neg_integer, String.t() | non_neg_integer) :: boolean
|
||||
def allergic_to?(flags, mask) when is_integer(mask), do: Bitwise.band(mask, flags) > 0
|
||||
def allergic_to?(flags, allergen) when is_binary(allergen), do: allergic_to?(@allergens[allergen], flags)
|
||||
end
|
||||
28
elixir/allergies/mix.exs
Normal file
28
elixir/allergies/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule Allergies.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :allergies,
|
||||
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
|
||||
241
elixir/allergies/test/allergies_test.exs
Normal file
241
elixir/allergies/test/allergies_test.exs
Normal file
@@ -0,0 +1,241 @@
|
||||
defmodule AllergiesTest do
|
||||
use ExUnit.Case
|
||||
|
||||
defp assert_is_a_set_containing(list, to_contain) do
|
||||
set = Enum.into(list, MapSet.new())
|
||||
|
||||
same_contents =
|
||||
to_contain
|
||||
|> Enum.into(MapSet.new())
|
||||
|> MapSet.equal?(set)
|
||||
|
||||
assert same_contents,
|
||||
"Expected a set with: #{inspect(to_contain)} got #{inspect(set |> MapSet.to_list())}"
|
||||
end
|
||||
|
||||
describe "allergy list against expected allergens -" do
|
||||
test "no allergies at all" do
|
||||
Allergies.list(0) |> assert_is_a_set_containing([])
|
||||
end
|
||||
|
||||
test "allergic to just eggs" do
|
||||
Allergies.list(1) |> assert_is_a_set_containing(~w[eggs])
|
||||
end
|
||||
|
||||
test "allergic to just peanuts" do
|
||||
Allergies.list(2) |> assert_is_a_set_containing(~w[peanuts])
|
||||
end
|
||||
|
||||
test "allergic to just strawberries" do
|
||||
Allergies.list(8) |> assert_is_a_set_containing(~w[strawberries])
|
||||
end
|
||||
|
||||
test "allergic to eggs and peanuts" do
|
||||
Allergies.list(3) |> assert_is_a_set_containing(~w[eggs peanuts])
|
||||
end
|
||||
|
||||
test "allergic to more than eggs but not peanuts" do
|
||||
Allergies.list(5) |> assert_is_a_set_containing(~w[eggs shellfish])
|
||||
end
|
||||
|
||||
test "allergic to lots of stuff" do
|
||||
Allergies.list(248)
|
||||
|> assert_is_a_set_containing(~w[strawberries tomatoes chocolate pollen cats])
|
||||
end
|
||||
|
||||
test "allergic to everything" do
|
||||
Allergies.list(255)
|
||||
|> assert_is_a_set_containing(
|
||||
~w[eggs peanuts shellfish strawberries tomatoes chocolate pollen cats]
|
||||
)
|
||||
end
|
||||
|
||||
test "ignore non allergen score parts" do
|
||||
Allergies.list(509)
|
||||
|> assert_is_a_set_containing(
|
||||
~w[eggs shellfish strawberries tomatoes chocolate pollen cats]
|
||||
)
|
||||
end
|
||||
|
||||
test "ignore non allergen score parts without highest valid score" do
|
||||
Allergies.list(257)
|
||||
|> assert_is_a_set_containing(~w[eggs])
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for egg allergies -" do
|
||||
test "not allergic to eggs" do
|
||||
refute Allergies.allergic_to?(0, "eggs")
|
||||
end
|
||||
|
||||
test "is allergic to only eggs" do
|
||||
assert Allergies.allergic_to?(1, "eggs")
|
||||
end
|
||||
|
||||
test "is allergic to eggs and something else" do
|
||||
assert Allergies.allergic_to?(3, "eggs")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not eggs" do
|
||||
refute Allergies.allergic_to?(2, "eggs")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including eggs)" do
|
||||
assert Allergies.allergic_to?(255, "eggs")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for peanuts allergies -" do
|
||||
test "not allergic to peanuts" do
|
||||
refute Allergies.allergic_to?(0, "peanuts")
|
||||
end
|
||||
|
||||
test "is allergic to only peanuts" do
|
||||
assert Allergies.allergic_to?(2, "peanuts")
|
||||
end
|
||||
|
||||
test "is allergic to peanuts and something else" do
|
||||
assert Allergies.allergic_to?(7, "peanuts")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not peanuts" do
|
||||
refute Allergies.allergic_to?(5, "peanuts")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including peanuts)" do
|
||||
assert Allergies.allergic_to?(255, "peanuts")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for shellfish allergies -" do
|
||||
test "not allergic to shellfish" do
|
||||
refute Allergies.allergic_to?(0, "shellfish")
|
||||
end
|
||||
|
||||
test "is allergic to only shellfish" do
|
||||
assert Allergies.allergic_to?(4, "shellfish")
|
||||
end
|
||||
|
||||
test "is allergic to shellfish and something else" do
|
||||
assert Allergies.allergic_to?(14, "shellfish")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not shellfish" do
|
||||
refute Allergies.allergic_to?(10, "shellfish")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including shellfish)" do
|
||||
assert Allergies.allergic_to?(255, "shellfish")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for strawberries allergies -" do
|
||||
test "not allergic to strawberries" do
|
||||
refute Allergies.allergic_to?(0, "strawberries")
|
||||
end
|
||||
|
||||
test "is allergic to only strawberries" do
|
||||
assert Allergies.allergic_to?(8, "strawberries")
|
||||
end
|
||||
|
||||
test "is allergic to strawberries and something else" do
|
||||
assert Allergies.allergic_to?(28, "strawberries")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not strawberries" do
|
||||
refute Allergies.allergic_to?(20, "strawberries")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including strawberries)" do
|
||||
assert Allergies.allergic_to?(255, "strawberries")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for tomatoes allergies -" do
|
||||
test "not allergic to tomatoes" do
|
||||
refute Allergies.allergic_to?(0, "tomatoes")
|
||||
end
|
||||
|
||||
test "is allergic to only tomatoes" do
|
||||
assert Allergies.allergic_to?(16, "tomatoes")
|
||||
end
|
||||
|
||||
test "is allergic to tomatoes and something else" do
|
||||
assert Allergies.allergic_to?(56, "tomatoes")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not tomatoes" do
|
||||
refute Allergies.allergic_to?(40, "tomatoes")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including tomatoes)" do
|
||||
assert Allergies.allergic_to?(255, "tomatoes")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for chocolate allergies -" do
|
||||
test "not allergic to chocolate" do
|
||||
refute Allergies.allergic_to?(0, "chocolate")
|
||||
end
|
||||
|
||||
test "is allergic to only chocolate" do
|
||||
assert Allergies.allergic_to?(32, "chocolate")
|
||||
end
|
||||
|
||||
test "is allergic to chocolate and something else" do
|
||||
assert Allergies.allergic_to?(112, "chocolate")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not chocolate" do
|
||||
refute Allergies.allergic_to?(80, "chocolate")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including chocolate)" do
|
||||
assert Allergies.allergic_to?(255, "chocolate")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for pollen allergies -" do
|
||||
test "not allergic to pollen" do
|
||||
refute Allergies.allergic_to?(0, "pollen")
|
||||
end
|
||||
|
||||
test "is allergic to only pollen" do
|
||||
assert Allergies.allergic_to?(64, "pollen")
|
||||
end
|
||||
|
||||
test "is allergic to pollen and something else" do
|
||||
assert Allergies.allergic_to?(224, "pollen")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not pollen" do
|
||||
refute Allergies.allergic_to?(160, "pollen")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including pollen)" do
|
||||
assert Allergies.allergic_to?(255, "pollen")
|
||||
end
|
||||
end
|
||||
|
||||
describe "score for cats allergies -" do
|
||||
test "not allergic to cats" do
|
||||
refute Allergies.allergic_to?(0, "cats")
|
||||
end
|
||||
|
||||
test "is allergic to only cats" do
|
||||
assert Allergies.allergic_to?(128, "cats")
|
||||
end
|
||||
|
||||
test "is allergic to cats and something else" do
|
||||
assert Allergies.allergic_to?(192, "cats")
|
||||
end
|
||||
|
||||
test "is allergic to something, but not cats" do
|
||||
refute Allergies.allergic_to?(64, "cats")
|
||||
end
|
||||
|
||||
test "is allergic to everything (including cats)" do
|
||||
assert Allergies.allergic_to?(255, "cats")
|
||||
end
|
||||
end
|
||||
end
|
||||
2
elixir/allergies/test/test_helper.exs
Normal file
2
elixir/allergies/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
41
elixir/anagram/.exercism/config.json
Normal file
41
elixir/anagram/.exercism/config.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"authors": [
|
||||
"rubysolo"
|
||||
],
|
||||
"contributors": [
|
||||
"andrewsardone",
|
||||
"angelikatyborska",
|
||||
"Br1ght0ne",
|
||||
"Cohen-Carlisle",
|
||||
"crazymykl",
|
||||
"dalexj",
|
||||
"devonestes",
|
||||
"henrik",
|
||||
"jeremy-w",
|
||||
"jinyeow",
|
||||
"kytrinyx",
|
||||
"lpil",
|
||||
"markijbema",
|
||||
"neenjaw",
|
||||
"parkerl",
|
||||
"pminten",
|
||||
"sotojuan",
|
||||
"Teapane",
|
||||
"tjcelaya",
|
||||
"waiting-for-dev"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/anagram.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/anagram_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Given a word and a list of possible anagrams, select the correct sublist.",
|
||||
"source": "Inspired by the Extreme Startup game",
|
||||
"source_url": "https://github.com/rchatley/extreme_startup"
|
||||
}
|
||||
1
elixir/anagram/.exercism/metadata.json
Normal file
1
elixir/anagram/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"anagram","id":"0ffb252576fd4b4fad8cdd024185d2be","url":"https://exercism.org/tracks/elixir/exercises/anagram","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/anagram/.formatter.exs
Normal file
4
elixir/anagram/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/anagram/.gitignore
vendored
Normal file
24
elixir/anagram/.gitignore
vendored
Normal 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").
|
||||
anagram-*.tar
|
||||
|
||||
75
elixir/anagram/HELP.md
Normal file
75
elixir/anagram/HELP.md
Normal 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/anagram.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.
|
||||
64
elixir/anagram/README.md
Normal file
64
elixir/anagram/README.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Anagram
|
||||
|
||||
Welcome to Anagram on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Introduction
|
||||
|
||||
At a garage sale, you find a lovely vintage typewriter at a bargain price!
|
||||
Excitedly, you rush home, insert a sheet of paper, and start typing away.
|
||||
However, your excitement wanes when you examine the output: all words are garbled!
|
||||
For example, it prints "stop" instead of "post" and "least" instead of "stale."
|
||||
Carefully, you try again, but now it prints "spot" and "slate."
|
||||
After some experimentation, you find there is a random delay before each letter is printed, which messes up the order.
|
||||
You now understand why they sold it for so little money!
|
||||
|
||||
You realize this quirk allows you to generate anagrams, which are words formed by rearranging the letters of another word.
|
||||
Pleased with your finding, you spend the rest of the day generating hundreds of anagrams.
|
||||
|
||||
## Instructions
|
||||
|
||||
Your task is to, given a target word and a set of candidate words, to find the subset of the candidates that are anagrams of the target.
|
||||
|
||||
An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`.
|
||||
A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`.
|
||||
|
||||
The target and candidates are words of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`).
|
||||
Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `StoP` is not an anagram of `sTOp`.
|
||||
The anagram set is the subset of the candidate set that are anagrams of the target (in any order).
|
||||
Words in the anagram set should have the same letter case as in the candidate set.
|
||||
|
||||
Given the target `"stone"` and candidates `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, `"Seton"`, the anagram set is `"tones"`, `"notes"`, `"Seton"`.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @rubysolo
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @andrewsardone
|
||||
- @angelikatyborska
|
||||
- @Br1ght0ne
|
||||
- @Cohen-Carlisle
|
||||
- @crazymykl
|
||||
- @dalexj
|
||||
- @devonestes
|
||||
- @henrik
|
||||
- @jeremy-w
|
||||
- @jinyeow
|
||||
- @kytrinyx
|
||||
- @lpil
|
||||
- @markijbema
|
||||
- @neenjaw
|
||||
- @parkerl
|
||||
- @pminten
|
||||
- @sotojuan
|
||||
- @Teapane
|
||||
- @tjcelaya
|
||||
- @waiting-for-dev
|
||||
|
||||
### Based on
|
||||
|
||||
Inspired by the Extreme Startup game - https://github.com/rchatley/extreme_startup
|
||||
21
elixir/anagram/lib/anagram.ex
Normal file
21
elixir/anagram/lib/anagram.ex
Normal file
@@ -0,0 +1,21 @@
|
||||
defmodule Anagram do
|
||||
@doc """
|
||||
Returns all candidates that are anagrams of, but not equal to, 'base'.
|
||||
"""
|
||||
@spec match(String.t(), [String.t()]) :: [String.t()]
|
||||
def match(base, candidates) do
|
||||
candidates
|
||||
|> Enum.filter(&anagram?(normalize(base), normalize(&1)))
|
||||
end
|
||||
|
||||
defp anagram?(base, base), do: false
|
||||
defp anagram?(base, candidate), do: hash(base) == hash(candidate)
|
||||
|
||||
@spec normalize(String.t()) :: String.t()
|
||||
defp normalize(string), do: string |> String.downcase() |> String.graphemes()
|
||||
|
||||
@spec hash(String.t()) :: Map.t()
|
||||
defp hash(string) do
|
||||
Enum.reduce(string, %{}, fn char, acc -> Map.update(acc, char, 1, &(&1 + 1)) end)
|
||||
end
|
||||
end
|
||||
28
elixir/anagram/mix.exs
Normal file
28
elixir/anagram/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule Anagram.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :anagram,
|
||||
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
|
||||
100
elixir/anagram/test/anagram_test.exs
Normal file
100
elixir/anagram/test/anagram_test.exs
Normal file
@@ -0,0 +1,100 @@
|
||||
defmodule AnagramTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test "no matches" do
|
||||
matches = Anagram.match("diaper", ~w(hello world zombies pants))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "detects two anagrams" do
|
||||
matches = Anagram.match("solemn", ~w(lemons cherry melons))
|
||||
assert matches == ~w(lemons melons)
|
||||
end
|
||||
|
||||
test "does not detect anagram subsets" do
|
||||
matches = Anagram.match("good", ~w(dog goody))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "detects anagram" do
|
||||
matches = Anagram.match("listen", ~w(enlists google inlets banana))
|
||||
assert matches == ~w(inlets)
|
||||
end
|
||||
|
||||
test "detects three anagrams" do
|
||||
matches = Anagram.match("allergy", ~w(gallery ballerina regally clergy largely leading))
|
||||
assert matches == ~w(gallery regally largely)
|
||||
end
|
||||
|
||||
test "detects multiple anagrams with different case" do
|
||||
matches = Anagram.match("nose", ~w(Eons ONES))
|
||||
assert matches == ~w(Eons ONES)
|
||||
end
|
||||
|
||||
test "does not detect non-anagrams with identical checksum" do
|
||||
matches = Anagram.match("mass", ~w(last))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "detect anagrams case-insensitively" do
|
||||
matches = Anagram.match("orchestra", ~w(cashregister Carthorse radishes))
|
||||
assert matches == ~w(Carthorse)
|
||||
end
|
||||
|
||||
test "detects anagrams using case-insensitive subject" do
|
||||
matches = Anagram.match("Orchestra", ~w(cashregister carthorse radishes))
|
||||
assert matches == ~w(carthorse)
|
||||
end
|
||||
|
||||
test "detects anagrams using case-insensitive possible matches" do
|
||||
matches = Anagram.match("orchestra", ~w(cashregister Carthorse radishes))
|
||||
assert matches == ~w(Carthorse)
|
||||
end
|
||||
|
||||
test "does not detect an anagram if the original word is repeated" do
|
||||
matches = Anagram.match("go", ~w(goGoGO))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "anagrams must use all letters exactly once" do
|
||||
matches = Anagram.match("tapper", ~w(patter))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "words are not anagrams of themselves" do
|
||||
matches = Anagram.match("BANANA", ~w(BANANA))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "words are not anagrams of themselves even if letter case is partially different" do
|
||||
matches = Anagram.match("BANANA", ~w(Banana))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "words are not anagrams of themselves even if letter case is completely different" do
|
||||
matches = Anagram.match("BANANA", ~w(banana))
|
||||
assert matches == []
|
||||
end
|
||||
|
||||
test "words other than themselves can be anagrams" do
|
||||
matches = Anagram.match("LISTEN", ~w(Silent LISTEN))
|
||||
assert matches == ~w(Silent)
|
||||
end
|
||||
|
||||
test "handles case of greek letters" do
|
||||
matches = Anagram.match("ΑΒΓ", ~w(ΒΓΑ ΒΓΔ γβα αβγ))
|
||||
assert matches == ~w(ΒΓΑ γβα)
|
||||
end
|
||||
|
||||
test "different characters may have the same bytes" do
|
||||
matches =
|
||||
Anagram.match(
|
||||
# binary representation: <<0x61, 0xE2, 0xAC, 0x82>>
|
||||
"a⬂",
|
||||
# binary representation: <<0xE2, 0x82, 0xAC, 0x61>>
|
||||
["€a"]
|
||||
)
|
||||
|
||||
assert matches == []
|
||||
end
|
||||
end
|
||||
2
elixir/anagram/test/test_helper.exs
Normal file
2
elixir/anagram/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
27
elixir/armstrong-numbers/.exercism/config.json
Normal file
27
elixir/armstrong-numbers/.exercism/config.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"authors": [
|
||||
"Bscruz19"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"Br1ght0ne",
|
||||
"Cohen-Carlisle",
|
||||
"devonestes",
|
||||
"neenjaw",
|
||||
"tsuka"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/armstrong_number.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/armstrong_number_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Determine if a number is an Armstrong number.",
|
||||
"source": "Wikipedia",
|
||||
"source_url": "https://en.wikipedia.org/wiki/Narcissistic_number"
|
||||
}
|
||||
1
elixir/armstrong-numbers/.exercism/metadata.json
Normal file
1
elixir/armstrong-numbers/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"armstrong-numbers","id":"87b5aa5429664271a572c9f3ac0722d1","url":"https://exercism.org/tracks/elixir/exercises/armstrong-numbers","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/armstrong-numbers/.formatter.exs
Normal file
4
elixir/armstrong-numbers/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/armstrong-numbers/.gitignore
vendored
Normal file
24
elixir/armstrong-numbers/.gitignore
vendored
Normal 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").
|
||||
armstrong_numbers-*.tar
|
||||
|
||||
75
elixir/armstrong-numbers/HELP.md
Normal file
75
elixir/armstrong-numbers/HELP.md
Normal 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/armstrong_number.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.
|
||||
38
elixir/armstrong-numbers/README.md
Normal file
38
elixir/armstrong-numbers/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Armstrong Numbers
|
||||
|
||||
Welcome to Armstrong Numbers on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
An [Armstrong number][armstrong-number] is a number that is the sum of its own digits each raised to the power of the number of digits.
|
||||
|
||||
For example:
|
||||
|
||||
- 9 is an Armstrong number, because `9 = 9^1 = 9`
|
||||
- 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1`
|
||||
- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153`
|
||||
- 154 is _not_ an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190`
|
||||
|
||||
Write some code to determine whether a number is an Armstrong number.
|
||||
|
||||
[armstrong-number]: https://en.wikipedia.org/wiki/Narcissistic_number
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @Bscruz19
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @Br1ght0ne
|
||||
- @Cohen-Carlisle
|
||||
- @devonestes
|
||||
- @neenjaw
|
||||
- @tsuka
|
||||
|
||||
### Based on
|
||||
|
||||
Wikipedia - https://en.wikipedia.org/wiki/Narcissistic_number
|
||||
13
elixir/armstrong-numbers/lib/armstrong_number.ex
Normal file
13
elixir/armstrong-numbers/lib/armstrong_number.ex
Normal file
@@ -0,0 +1,13 @@
|
||||
defmodule ArmstrongNumber do
|
||||
@moduledoc """
|
||||
Provides a way to validate whether or not a number is an Armstrong number
|
||||
"""
|
||||
|
||||
@spec valid?(integer) :: boolean
|
||||
def valid?(number) do
|
||||
digits = Integer.digits(number)
|
||||
power = length(digits)
|
||||
|
||||
Enum.reduce(digits, 0, &(&1 ** power + &2)) == number
|
||||
end
|
||||
end
|
||||
28
elixir/armstrong-numbers/mix.exs
Normal file
28
elixir/armstrong-numbers/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule ArmstrongNumber.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :armstrong_number,
|
||||
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
|
||||
47
elixir/armstrong-numbers/test/armstrong_number_test.exs
Normal file
47
elixir/armstrong-numbers/test/armstrong_number_test.exs
Normal file
@@ -0,0 +1,47 @@
|
||||
defmodule ArmstrongNumberTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test "Zero is an Armstrong number" do
|
||||
assert ArmstrongNumber.valid?(0)
|
||||
end
|
||||
|
||||
test "Single digit numbers are Armstrong numbers" do
|
||||
assert ArmstrongNumber.valid?(5)
|
||||
end
|
||||
|
||||
test "There are no two-digit Armstrong Numbers" do
|
||||
refute ArmstrongNumber.valid?(10)
|
||||
end
|
||||
|
||||
test "Three-digit number that is an Armstrong number" do
|
||||
assert ArmstrongNumber.valid?(153)
|
||||
end
|
||||
|
||||
test "Three-digit number that is not an Armstrong number" do
|
||||
refute ArmstrongNumber.valid?(100)
|
||||
end
|
||||
|
||||
test "Four-digit number that is an Armstrong number" do
|
||||
assert ArmstrongNumber.valid?(9474)
|
||||
end
|
||||
|
||||
test "Four-digit number that is not an Armstrong number" do
|
||||
refute ArmstrongNumber.valid?(9475)
|
||||
end
|
||||
|
||||
test "Seven-digit number that is an Armstrong number" do
|
||||
assert ArmstrongNumber.valid?(9_926_315)
|
||||
end
|
||||
|
||||
test "Seven-digit number that is not an Armstrong number" do
|
||||
refute ArmstrongNumber.valid?(9_926_134)
|
||||
end
|
||||
|
||||
test "Armstrong number containing seven zeroes" do
|
||||
assert ArmstrongNumber.valid?(186_709_961_001_538_790_100_634_132_976_990)
|
||||
end
|
||||
|
||||
test "The largest and last Armstrong number" do
|
||||
assert ArmstrongNumber.valid?(115_132_219_018_763_992_565_095_597_973_971_522_401)
|
||||
end
|
||||
end
|
||||
2
elixir/armstrong-numbers/test/test_helper.exs
Normal file
2
elixir/armstrong-numbers/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
36
elixir/atbash-cipher/.exercism/config.json
Normal file
36
elixir/atbash-cipher/.exercism/config.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"authors": [
|
||||
"rubysolo"
|
||||
],
|
||||
"contributors": [
|
||||
"andrewsardone",
|
||||
"angelikatyborska",
|
||||
"Br1ght0ne",
|
||||
"Cohen-Carlisle",
|
||||
"dalexj",
|
||||
"devonestes",
|
||||
"jinyeow",
|
||||
"kytrinyx",
|
||||
"lpil",
|
||||
"mhinz",
|
||||
"neenjaw",
|
||||
"parkerl",
|
||||
"sotojuan",
|
||||
"Teapane",
|
||||
"waiting-for-dev"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/atbash.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/atbash_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.",
|
||||
"source": "Wikipedia",
|
||||
"source_url": "https://en.wikipedia.org/wiki/Atbash"
|
||||
}
|
||||
1
elixir/atbash-cipher/.exercism/metadata.json
Normal file
1
elixir/atbash-cipher/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"atbash-cipher","id":"156913b0379c4b8886dff7de48ab370e","url":"https://exercism.org/tracks/elixir/exercises/atbash-cipher","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/atbash-cipher/.formatter.exs
Normal file
4
elixir/atbash-cipher/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/atbash-cipher/.gitignore
vendored
Normal file
24
elixir/atbash-cipher/.gitignore
vendored
Normal 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").
|
||||
atbash_cipher-*.tar
|
||||
|
||||
75
elixir/atbash-cipher/HELP.md
Normal file
75
elixir/atbash-cipher/HELP.md
Normal 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/atbash.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.
|
||||
60
elixir/atbash-cipher/README.md
Normal file
60
elixir/atbash-cipher/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Atbash Cipher
|
||||
|
||||
Welcome to Atbash Cipher on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.
|
||||
|
||||
The Atbash cipher is a simple substitution cipher that relies on transposing all the letters in the alphabet such that the resulting alphabet is backwards.
|
||||
The first letter is replaced with the last letter, the second with the second-last, and so on.
|
||||
|
||||
An Atbash cipher for the Latin alphabet would be as follows:
|
||||
|
||||
```text
|
||||
Plain: abcdefghijklmnopqrstuvwxyz
|
||||
Cipher: zyxwvutsrqponmlkjihgfedcba
|
||||
```
|
||||
|
||||
It is a very weak cipher because it only has one possible key, and it is a simple mono-alphabetic substitution cipher.
|
||||
However, this may not have been an issue in the cipher's time.
|
||||
|
||||
Ciphertext is written out in groups of fixed length, the traditional group size being 5 letters, leaving numbers unchanged, and punctuation is excluded.
|
||||
This is to make it harder to guess things based on word boundaries.
|
||||
All text will be encoded as lowercase letters.
|
||||
|
||||
## Examples
|
||||
|
||||
- Encoding `test` gives `gvhg`
|
||||
- Encoding `x123 yes` gives `c123b vh`
|
||||
- Decoding `gvhg` gives `test`
|
||||
- Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog`
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @rubysolo
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @andrewsardone
|
||||
- @angelikatyborska
|
||||
- @Br1ght0ne
|
||||
- @Cohen-Carlisle
|
||||
- @dalexj
|
||||
- @devonestes
|
||||
- @jinyeow
|
||||
- @kytrinyx
|
||||
- @lpil
|
||||
- @mhinz
|
||||
- @neenjaw
|
||||
- @parkerl
|
||||
- @sotojuan
|
||||
- @Teapane
|
||||
- @waiting-for-dev
|
||||
|
||||
### Based on
|
||||
|
||||
Wikipedia - https://en.wikipedia.org/wiki/Atbash
|
||||
48
elixir/atbash-cipher/lib/atbash.ex
Normal file
48
elixir/atbash-cipher/lib/atbash.ex
Normal file
@@ -0,0 +1,48 @@
|
||||
defmodule Atbash do
|
||||
@letters ?a..?z
|
||||
|> Enum.to_list
|
||||
|> to_string
|
||||
|> String.graphemes()
|
||||
|
||||
@digits ?0..?9
|
||||
|> Enum.to_list
|
||||
|> to_string
|
||||
|> String.graphemes()
|
||||
|
||||
@table Map.new(Enum.zip(@letters, Enum.reverse(@letters)))
|
||||
|
||||
defguardp is_letter(char) when char in @letters
|
||||
defguardp is_digit(char) when char in @digits
|
||||
|
||||
@doc """
|
||||
Encode a given plaintext to the corresponding ciphertext
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Atbash.encode("completely insecure")
|
||||
"xlnko vgvob rmhvx fiv"
|
||||
"""
|
||||
@spec encode(String.t()) :: String.t()
|
||||
def encode(plaintext) do
|
||||
plaintext
|
||||
|> transpose()
|
||||
|> String.graphemes()
|
||||
|> Enum.chunk_every(5)
|
||||
|> Enum.join(" ")
|
||||
end
|
||||
|
||||
@spec decode(String.t()) :: String.t()
|
||||
def decode(cipher), do: transpose(cipher)
|
||||
|
||||
defp transpose(string) do
|
||||
string
|
||||
|> String.downcase()
|
||||
|> String.graphemes()
|
||||
|> Enum.map(&code/1)
|
||||
|> Enum.join()
|
||||
end
|
||||
|
||||
defp code(char) when is_digit(char), do: char
|
||||
defp code(char) when is_letter(char), do: @table[char]
|
||||
defp code(_char), do: nil
|
||||
end
|
||||
28
elixir/atbash-cipher/mix.exs
Normal file
28
elixir/atbash-cipher/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule Atbash.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :atbash,
|
||||
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
|
||||
77
elixir/atbash-cipher/test/atbash_test.exs
Normal file
77
elixir/atbash-cipher/test/atbash_test.exs
Normal file
@@ -0,0 +1,77 @@
|
||||
defmodule AtbashTest do
|
||||
use ExUnit.Case
|
||||
|
||||
describe "encode" do
|
||||
test "yes" do
|
||||
assert Atbash.encode("yes") == "bvh"
|
||||
end
|
||||
|
||||
test "no" do
|
||||
assert Atbash.encode("no") == "ml"
|
||||
end
|
||||
|
||||
test "OMG" do
|
||||
assert Atbash.encode("OMG") == "lnt"
|
||||
end
|
||||
|
||||
test "O M G" do
|
||||
assert Atbash.encode("O M G") == "lnt"
|
||||
end
|
||||
|
||||
test "mindblowingly" do
|
||||
assert Atbash.encode("mindblowingly") == "nrmwy oldrm tob"
|
||||
end
|
||||
|
||||
test "numbers" do
|
||||
assert Atbash.encode("Testing, 1 2 3, testing.") == "gvhgr mt123 gvhgr mt"
|
||||
end
|
||||
|
||||
test "deep thought" do
|
||||
assert Atbash.encode("Truth is fiction.") == "gifgs rhurx grlm"
|
||||
end
|
||||
|
||||
test "all the letters" do
|
||||
plaintext = "The quick brown fox jumps over the lazy dog."
|
||||
cipher = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
|
||||
assert Atbash.encode(plaintext) == cipher
|
||||
end
|
||||
end
|
||||
|
||||
describe "decode" do
|
||||
test "exercism" do
|
||||
cipher = "vcvix rhn"
|
||||
plaintext = "exercism"
|
||||
assert Atbash.decode(cipher) == plaintext
|
||||
end
|
||||
|
||||
test "a sentence" do
|
||||
cipher = "zmlyh gzxov rhlug vmzhg vkkrm thglm v"
|
||||
plaintext = "anobstacleisoftenasteppingstone"
|
||||
assert Atbash.decode(cipher) == plaintext
|
||||
end
|
||||
|
||||
test "numbers" do
|
||||
cipher = "gvhgr mt123 gvhgr mt"
|
||||
plaintext = "testing123testing"
|
||||
assert Atbash.decode(cipher) == plaintext
|
||||
end
|
||||
|
||||
test "all the letters" do
|
||||
cipher = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
|
||||
plaintext = "thequickbrownfoxjumpsoverthelazydog"
|
||||
assert Atbash.decode(cipher) == plaintext
|
||||
end
|
||||
|
||||
test "with too many spaces" do
|
||||
cipher = "vc vix r hn"
|
||||
plaintext = "exercism"
|
||||
assert Atbash.decode(cipher) == plaintext
|
||||
end
|
||||
|
||||
test "with no spaces" do
|
||||
cipher = "zmlyhgzxovrhlugvmzhgvkkrmthglmv"
|
||||
plaintext = "anobstacleisoftenasteppingstone"
|
||||
assert Atbash.decode(cipher) == plaintext
|
||||
end
|
||||
end
|
||||
end
|
||||
2
elixir/atbash-cipher/test/test_helper.exs
Normal file
2
elixir/atbash-cipher/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
22
elixir/basketball-website/.exercism/config.json
Normal file
22
elixir/basketball-website/.exercism/config.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"authors": [
|
||||
"neenjaw"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"NobbZ"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/basketball_website.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/basketball_website_test.exs"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.ex"
|
||||
]
|
||||
},
|
||||
"language_versions": ">=1.10",
|
||||
"blurb": "Learn about Access Behaviour by helping extract deeply nested data for the basketball team's website."
|
||||
}
|
||||
1
elixir/basketball-website/.exercism/metadata.json
Normal file
1
elixir/basketball-website/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"basketball-website","id":"740e1842211445898b26c211cbf40f0c","url":"https://exercism.org/tracks/elixir/exercises/basketball-website","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/basketball-website/.formatter.exs
Normal file
4
elixir/basketball-website/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/basketball-website/.gitignore
vendored
Normal file
24
elixir/basketball-website/.gitignore
vendored
Normal 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").
|
||||
access-*.tar
|
||||
|
||||
75
elixir/basketball-website/HELP.md
Normal file
75
elixir/basketball-website/HELP.md
Normal 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/basketball_website.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.
|
||||
18
elixir/basketball-website/HINTS.md
Normal file
18
elixir/basketball-website/HINTS.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- Read about the [`Access` behaviour][access-behaviour] in the documentation.
|
||||
|
||||
## 1. Extract data from a nested map structure
|
||||
|
||||
- First tokenize the string path to a usable state. You can make use of [`String` module functions][string-module].
|
||||
- Write a recursive function to traverse the nested-map structure to retrieve the value or return `nil`.
|
||||
|
||||
## 2. Refactor using included functions
|
||||
|
||||
- Read through the various [`Kernel` module functions][kernel-module], to find one that might shorten/simplify your approach.
|
||||
|
||||
[kernel-module]: https://hexdocs.pm/elixir/Kernel.html#functions
|
||||
[string-module]: https://hexdocs.pm/elixir/String.html#functions
|
||||
[access-behaviour]: https://hexdocs.pm/elixir/Access.html
|
||||
82
elixir/basketball-website/README.md
Normal file
82
elixir/basketball-website/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Basketball Website
|
||||
|
||||
Welcome to Basketball Website 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
|
||||
|
||||
## Access Behaviour
|
||||
|
||||
Elixir uses code _Behaviours_ to provide common generic interfaces while facilitating specific implementations for each module which implements it. One such common example is the _Access Behaviour_.
|
||||
|
||||
The _Access Behaviour_ provides a common interface for retrieving data from a key-based data structure. The _Access Behaviour_ is implemented for maps and keyword lists, but let's look at its use for maps to get a feel for it. _Access Behaviour_ specifies that when you have a map, you may follow it with _square brackets_ and then use the key to retrieve the value associated with that key.
|
||||
|
||||
```elixir
|
||||
# Suppose we have these two maps defined (note the difference in the key type)
|
||||
my_map = %{key: "my value"}
|
||||
your_map = %{"key" => "your value"}
|
||||
|
||||
# Obtain the value using the Access Behaviour
|
||||
my_map[:key] == "my value"
|
||||
your_map[:key] == nil
|
||||
your_map["key"] == "your value"
|
||||
```
|
||||
|
||||
If the key does not exist in the data structure, then `nil` is returned. This can be a source of unintended behavior, because it does not raise an error. Note that `nil` itself implements the Access Behaviour and always returns `nil` for any key.
|
||||
|
||||
## Instructions
|
||||
|
||||
You are working with a web development team to maintain a website for a local basketball team. The web development team is less familiar with Elixir and is asking for a function to be able to extract data from a series of nested maps to facilitate rapid development.
|
||||
|
||||
## 1. Extract data from a nested map structure
|
||||
|
||||
Implement the `extract_from_path/2` function to take two arguments:
|
||||
|
||||
- `data`: a nested map structure with data about the basketball team.
|
||||
- `path`: a string consisting of period-delimited keys to obtain the value associated with the last key.
|
||||
|
||||
If the value or the key does not exist at any point in the path, `nil` should be returned
|
||||
|
||||
```elixir
|
||||
data = %{
|
||||
"team_mascot" => %{
|
||||
"animal" => "bear",
|
||||
"actor" => %{
|
||||
"first_name" => "Noel"
|
||||
}
|
||||
}
|
||||
}
|
||||
BasketballWebsite.extract_from_path(data, "team_mascot.animal")
|
||||
# => "bear"
|
||||
BasketballWebsite.extract_from_path(data, "team_mascot.colors")
|
||||
# => nil
|
||||
```
|
||||
|
||||
Use the _Access Behaviour_ when implementing this function.
|
||||
|
||||
Do not use any `Map` or `Kernel` module functions for working with the nested map data structure.
|
||||
|
||||
## 2. Refactor using included functions
|
||||
|
||||
Your coworker reviewing your code tells you about a `Kernel` module function which does something very similar to your implementation.
|
||||
|
||||
Implement `get_in_path/2` to use this `Kernel` module function.
|
||||
|
||||
The arguments expected are the same as part 1.
|
||||
|
||||
```elixir
|
||||
BasketballWebsite.get_in_path(data, "team_mascot.actor.first_name")
|
||||
# => "Noel"
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @neenjaw
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @NobbZ
|
||||
15
elixir/basketball-website/lib/basketball_website.ex
Normal file
15
elixir/basketball-website/lib/basketball_website.ex
Normal file
@@ -0,0 +1,15 @@
|
||||
defmodule BasketballWebsite do
|
||||
def extract_from_path(data, path) do
|
||||
path
|
||||
|> String.split(".")
|
||||
|> get_path(data)
|
||||
end
|
||||
|
||||
defp get_path(_list, nil), do: nil
|
||||
defp get_path([], data), do: data
|
||||
defp get_path([head | tail], data), do: get_path(tail, data[head])
|
||||
|
||||
def get_in_path(data, path) do
|
||||
get_in(data, String.split(path, "."))
|
||||
end
|
||||
end
|
||||
28
elixir/basketball-website/mix.exs
Normal file
28
elixir/basketball-website/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule BasketballWebsite.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :basketball_website,
|
||||
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
|
||||
335
elixir/basketball-website/test/basketball_website_test.exs
Normal file
335
elixir/basketball-website/test/basketball_website_test.exs
Normal file
@@ -0,0 +1,335 @@
|
||||
defmodule BasketballWebsiteTest do
|
||||
use ExUnit.Case
|
||||
|
||||
describe "extract_from_path retrieves from" do
|
||||
@tag task_id: 1
|
||||
test "first layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(team_data, "team_name") == "Hoop Masters"
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "second layer" do
|
||||
team_data = %{
|
||||
"coach" => %{
|
||||
"first_name" => "Jane",
|
||||
"last_name" => "Brown"
|
||||
},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(team_data, "coach.first_name") == "Jane"
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "third layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"99" => %{
|
||||
"first_name" => "Amalee",
|
||||
"last_name" => "Tynemouth",
|
||||
"email" => "atynemouth0@yellowpages.com",
|
||||
"statistics" => %{}
|
||||
},
|
||||
"98" => %{
|
||||
"first_name" => "Tiffie",
|
||||
"last_name" => "Derle",
|
||||
"email" => "tderle1@vimeo.com",
|
||||
"statistics" => %{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(team_data, "players.99.first_name") == "Amalee"
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "fourth layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"42" => %{
|
||||
"first_name" => "Conchita",
|
||||
"last_name" => "Elham",
|
||||
"email" => "celham4@wikia.com",
|
||||
"statistics" => %{
|
||||
"average_points_per_game" => 4.6,
|
||||
"free_throws_made" => 7,
|
||||
"free_throws_attempted" => 10
|
||||
}
|
||||
},
|
||||
"61" => %{
|
||||
"first_name" => "Noel",
|
||||
"last_name" => "Fawlkes",
|
||||
"email" => "nfawlkes5@yahoo.co.jp",
|
||||
"statistics" => %{
|
||||
"average_points_per_game" => 5.0,
|
||||
"free_throws_made" => 5,
|
||||
"free_throws_attempted" => 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(
|
||||
team_data,
|
||||
"players.61.statistics.average_points_per_game"
|
||||
) === 5.0
|
||||
end
|
||||
end
|
||||
|
||||
describe "extract_from_path returns nil from nonexistent last key in" do
|
||||
@tag task_id: 1
|
||||
test "first layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(team_data, "team_song") == nil
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "second layer" do
|
||||
team_data = %{
|
||||
"coach" => %{
|
||||
"first_name" => "Jane",
|
||||
"last_name" => "Brown"
|
||||
},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(team_data, "coach.age") == nil
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "third layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"32" => %{
|
||||
"first_name" => "Deni",
|
||||
"last_name" => "Lidster",
|
||||
"email" => nil,
|
||||
"statistics" => %{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(team_data, "players.32.height") == nil
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "fourth layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"12" => %{
|
||||
"first_name" => "Andy",
|
||||
"last_name" => "Napoli",
|
||||
"email" => "anapoli7@goodreads.com",
|
||||
"statistics" => %{
|
||||
"average_points_per_game" => 7
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(
|
||||
team_data,
|
||||
"players.12.statistics.personal_fouls"
|
||||
) == nil
|
||||
end
|
||||
end
|
||||
|
||||
@tag task_id: 1
|
||||
test "extract_from_path returns nil from nonexistent path" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.extract_from_path(
|
||||
team_data,
|
||||
"support_personnel.physiotherapy.first_name"
|
||||
) == nil
|
||||
end
|
||||
|
||||
describe "get_in_path retrieves from" do
|
||||
@tag task_id: 2
|
||||
test "first layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "team_name") == "Hoop Masters"
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "second layer" do
|
||||
team_data = %{
|
||||
"coach" => %{
|
||||
"first_name" => "Jane",
|
||||
"last_name" => "Brown"
|
||||
},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "coach.first_name") == "Jane"
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "third layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"99" => %{
|
||||
"first_name" => "Amalee",
|
||||
"last_name" => "Tynemouth",
|
||||
"email" => "atynemouth0@yellowpages.com",
|
||||
"statistics" => %{}
|
||||
},
|
||||
"98" => %{
|
||||
"first_name" => "Tiffie",
|
||||
"last_name" => "Derle",
|
||||
"email" => "tderle1@vimeo.com",
|
||||
"statistics" => %{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "players.99.first_name") == "Amalee"
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "fourth layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"42" => %{
|
||||
"first_name" => "Conchita",
|
||||
"last_name" => "Elham",
|
||||
"email" => "celham4@wikia.com",
|
||||
"statistics" => %{
|
||||
"average_points_per_game" => 4.6,
|
||||
"free_throws_made" => 7,
|
||||
"free_throws_attempted" => 10
|
||||
}
|
||||
},
|
||||
"61" => %{
|
||||
"first_name" => "Noel",
|
||||
"last_name" => "Fawlkes",
|
||||
"email" => "nfawlkes5@yahoo.co.jp",
|
||||
"statistics" => %{
|
||||
"average_points_per_game" => 5.0,
|
||||
"free_throws_made" => 5,
|
||||
"free_throws_attempted" => 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(
|
||||
team_data,
|
||||
"players.61.statistics.average_points_per_game"
|
||||
) === 5.0
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_in_path returns nil from nonexistent last key in" do
|
||||
@tag task_id: 2
|
||||
test "first layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "team_song") == nil
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "second layer" do
|
||||
team_data = %{
|
||||
"coach" => %{
|
||||
"first_name" => "Jane",
|
||||
"last_name" => "Brown"
|
||||
},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "coach.age") == nil
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "third layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"32" => %{
|
||||
"first_name" => "Deni",
|
||||
"last_name" => "Lidster",
|
||||
"email" => nil,
|
||||
"statistics" => %{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "players.32.height") == nil
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "fourth layer" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{
|
||||
"12" => %{
|
||||
"first_name" => "Andy",
|
||||
"last_name" => "Napoli",
|
||||
"email" => "anapoli7@goodreads.com",
|
||||
"statistics" => %{
|
||||
"average_points_per_game" => 7
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "players.12.statistics.personal_fouls") ==
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@tag task_id: 2
|
||||
test "get_in_path returns nil from nonexistent path" do
|
||||
team_data = %{
|
||||
"coach" => %{},
|
||||
"team_name" => "Hoop Masters",
|
||||
"players" => %{}
|
||||
}
|
||||
|
||||
assert BasketballWebsite.get_in_path(team_data, "support_personnel.physiotherapy.first_name") ==
|
||||
nil
|
||||
end
|
||||
end
|
||||
2
elixir/basketball-website/test/test_helper.exs
Normal file
2
elixir/basketball-website/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true, seed: 0)
|
||||
25
elixir/binary-search-tree/.exercism/config.json
Normal file
25
elixir/binary-search-tree/.exercism/config.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"authors": [
|
||||
"sngeth"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"Cohen-Carlisle",
|
||||
"devonestes",
|
||||
"neenjaw",
|
||||
"sotojuan"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/binary_search_tree.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/binary_search_tree_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Insert and search for numbers in a binary tree.",
|
||||
"source": "Josh Cheek"
|
||||
}
|
||||
1
elixir/binary-search-tree/.exercism/metadata.json
Normal file
1
elixir/binary-search-tree/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"binary-search-tree","id":"fc6ed3ee9f82408eb78d0f9df5e506bf","url":"https://exercism.org/tracks/elixir/exercises/binary-search-tree","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/binary-search-tree/.formatter.exs
Normal file
4
elixir/binary-search-tree/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/binary-search-tree/.gitignore
vendored
Normal file
24
elixir/binary-search-tree/.gitignore
vendored
Normal 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").
|
||||
binary_search_tree-*.tar
|
||||
|
||||
75
elixir/binary-search-tree/HELP.md
Normal file
75
elixir/binary-search-tree/HELP.md
Normal 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/binary_search_tree.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.
|
||||
70
elixir/binary-search-tree/README.md
Normal file
70
elixir/binary-search-tree/README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Binary Search Tree
|
||||
|
||||
Welcome to Binary Search Tree on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Insert and search for numbers in a binary tree.
|
||||
|
||||
When we need to represent sorted data, an array does not make a good data structure.
|
||||
|
||||
Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes `[1, 3, 4, 5, 2]`.
|
||||
Now we must sort the entire array again!
|
||||
We can improve on this by realizing that we only need to make space for the new item `[1, nil, 3, 4, 5]`, and then adding the item in the space we added.
|
||||
But this still requires us to shift many elements down by one.
|
||||
|
||||
Binary Search Trees, however, can operate on sorted data much more efficiently.
|
||||
|
||||
A binary search tree consists of a series of connected nodes.
|
||||
Each node contains a piece of data (e.g. the number 3), a variable named `left`, and a variable named `right`.
|
||||
The `left` and `right` variables point at `nil`, or other nodes.
|
||||
Since these other nodes in turn have other nodes beneath them, we say that the left and right variables are pointing at subtrees.
|
||||
All data in the left subtree is less than or equal to the current node's data, and all data in the right subtree is greater than the current node's data.
|
||||
|
||||
For example, if we had a node containing the data 4, and we added the data 2, our tree would look like this:
|
||||
|
||||
4
|
||||
/
|
||||
2
|
||||
|
||||
If we then added 6, it would look like this:
|
||||
|
||||
4
|
||||
/ \
|
||||
2 6
|
||||
|
||||
If we then added 3, it would look like this
|
||||
|
||||
4
|
||||
/ \
|
||||
2 6
|
||||
\
|
||||
3
|
||||
|
||||
And if we then added 1, 5, and 7, it would look like this
|
||||
|
||||
4
|
||||
/ \
|
||||
/ \
|
||||
2 6
|
||||
/ \ / \
|
||||
1 3 5 7
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @sngeth
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @Cohen-Carlisle
|
||||
- @devonestes
|
||||
- @neenjaw
|
||||
- @sotojuan
|
||||
|
||||
### Based on
|
||||
|
||||
Josh Cheek
|
||||
26
elixir/binary-search-tree/lib/binary_search_tree.ex
Normal file
26
elixir/binary-search-tree/lib/binary_search_tree.ex
Normal file
@@ -0,0 +1,26 @@
|
||||
defmodule BinarySearchTree do
|
||||
@type bst_node :: %{data: any, left: bst_node | nil, right: bst_node | nil}
|
||||
|
||||
@doc """
|
||||
Create a new Binary Search Tree with root's value as the given 'data'
|
||||
"""
|
||||
@spec new(any) :: bst_node
|
||||
def new(data), do: %{data: data, left: nil, right: nil}
|
||||
|
||||
@doc """
|
||||
Creates and inserts a node with its value as 'data' into the tree.
|
||||
"""
|
||||
@spec insert(bst_node, any) :: bst_node
|
||||
def insert(nil, data), do: new(data)
|
||||
def insert(tree, data) when data <= tree.data, do:
|
||||
%{tree | left: insert(tree.left, data)}
|
||||
def insert(tree, data), do:
|
||||
%{tree | right: insert(tree.right, data)}
|
||||
|
||||
@doc """
|
||||
Traverses the Binary Search Tree in order and returns a list of each node's data.
|
||||
"""
|
||||
@spec in_order(bst_node) :: [any]
|
||||
def in_order(nil), do: []
|
||||
def in_order(tree), do: in_order(tree.left) ++ [tree.data | in_order(tree.right)]
|
||||
end
|
||||
28
elixir/binary-search-tree/mix.exs
Normal file
28
elixir/binary-search-tree/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule BinarySearchTree.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :binary_search_tree,
|
||||
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
|
||||
119
elixir/binary-search-tree/test/binary_search_tree_test.exs
Normal file
119
elixir/binary-search-tree/test/binary_search_tree_test.exs
Normal file
@@ -0,0 +1,119 @@
|
||||
defmodule BinarySearchTreeTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test "data is retained" do
|
||||
root = BinarySearchTree.new(4)
|
||||
assert root.data == 4
|
||||
assert root.left == nil
|
||||
assert root.right == nil
|
||||
end
|
||||
|
||||
describe "insert data at proper node" do
|
||||
test "smaller number at left node" do
|
||||
root =
|
||||
BinarySearchTree.new(4)
|
||||
|> BinarySearchTree.insert(2)
|
||||
|
||||
assert root.data == 4
|
||||
assert root.left.data == 2
|
||||
assert root.left.left == nil
|
||||
assert root.left.right == nil
|
||||
assert root.right == nil
|
||||
end
|
||||
|
||||
test "same number at left node" do
|
||||
root =
|
||||
BinarySearchTree.new(4)
|
||||
|> BinarySearchTree.insert(4)
|
||||
|
||||
assert root.data == 4
|
||||
assert root.left.data == 4
|
||||
assert root.left.left == nil
|
||||
assert root.left.right == nil
|
||||
assert root.right == nil
|
||||
end
|
||||
|
||||
test "greater number at right node" do
|
||||
root =
|
||||
BinarySearchTree.new(4)
|
||||
|> BinarySearchTree.insert(5)
|
||||
|
||||
assert root.data == 4
|
||||
assert root.left == nil
|
||||
assert root.right.data == 5
|
||||
assert root.right.left == nil
|
||||
assert root.right.right == nil
|
||||
end
|
||||
end
|
||||
|
||||
test "can create complex tree" do
|
||||
root =
|
||||
BinarySearchTree.new(4)
|
||||
|> BinarySearchTree.insert(2)
|
||||
|> BinarySearchTree.insert(6)
|
||||
|> BinarySearchTree.insert(1)
|
||||
|> BinarySearchTree.insert(3)
|
||||
|> BinarySearchTree.insert(5)
|
||||
|> BinarySearchTree.insert(7)
|
||||
|
||||
assert root.data == 4
|
||||
assert root.left.data == 2
|
||||
assert root.left.left.data == 1
|
||||
assert root.left.left.left == nil
|
||||
assert root.left.left.right == nil
|
||||
assert root.left.right.data == 3
|
||||
assert root.left.right.left == nil
|
||||
assert root.left.right.right == nil
|
||||
assert root.right.data == 6
|
||||
assert root.right.left.data == 5
|
||||
assert root.right.left.left == nil
|
||||
assert root.right.left.right == nil
|
||||
assert root.right.right.data == 7
|
||||
assert root.right.right.left == nil
|
||||
assert root.right.right.right == nil
|
||||
end
|
||||
|
||||
describe "can sort data" do
|
||||
test "can sort single number" do
|
||||
root = BinarySearchTree.new(2)
|
||||
|
||||
assert [2] == BinarySearchTree.in_order(root)
|
||||
end
|
||||
|
||||
test "can sort if second number is smaller than first" do
|
||||
root =
|
||||
BinarySearchTree.new(2)
|
||||
|> BinarySearchTree.insert(1)
|
||||
|
||||
assert [1, 2] == BinarySearchTree.in_order(root)
|
||||
end
|
||||
|
||||
test "can sort if second number is the same as the first" do
|
||||
root =
|
||||
BinarySearchTree.new(2)
|
||||
|> BinarySearchTree.insert(2)
|
||||
|
||||
assert [2, 2] == BinarySearchTree.in_order(root)
|
||||
end
|
||||
|
||||
test "can sort if second number is greater than the first" do
|
||||
root =
|
||||
BinarySearchTree.new(2)
|
||||
|> BinarySearchTree.insert(3)
|
||||
|
||||
assert [2, 3] == BinarySearchTree.in_order(root)
|
||||
end
|
||||
|
||||
test "can sort complex tree" do
|
||||
root =
|
||||
BinarySearchTree.new(2)
|
||||
|> BinarySearchTree.insert(1)
|
||||
|> BinarySearchTree.insert(3)
|
||||
|> BinarySearchTree.insert(6)
|
||||
|> BinarySearchTree.insert(7)
|
||||
|> BinarySearchTree.insert(5)
|
||||
|
||||
assert [1, 2, 3, 5, 6, 7] == BinarySearchTree.in_order(root)
|
||||
end
|
||||
end
|
||||
end
|
||||
2
elixir/binary-search-tree/test/test_helper.exs
Normal file
2
elixir/binary-search-tree/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
31
elixir/binary-search/.exercism/config.json
Normal file
31
elixir/binary-search/.exercism/config.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"authors": [
|
||||
"bernardoamc"
|
||||
],
|
||||
"contributors": [
|
||||
"angelikatyborska",
|
||||
"Cohen-Carlisle",
|
||||
"devonestes",
|
||||
"lpil",
|
||||
"martinsvalin",
|
||||
"neenjaw",
|
||||
"parkerl",
|
||||
"screamingjungle",
|
||||
"sotojuan",
|
||||
"waiting-for-dev"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/binary_search.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/binary_search_test.exs"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.ex"
|
||||
]
|
||||
},
|
||||
"blurb": "Implement a binary search algorithm.",
|
||||
"source": "Wikipedia",
|
||||
"source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm"
|
||||
}
|
||||
1
elixir/binary-search/.exercism/metadata.json
Normal file
1
elixir/binary-search/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"binary-search","id":"46907374d6fd43e0815717c10201d2e0","url":"https://exercism.org/tracks/elixir/exercises/binary-search","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/binary-search/.formatter.exs
Normal file
4
elixir/binary-search/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/binary-search/.gitignore
vendored
Normal file
24
elixir/binary-search/.gitignore
vendored
Normal 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").
|
||||
binary_search-*.tar
|
||||
|
||||
75
elixir/binary-search/HELP.md
Normal file
75
elixir/binary-search/HELP.md
Normal 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/binary_search.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.
|
||||
71
elixir/binary-search/README.md
Normal file
71
elixir/binary-search/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Binary Search
|
||||
|
||||
Welcome to Binary Search on Exercism's Elixir Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Introduction
|
||||
|
||||
You have stumbled upon a group of mathematicians who are also singer-songwriters.
|
||||
They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]).
|
||||
|
||||
You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while.
|
||||
Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about.
|
||||
|
||||
You realize that you can use a binary search algorithm to quickly find a song given the title.
|
||||
|
||||
[zero]: https://en.wikipedia.org/wiki/0
|
||||
[seventy-three]: https://en.wikipedia.org/wiki/73_(number)
|
||||
[kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number)
|
||||
|
||||
## Instructions
|
||||
|
||||
Your task is to implement a binary search algorithm.
|
||||
|
||||
A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for.
|
||||
It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations.
|
||||
|
||||
~~~~exercism/caution
|
||||
Binary search only works when a list has been sorted.
|
||||
~~~~
|
||||
|
||||
The algorithm looks like this:
|
||||
|
||||
- Find the middle element of a _sorted_ list and compare it with the item we're looking for.
|
||||
- If the middle element is our item, then we're done!
|
||||
- If the middle element is greater than our item, we can eliminate that element and all the elements **after** it.
|
||||
- If the middle element is less than our item, we can eliminate that element and all the elements **before** it.
|
||||
- If every element of the list has been eliminated then the item is not in the list.
|
||||
- Otherwise, repeat the process on the part of the list that has not been eliminated.
|
||||
|
||||
Here's an example:
|
||||
|
||||
Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`.
|
||||
|
||||
- We start by comparing 23 with the middle element, 16.
|
||||
- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`.
|
||||
- We then compare 23 with the new middle element, 28.
|
||||
- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`.
|
||||
- We've found our item.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @bernardoamc
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @angelikatyborska
|
||||
- @Cohen-Carlisle
|
||||
- @devonestes
|
||||
- @lpil
|
||||
- @martinsvalin
|
||||
- @neenjaw
|
||||
- @parkerl
|
||||
- @screamingjungle
|
||||
- @sotojuan
|
||||
- @waiting-for-dev
|
||||
|
||||
### Based on
|
||||
|
||||
Wikipedia - https://en.wikipedia.org/wiki/Binary_search_algorithm
|
||||
34
elixir/binary-search/lib/binary_search.ex
Normal file
34
elixir/binary-search/lib/binary_search.ex
Normal file
@@ -0,0 +1,34 @@
|
||||
defmodule BinarySearch do
|
||||
@doc """
|
||||
Searches for a key in the tuple using the binary search algorithm.
|
||||
It returns :not_found if the key is not in the tuple.
|
||||
Otherwise returns {:ok, index}.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> BinarySearch.search({}, 2)
|
||||
:not_found
|
||||
|
||||
iex> BinarySearch.search({1, 3, 5}, 2)
|
||||
:not_found
|
||||
|
||||
iex> BinarySearch.search({1, 3, 5}, 5)
|
||||
{:ok, 2}
|
||||
|
||||
"""
|
||||
|
||||
@spec search(tuple, integer) :: {:ok, integer} | :not_found
|
||||
def search({}, _value), do: :not_found
|
||||
def search(numbers, value), do: do_search(numbers, value, 0, tuple_size(numbers) - 1)
|
||||
|
||||
defp do_search(_numbers, _value, from, to) when from > to, do: :not_found
|
||||
defp do_search(numbers, value, from, to) do
|
||||
middle = div(from + to, 2)
|
||||
element = elem(numbers, middle)
|
||||
cond do
|
||||
value == element -> {:ok, middle}
|
||||
value < element -> do_search(numbers, value, from, middle - 1)
|
||||
value > element -> do_search(numbers, value, middle + 1, to)
|
||||
end
|
||||
end
|
||||
end
|
||||
28
elixir/binary-search/mix.exs
Normal file
28
elixir/binary-search/mix.exs
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule BinarySearch.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :binary_search,
|
||||
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
|
||||
57
elixir/binary-search/test/binary_search_test.exs
Normal file
57
elixir/binary-search/test/binary_search_test.exs
Normal file
@@ -0,0 +1,57 @@
|
||||
defmodule BinarySearchTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test "finds a value in a tuple with one element" do
|
||||
assert BinarySearch.search({6}, 6) == {:ok, 0}
|
||||
assert BinarySearch.search({3}, 3) == {:ok, 0}
|
||||
end
|
||||
|
||||
test "finds a value in the middle of a tuple" do
|
||||
assert BinarySearch.search({1, 2, 4, 5, 6}, 4) == {:ok, 2}
|
||||
assert BinarySearch.search({1, 3, 4, 6, 8, 9, 11}, 6) == {:ok, 3}
|
||||
end
|
||||
|
||||
test "finds a value at the beginning of a tuple" do
|
||||
assert BinarySearch.search({1, 2, 4, 5, 6}, 1) == {:ok, 0}
|
||||
assert BinarySearch.search({1, 3, 4, 5, 8, 9, 11}, 1) == {:ok, 0}
|
||||
end
|
||||
|
||||
test "finds a value at the end of a tuple" do
|
||||
assert BinarySearch.search({1, 2, 4, 5, 6}, 6) == {:ok, 4}
|
||||
assert BinarySearch.search({1, 3, 4, 5, 8, 9, 11}, 11) == {:ok, 6}
|
||||
end
|
||||
|
||||
test "finds a value in a tuple of odd length" do
|
||||
tuple = {1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634}
|
||||
assert BinarySearch.search(tuple, 144) == {:ok, 9}
|
||||
end
|
||||
|
||||
test "finds a value in a tuple of even length" do
|
||||
tuple = {1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377}
|
||||
assert BinarySearch.search(tuple, 21) == {:ok, 5}
|
||||
assert BinarySearch.search(tuple, 34) == {:ok, 6}
|
||||
end
|
||||
|
||||
test "identifies that a value is not included in the tuple" do
|
||||
assert BinarySearch.search({2, 4, 6}, 3) == :not_found
|
||||
assert BinarySearch.search({1, 3, 4, 6, 8, 9, 11}, 7) == :not_found
|
||||
end
|
||||
|
||||
test "a value smaller than the tuple's smallest value is not found" do
|
||||
assert BinarySearch.search({2, 4, 6}, 1) == :not_found
|
||||
assert BinarySearch.search({1, 3, 4, 6, 8, 9, 11}, 0) == :not_found
|
||||
end
|
||||
|
||||
test "a value larger than the tuple's largest value is not found" do
|
||||
assert BinarySearch.search({2, 4, 6}, 9) == :not_found
|
||||
assert BinarySearch.search({1, 3, 4, 6, 8, 9, 11}, 13) == :not_found
|
||||
end
|
||||
|
||||
test "nothing is found in an empty tuple" do
|
||||
assert BinarySearch.search({}, 1) == :not_found
|
||||
end
|
||||
|
||||
test "nothing is found when the left and right bounds cross" do
|
||||
assert BinarySearch.search({1, 2}, 0) == :not_found
|
||||
end
|
||||
end
|
||||
2
elixir/binary-search/test/test_helper.exs
Normal file
2
elixir/binary-search/test/test_helper.exs
Normal file
@@ -0,0 +1,2 @@
|
||||
ExUnit.start()
|
||||
ExUnit.configure(exclude: :pending, trace: true)
|
||||
25
elixir/bird-count/.exercism/config.json
Normal file
25
elixir/bird-count/.exercism/config.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"authors": [
|
||||
"angelikatyborska"
|
||||
],
|
||||
"contributors": [
|
||||
"neenjaw"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"lib/bird_count.ex"
|
||||
],
|
||||
"test": [
|
||||
"test/bird_count_test.exs"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.ex"
|
||||
]
|
||||
},
|
||||
"language_versions": ">=1.10",
|
||||
"forked_from": [
|
||||
"csharp/bird-watcher"
|
||||
],
|
||||
"icon": "bird-watcher",
|
||||
"blurb": "Learn about recursion by keeping track of how many birds visit your garden each day."
|
||||
}
|
||||
1
elixir/bird-count/.exercism/metadata.json
Normal file
1
elixir/bird-count/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"elixir","exercise":"bird-count","id":"0c00dd30ec8043f1ab5a1e23a37b5f35","url":"https://exercism.org/tracks/elixir/exercises/bird-count","handle":"negrienko","is_requester":true,"auto_approve":false}
|
||||
4
elixir/bird-count/.formatter.exs
Normal file
4
elixir/bird-count/.formatter.exs
Normal file
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
elixir/bird-count/.gitignore
vendored
Normal file
24
elixir/bird-count/.gitignore
vendored
Normal 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").
|
||||
recursion-*.tar
|
||||
|
||||
75
elixir/bird-count/HELP.md
Normal file
75
elixir/bird-count/HELP.md
Normal 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/bird_count.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.
|
||||
41
elixir/bird-count/HINTS.md
Normal file
41
elixir/bird-count/HINTS.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- Read about recursion in the official [Getting Started guide][getting-started-recursion].
|
||||
- Read about recursion on [elixirschool.com][elixir-school-recursion].
|
||||
- Use multiple clause functions and pattern matching.
|
||||
- Try to split a problem into a base case and a recursive case. For example, let's say you want to count how many cookies are there in the cookie jar with a recursive approach. A base case is an empty jar - it has zero cookies. If the jar is not empty, then the number of cookies in the jar is equal to one cookie plus the number of cookies in the jar after removing one cookie.
|
||||
|
||||
## 1. Check how many birds visited today
|
||||
|
||||
- This task doesn't need recursion.
|
||||
- Accessing the first element in a list can be done by [pattern matching][getting-started-pattern-matching].
|
||||
|
||||
## 2. Increment today's count
|
||||
|
||||
- This task doesn't need recursion.
|
||||
- Accessing the first element in a list can be done by [pattern matching][getting-started-pattern-matching].
|
||||
|
||||
## 3. Check if there was a day with no visiting birds
|
||||
|
||||
- Use recursion to iterate over elements in the list until a day with no visiting birds is found.
|
||||
- The base case is an empty list.
|
||||
|
||||
## 4. Calculate the total number of visiting birds
|
||||
|
||||
- Use recursion to iterate over every element in the list.
|
||||
- The base case is an empty list.
|
||||
|
||||
## 5. Calculate the number of busy days
|
||||
|
||||
- Use recursion to iterate over every element in the list.
|
||||
- The base case is an empty list.
|
||||
- A function can have more than one recursive case.
|
||||
- Use a [guard][kernel-equal-or-greater-than] for one of the function clauses.
|
||||
|
||||
[getting-started-recursion]: https://elixir-lang.org/getting-started/recursion.html
|
||||
[getting-started-pattern-matching]: https://elixir-lang.org/getting-started/pattern-matching.html#pattern-matching-1
|
||||
[getting-started-strings]: https://elixir-lang.org/getting-started/recursion.html
|
||||
[elixir-school-recursion]: https://elixirschool.com/blog/recursion/
|
||||
[kernel-equal-or-greater-than]: https://hexdocs.pm/elixir/Kernel.html#%3E=/2
|
||||
93
elixir/bird-count/README.md
Normal file
93
elixir/bird-count/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Bird Count
|
||||
|
||||
Welcome to Bird Count 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
|
||||
|
||||
## Recursion
|
||||
|
||||
Recursive functions are functions that call themselves.
|
||||
|
||||
A recursive function needs to have at least one _base case_ and at least one _recursive case_.
|
||||
|
||||
A _base case_ returns a value without calling the function again. A _recursive case_ calls the function again, modifying the input so that it will at some point match the base case.
|
||||
|
||||
Very often, each case is written in its own function clause.
|
||||
|
||||
```elixir
|
||||
# base case
|
||||
def count([]), do: 0
|
||||
|
||||
# recursive case
|
||||
def count([_head | tail]), do: 1 + count(tail)
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
You're an avid bird watcher that keeps track of how many birds have visited your garden on any given day.
|
||||
|
||||
You decided to bring your bird watching to a new level and implement a few tools that will help you track and process the data.
|
||||
|
||||
You have chosen to store the data as a list of integers. The first number in the list is the number of birds that visited your garden today, the second yesterday, and so on.
|
||||
|
||||
## 1. Check how many birds visited today
|
||||
|
||||
Implement the `BirdCount.today/1` function. It should take a list of daily bird counts and return today's count. If the list is empty, it should return `nil`.
|
||||
|
||||
```elixir
|
||||
BirdCount.today([2, 5, 1])
|
||||
# => 2
|
||||
```
|
||||
|
||||
## 2. Increment today's count
|
||||
|
||||
Implement the `BirdCount.increment_day_count/1` function. It should take a list of daily bird counts and increment the today's count by 1. If the list is empty, return `[1]`.
|
||||
|
||||
```elixir
|
||||
BirdCount.increment_day_count([4, 0, 2])
|
||||
# => [5, 0, 2]
|
||||
```
|
||||
|
||||
## 3. Check if there was a day with no visiting birds
|
||||
|
||||
Implement the `BirdCount.has_day_without_birds?/1` function. It should take a list of daily bird counts. It should return `true` if there was at least one day when no birds visited the garden, and `false` otherwise.
|
||||
|
||||
```elixir
|
||||
BirdCount.has_day_without_birds?([2, 0, 4])
|
||||
# => true
|
||||
|
||||
BirdCount.has_day_without_birds?([3, 8, 1, 5])
|
||||
# => false
|
||||
```
|
||||
|
||||
## 4. Calculate the total number of visiting birds
|
||||
|
||||
Implement the `BirdCount.total/1` function. It should take a list of daily bird counts and return the total number that visited your garden since you started collecting the data.
|
||||
|
||||
```elixir
|
||||
BirdCount.total([4, 0, 9, 0, 5])
|
||||
# => 18
|
||||
```
|
||||
|
||||
## 5. Calculate the number of busy days
|
||||
|
||||
Some days are busier than others. A busy day is one where five or more birds have visited your garden.
|
||||
|
||||
Implement the `BirdCount.busy_days/1` function. It should take a list of daily bird counts and return the number of busy days.
|
||||
|
||||
```elixir
|
||||
BirdCount.busy_days([4, 5, 0, 0, 6])
|
||||
# => 2
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @angelikatyborska
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @neenjaw
|
||||
18
elixir/bird-count/lib/bird_count.ex
Normal file
18
elixir/bird-count/lib/bird_count.ex
Normal file
@@ -0,0 +1,18 @@
|
||||
defmodule BirdCount do
|
||||
def today([]), do: nil
|
||||
def today([head | _tail]), do: head
|
||||
|
||||
def increment_day_count([]), do: [1]
|
||||
def increment_day_count([head | tail]), do: [head + 1 | tail]
|
||||
|
||||
def has_day_without_birds?([]), do: false
|
||||
def has_day_without_birds?([0 | _tail]), do: true
|
||||
def has_day_without_birds?([_head | tail]), do: has_day_without_birds?(tail)
|
||||
|
||||
def total([]), do: 0
|
||||
def total([head | tail]), do: head + total(tail)
|
||||
|
||||
def busy_days([]), do: 0
|
||||
def busy_days([head | tail]) when head >= 5, do: 1 + busy_days(tail)
|
||||
def busy_days([_head | tail]), do: busy_days(tail)
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user