Compare commits
17 Commits
2ac630dd8c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d1d94c31d | ||
|
|
172b59c404 | ||
|
|
589a3b886a | ||
|
|
760f5ef4a6 | ||
|
|
0d5036c5c4 | ||
|
|
d8e3cea890 | ||
|
|
84098e7db9 | ||
|
|
fad9b41d97 | ||
|
|
89739137e7 | ||
|
|
c2bd0afb7d | ||
|
|
74e8c6d6dc | ||
|
|
05a0ab003b | ||
|
|
c0308da8c5 | ||
|
|
2c54444d46 | ||
|
|
1c8dcb28be | ||
|
|
0df72539ef | ||
|
|
b8181175c9 |
21
erlang-extraction/.exercism/config.json
Normal file
21
erlang-extraction/.exercism/config.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/erlang_extraction.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/erlang_extraction_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"blurb": "Learn about external types and functions by using an Erlang library"
|
||||
}
|
||||
1
erlang-extraction/.exercism/metadata.json
Normal file
1
erlang-extraction/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"erlang-extraction","id":"567185dac6004b25b6b5bc1eb51faa91","url":"https://exercism.org/tracks/gleam/exercises/erlang-extraction","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
erlang-extraction/.gitignore
vendored
Normal file
4
erlang-extraction/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
erlang-extraction/HELP.md
Normal file
32
erlang-extraction/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/erlang_extraction.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
23
erlang-extraction/HINTS.md
Normal file
23
erlang-extraction/HINTS.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Hints
|
||||
|
||||
## 1. Define the `GbTree` external type
|
||||
|
||||
- External types can be defined using the `pub type TypeName(a, b, c)` syntax.
|
||||
|
||||
## 2. Define the `new_gb_tree` function
|
||||
|
||||
- External functions can be defined using the `@external(erlang, "module", "function")` syntax.
|
||||
- The function should use the `gb_trees:empty/0`.
|
||||
|
||||
## 3. Define the `insert` function
|
||||
|
||||
- Check the `gb_trees:insert/3` documentation to confirm the correct order of arguments.
|
||||
- The external function can be a private function that is called by the `insert` function in order to change the order of the arguments.
|
||||
- The function should use the `gb_trees:insert/3`.
|
||||
|
||||
## 4. Define the `delete` function
|
||||
|
||||
- Check the `gb_trees:delete_any/2` documentation to confirm the correct order of arguments.
|
||||
- The external function can be a private function that is called by the `delete` function in order to change the order of the arguments.
|
||||
- The function should use the `gb_trees:delete_any/2`.
|
||||
- The `gb_trees:delete/2` function will crash if the key is not found, so it should not be used.
|
||||
108
erlang-extraction/README.md
Normal file
108
erlang-extraction/README.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Erlang Extraction
|
||||
|
||||
Welcome to Erlang Extraction on Exercism's Gleam 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
|
||||
|
||||
## External Functions
|
||||
|
||||
Gleam can run on the Erlang virtual machine (BEAM), or on JavaScript runtimes. There are many other languages that use these runtimes, and it is often useful to be able to call code written in these languages from Gleam.
|
||||
|
||||
Gleam's _external functions_ feature permits functions in other languages to be imported into Gleam and called with no runtime overhead.
|
||||
|
||||
If your Gleam project runs on the Erlang virtual machine and you wish to call the `reverse` function from the Erlang `lists` module you can do it by adding the `@external` attribute to a Gleam function head like this:
|
||||
|
||||
```gleam
|
||||
@external(erlang, "lists", "reverse")
|
||||
pub fn reverse_list(x: List(a)) -> List(a)
|
||||
```
|
||||
|
||||
This can then be called as a normal Gleam function:
|
||||
|
||||
```gleam
|
||||
let reversed = reverse_list([1, 2, 3])
|
||||
// -> [3, 2, 1]
|
||||
```
|
||||
|
||||
If you attempt to compile this code for JavaScript runtimes it will fail with an error message as there is no implementation for JavaScript. Another implementation can be specified for JavaScript runtimes like this:
|
||||
|
||||
```gleam
|
||||
@external(erlang, "lists", "reverse")
|
||||
@external(javascript, "./my_module.mjs", "reverse")
|
||||
pub fn reverse_list(x: List(a)) -> List(a)
|
||||
```
|
||||
|
||||
It is also possible to write a Gleam implementation that will be used when there is no external implementation for the current compile target:
|
||||
|
||||
```gleam
|
||||
@external(erlang, "lists", "reverse")
|
||||
pub fn reverse_list(x: List(a)) -> List(a) {
|
||||
tail_recursive_reverse(x, [])
|
||||
}
|
||||
|
||||
fn tail_recursive_reverse(list, reversed) {
|
||||
case list {
|
||||
[] -> reversed
|
||||
[x, ..xs] -> tail_recursive_reverse(xs, [x, ..reversed])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## External Types
|
||||
|
||||
External types can be used to refer to data types defined in other languages, such as Erlang or JavaScript.
|
||||
|
||||
To define an external type declare a type but do not provide any constructors. This can then be used in the same way as any other type.
|
||||
|
||||
```gleam
|
||||
pub type OrderedDictionary(element)
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
Tadhg has found the perfect Erlang library to help with his project. Being an older Erlang library it is using the `gb_trees` module rather than the newer `maps` module for storing data.
|
||||
|
||||
Help out Tadgh by creating external types and functions for working with `gb_trees` in Gleam.
|
||||
|
||||
## 1. Define the `GbTree` external type
|
||||
|
||||
The `GbTree` type should have two type parameters, a key type and a value type. It should have no constructors, making it an external type.
|
||||
|
||||
## 2. Define the `new_gb_tree` function
|
||||
|
||||
The `new_gb_tree` function should take no arguments and return an empty `GbTree`.
|
||||
|
||||
It should use the [`gb_trees:empty/0` function][empty] from the Erlang standard library.
|
||||
|
||||
## 3. Define the `insert` function
|
||||
|
||||
The `insert` function should take a `GbTree` and a key and value to insert into the tree. It should return a new `GbTree` with the key and value inserted.
|
||||
|
||||
The function should take three arguments:
|
||||
1. The `GbTree` to insert into.
|
||||
2. The key to insert.
|
||||
3. The value to insert.
|
||||
|
||||
It should use the [`gb_trees:insert/3` function][insert] from the Erlang standard library.
|
||||
|
||||
## 4. Define the `delete` function
|
||||
|
||||
The `delete` function should take a `GbTree` and a key to delete from the tree. It should return a new `GbTree` with the key and value deleted.
|
||||
|
||||
The function should take two arguments:
|
||||
1. The `GbTree` to delete from.
|
||||
2. The key to delete.
|
||||
|
||||
It should use the [`gb_trees:delete_any/2` function][delete_any] from the Erlang standard library.
|
||||
|
||||
[empty]: https://www.erlang.org/doc/apps/stdlib/gb_trees.html#empty/0
|
||||
[insert]: https://www.erlang.org/doc/apps/stdlib/gb_trees.html#insert/3
|
||||
[delete_any]: https://www.erlang.org/doc/apps/stdlib/gb_trees.html#delete_any/2
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
erlang-extraction/gleam.toml
Normal file
14
erlang-extraction/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "erlang_extraction"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
erlang-extraction/manifest.toml
Normal file
31
erlang-extraction/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
20
erlang-extraction/src/erlang_extraction.gleam
Normal file
20
erlang-extraction/src/erlang_extraction.gleam
Normal file
@@ -0,0 +1,20 @@
|
||||
// Please define the GbTree type
|
||||
|
||||
pub type GbTree(k, v)
|
||||
|
||||
@external(erlang, "gb_trees", "empty")
|
||||
pub fn new_gb_tree() -> GbTree(k, v)
|
||||
|
||||
pub fn insert(tree: GbTree(k, v), key: k, value: v) -> GbTree(k, v) {
|
||||
gb_trees_insert(key, value, tree)
|
||||
}
|
||||
|
||||
@external(erlang, "gb_trees", "insert")
|
||||
fn gb_trees_insert(key: k, value: v, tree: GbTree(k, v)) -> GbTree(k, v)
|
||||
|
||||
pub fn delete(tree: GbTree(k, v), key: k) -> GbTree(k, v) {
|
||||
gb_trees_delete_any(key, tree)
|
||||
}
|
||||
|
||||
@external(erlang, "gb_trees", "delete_any")
|
||||
fn gb_trees_delete_any(key: k, tree: GbTree(k, v)) -> GbTree(k, v)
|
||||
54
erlang-extraction/test/erlang_extraction_test.gleam
Normal file
54
erlang-extraction/test/erlang_extraction_test.gleam
Normal file
@@ -0,0 +1,54 @@
|
||||
import erlang_extraction.{type GbTree}
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
@external(erlang, "gb_trees", "to_list")
|
||||
fn to_list(tree: GbTree(k, v)) -> List(#(k, v))
|
||||
|
||||
pub fn new_gb_tree_test() {
|
||||
erlang_extraction.new_gb_tree()
|
||||
|> to_list
|
||||
|> should.equal([])
|
||||
}
|
||||
|
||||
pub fn insert_int_string_test() {
|
||||
erlang_extraction.new_gb_tree()
|
||||
|> erlang_extraction.insert(1, "one")
|
||||
|> erlang_extraction.insert(2, "two")
|
||||
|> erlang_extraction.insert(3, "three")
|
||||
|> to_list
|
||||
|> should.equal([#(1, "one"), #(2, "two"), #(3, "three")])
|
||||
}
|
||||
|
||||
pub fn insert_string_int_test() {
|
||||
erlang_extraction.new_gb_tree()
|
||||
|> erlang_extraction.insert("one", 1)
|
||||
|> erlang_extraction.insert("two", 2)
|
||||
|> erlang_extraction.insert("three", 3)
|
||||
|> to_list
|
||||
|> should.equal([#("one", 1), #("three", 3), #("two", 2)])
|
||||
}
|
||||
|
||||
pub fn delete_test() {
|
||||
erlang_extraction.new_gb_tree()
|
||||
|> erlang_extraction.insert(1, "one")
|
||||
|> erlang_extraction.insert(2, "two")
|
||||
|> erlang_extraction.insert(3, "three")
|
||||
|> erlang_extraction.delete(2)
|
||||
|> to_list
|
||||
|> should.equal([#(1, "one"), #(3, "three")])
|
||||
}
|
||||
|
||||
pub fn delete_non_existing_test() {
|
||||
erlang_extraction.new_gb_tree()
|
||||
|> erlang_extraction.insert(1, "one")
|
||||
|> erlang_extraction.insert(2, "two")
|
||||
|> erlang_extraction.insert(3, "three")
|
||||
|> erlang_extraction.delete(4)
|
||||
|> to_list
|
||||
|> should.equal([#(1, "one"), #(2, "two"), #(3, "three")])
|
||||
}
|
||||
21
expert-experiments/.exercism/config.json
Normal file
21
expert-experiments/.exercism/config.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/expert_experiments.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/expert_experiments_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"blurb": "Learn about use expressions by conducting some experiments"
|
||||
}
|
||||
1
expert-experiments/.exercism/metadata.json
Normal file
1
expert-experiments/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"expert-experiments","id":"4f12bf49f75c4ebaba7dc8a949bd874b","url":"https://exercism.org/tracks/gleam/exercises/expert-experiments","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
expert-experiments/.gitignore
vendored
Normal file
4
expert-experiments/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
expert-experiments/HELP.md
Normal file
32
expert-experiments/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/expert_experiments.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
15
expert-experiments/HINTS.md
Normal file
15
expert-experiments/HINTS.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Hints
|
||||
|
||||
## 1. Define the `with_retry` function
|
||||
|
||||
- A `case` expression can be used to pattern match on a result.
|
||||
|
||||
## 2. Define the `record_timing` function
|
||||
|
||||
- The `time_logger` function should be called even if the `experiment` function returns an `Error` value.
|
||||
|
||||
## 3. Define the `run_experiment` function
|
||||
|
||||
- The [`result.try` function][result-try] can be used in a `use` expression to stop if a result is an `Error` value.
|
||||
|
||||
[result-try]: https://hexdocs.pm/gleam_stdlib/gleam/result.html#try
|
||||
149
expert-experiments/README.md
Normal file
149
expert-experiments/README.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Expert Experiments
|
||||
|
||||
Welcome to Expert Experiments on Exercism's Gleam 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
|
||||
|
||||
## Use Expressions
|
||||
|
||||
In Gleam it is common to write and use higher order functions, that is functions that take other functions as arguments. Sometimes when using many higher order functions at once the code can become difficult to read, with many layers of indentation.
|
||||
|
||||
For example, here is a function that calls several functions that return `Result(Int, Nil)`, and sums the values if all four are successful.
|
||||
|
||||
```gleam
|
||||
import gleam/result
|
||||
|
||||
pub fn main() -> Result(Int, Nil) {
|
||||
result.try(function1(), fn(a) {
|
||||
result.try(function2(), fn(b) {
|
||||
result.try(function3(), fn(c) {
|
||||
result.try(function4(), fn(d) {
|
||||
Ok(a + b + c + d)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Gleam's `use` expressions allow us to write this code without the indentation, often making it easier to read.
|
||||
|
||||
```gleam
|
||||
import gleam/result
|
||||
|
||||
pub fn main() -> Result(Int, Nil) {
|
||||
use a <- result.try(function1())
|
||||
use b <- result.try(function2())
|
||||
use c <- result.try(function3())
|
||||
use d <- result.try(function4())
|
||||
Ok(a + b + c + d)
|
||||
}
|
||||
```
|
||||
|
||||
A `use` expression collects all the following statements in the block and passes it as a callback function as the final argument to the function call. The variables between the `use` keyword and the `<-` symbol are the names of the arguments that will be passed to the callback function.
|
||||
|
||||
```gleam
|
||||
// This use expression
|
||||
use a <- function(1, 2)
|
||||
io.println("Hello!")
|
||||
a
|
||||
|
||||
// Is equivalent to this normal function call
|
||||
function(1, 2, fn(a) {
|
||||
io.println("Hello!")
|
||||
a
|
||||
})
|
||||
```
|
||||
|
||||
The callback function can take any number of arguments, or none at all.
|
||||
|
||||
```gleam
|
||||
use a, b, c, d <- call_4_function()
|
||||
|
||||
use <- call_0_function()
|
||||
```
|
||||
|
||||
There are no special requirements to create a function that can be called with a `use` expression, other than taking a callback function as the final argument.
|
||||
|
||||
```gleam
|
||||
pub fn call_twice(function: fn() -> t) -> #(t, t) {
|
||||
let first = function()
|
||||
let second = function()
|
||||
#(first, second)
|
||||
}
|
||||
```
|
||||
|
||||
Gleam's `use` expressions are a very powerful feature that can be applied to lots of problems, but when overused they can make code difficult to read. It is generally preferred to use the normal function call syntax and only reach for `use` expressions when they make the code easier to read.
|
||||
|
||||
## Instructions
|
||||
|
||||
Daphne has been working on a system to run and record the results of her experiments. Some of the code has become a bit verbose and repetitive, so she's asked you to write some `use` expressions to help clean it up.
|
||||
|
||||
## 1. Define the `with_retry` function
|
||||
|
||||
Sometimes experiments can fail due to a one-off mistake, so if an experiment fails Daphne wants to retry it again to see if it works the second time.
|
||||
|
||||
Define the `with_retry` function that takes a result returning function as an argument.
|
||||
|
||||
If the function returns an `Ok` value then `with_retry` should return that value.
|
||||
|
||||
If the function returns an `Error` value then `with_retry` should call the function again and return the result of that call.
|
||||
|
||||
Daphne will use the function like this:
|
||||
|
||||
```gleam
|
||||
pub fn main() {
|
||||
use <- with_retry
|
||||
// Perform the experiment here
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Define the `record_timing` function
|
||||
|
||||
Daphne records how long each experiment takes to run by calling a time logging function before and after each experiment.
|
||||
|
||||
Define the `record_timing` function that takes two arguments:
|
||||
- A time logging function which takes no arguments and returns `Nil`.
|
||||
- An experiment function which takes no arguments and returns a result.
|
||||
|
||||
`record_timing` should call the time logging function, then call the experiment function, then call the time logging function again, and finally return the result of the experiment function.
|
||||
|
||||
Daphne will use the function like this:
|
||||
|
||||
```gleam
|
||||
pub fn main() {
|
||||
use <- record_timing(time_logger)
|
||||
// Perform the experiment here
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Define the `run_experiment` function
|
||||
|
||||
Experiments are made up of three phases. The setup, the action, and the recording. All three phases return results, and each phase needs the successful result of the previous phase to run.
|
||||
|
||||
Define the `run_experiment` function that takes four arguments:
|
||||
- The name of the experiment as a `String`.
|
||||
- A setup function which takes no arguments and returns a result.
|
||||
- An action function which takes the `Ok` value of the setup function as an argument and returns a result.
|
||||
- A recording function which takes the `Ok` value of the setup and action functions as arguments and returns a result.
|
||||
|
||||
If all three functions succeed then `run_experiment` should return `Ok(#(experiment_name, recording_data))`.
|
||||
|
||||
If any of the functions return an `Error` value then `run_experiment` should return that value.
|
||||
|
||||
Daphne will use the function like this:
|
||||
|
||||
```gleam
|
||||
pub fn main() {
|
||||
use setup_data, action_data <- run_experiment("Test 1", setup, action)
|
||||
// Record the results here
|
||||
}
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
expert-experiments/gleam.toml
Normal file
14
expert-experiments/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "expert_experiments"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
expert-experiments/manifest.toml
Normal file
31
expert-experiments/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
31
expert-experiments/src/expert_experiments.gleam
Normal file
31
expert-experiments/src/expert_experiments.gleam
Normal file
@@ -0,0 +1,31 @@
|
||||
import gleam/result
|
||||
|
||||
pub fn with_retry(experiment: fn() -> Result(t, e)) -> Result(t, e) {
|
||||
case experiment() {
|
||||
Error(_) -> experiment()
|
||||
Ok(result) -> Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_timing(
|
||||
time_logger: fn() -> Nil,
|
||||
experiment: fn() -> Result(t, e),
|
||||
) -> Result(t, e) {
|
||||
time_logger()
|
||||
let result = experiment()
|
||||
time_logger()
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn run_experiment(
|
||||
name: String,
|
||||
setup: fn() -> Result(t, e),
|
||||
action: fn(t) -> Result(u, e),
|
||||
record: fn(t, u) -> Result(v, e),
|
||||
) -> Result(#(String, v), e) {
|
||||
use setup_result <- result.try(setup())
|
||||
use action_result <- result.try(action(setup_result))
|
||||
use record_result <- result.try(record(setup_result, action_result))
|
||||
Ok(#(name, record_result))
|
||||
}
|
||||
143
expert-experiments/test/expert_experiments_test.gleam
Normal file
143
expert-experiments/test/expert_experiments_test.gleam
Normal file
@@ -0,0 +1,143 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import expert_experiments
|
||||
import gleam/erlang/process
|
||||
import gleam/list
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
fn mutable_yielder(elements: List(t)) -> fn() -> t {
|
||||
let subject = process.new_subject()
|
||||
list.each(elements, fn(element) { process.send(subject, element) })
|
||||
fn() {
|
||||
case process.receive(subject, 0) {
|
||||
Ok(element) -> element
|
||||
Error(_) -> panic as "Callback called too many times"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn logger() -> #(fn(String) -> Nil, fn() -> List(String)) {
|
||||
let subject = process.new_subject()
|
||||
let writer = fn(message) { process.send(subject, message) }
|
||||
let reader = fn() { read_all(subject, []) }
|
||||
#(writer, reader)
|
||||
}
|
||||
|
||||
fn read_all(
|
||||
subject: process.Subject(String),
|
||||
read: List(String),
|
||||
) -> List(String) {
|
||||
case process.receive(subject, 0) {
|
||||
Ok(message) -> read_all(subject, [message, ..read])
|
||||
Error(_) -> list.reverse(read)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_retry_pass_test() {
|
||||
let function = mutable_yielder([Ok("First"), Error("Second")])
|
||||
{
|
||||
use <- expert_experiments.with_retry
|
||||
function()
|
||||
}
|
||||
|> should.equal(Ok("First"))
|
||||
}
|
||||
|
||||
pub fn with_retry_fail_fail_test() {
|
||||
let function = mutable_yielder([Error("First"), Error("Second")])
|
||||
{
|
||||
use <- expert_experiments.with_retry
|
||||
function()
|
||||
}
|
||||
|> should.equal(Error("Second"))
|
||||
}
|
||||
|
||||
pub fn with_retry_fail_pass_test() {
|
||||
let function = mutable_yielder([Error("First"), Ok("Second")])
|
||||
{
|
||||
use <- expert_experiments.with_retry
|
||||
function()
|
||||
}
|
||||
|> should.equal(Ok("Second"))
|
||||
}
|
||||
|
||||
pub fn record_timing_pass_test() {
|
||||
let #(writer, reader) = logger()
|
||||
{
|
||||
use <- expert_experiments.record_timing(fn() { writer("timer") })
|
||||
writer("experiment")
|
||||
Ok(0)
|
||||
}
|
||||
|> should.equal(Ok(0))
|
||||
|
||||
reader()
|
||||
|> should.equal(["timer", "experiment", "timer"])
|
||||
}
|
||||
|
||||
pub fn record_timing_fail_test() {
|
||||
let #(writer, reader) = logger()
|
||||
{
|
||||
use <- expert_experiments.record_timing(fn() { writer("timer") })
|
||||
writer("experiment")
|
||||
Error(Nil)
|
||||
}
|
||||
|> should.equal(Error(Nil))
|
||||
|
||||
reader()
|
||||
|> should.equal(["timer", "experiment", "timer"])
|
||||
}
|
||||
|
||||
pub fn run_experiment_fail_test() {
|
||||
{
|
||||
let setup = fn() { Error("Setup failed") }
|
||||
let action = fn(_) { panic as "Should not run action" }
|
||||
use _, _ <- expert_experiments.run_experiment("Experiment 1", setup, action)
|
||||
panic as "Should not run record"
|
||||
}
|
||||
|> should.equal(Error("Setup failed"))
|
||||
}
|
||||
|
||||
pub fn run_experiment_pass_fail_test() {
|
||||
{
|
||||
let setup = fn() { Ok(1) }
|
||||
let action = fn(x) {
|
||||
should.equal(x, 1)
|
||||
Error("Action failed")
|
||||
}
|
||||
use _, _ <- expert_experiments.run_experiment("Experiment 1", setup, action)
|
||||
panic as "Should not run record"
|
||||
}
|
||||
|> should.equal(Error("Action failed"))
|
||||
}
|
||||
|
||||
pub fn run_experiment_pass_pass_fail_test() {
|
||||
{
|
||||
let setup = fn() { Ok(1) }
|
||||
let action = fn(x) {
|
||||
should.equal(x, 1)
|
||||
Ok("2")
|
||||
}
|
||||
use x, y <- expert_experiments.run_experiment("Experiment 1", setup, action)
|
||||
should.equal(x, 1)
|
||||
should.equal(y, "2")
|
||||
Error("Record failed")
|
||||
}
|
||||
|> should.equal(Error("Record failed"))
|
||||
}
|
||||
|
||||
pub fn run_experiment_pass_pass_pass_test() {
|
||||
{
|
||||
let setup = fn() { Ok(1) }
|
||||
let action = fn(x) {
|
||||
should.equal(x, 1)
|
||||
Ok("2")
|
||||
}
|
||||
use x, y <- expert_experiments.run_experiment("Experiment 1", setup, action)
|
||||
should.equal(x, 1)
|
||||
should.equal(y, "2")
|
||||
Ok("Success!")
|
||||
}
|
||||
|> should.equal(Ok(#("Experiment 1", "Success!")))
|
||||
}
|
||||
24
go/.exercism/config.json
Normal file
24
go/.exercism/config.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/go.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/go_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elm/go"
|
||||
],
|
||||
"blurb": "Learn usage of Result by applying the rules of the game of Go"
|
||||
}
|
||||
1
go/.exercism/metadata.json
Normal file
1
go/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"go","id":"5f92ded7f0d94054b5eb825d783c3245","url":"https://exercism.org/tracks/gleam/exercises/go","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
go/.gitignore
vendored
Normal file
4
go/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
go/HELP.md
Normal file
32
go/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/go.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
5
go/HINTS.md
Normal file
5
go/HINTS.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Hints
|
||||
|
||||
- The [Result module][result-module] has some useful functions for working with the Result type, such as `result.map` and `result.try`.
|
||||
|
||||
[result-module]: https://hexdocs.pm/gleam_stdlib/gleam/result.html
|
||||
107
go/README.md
Normal file
107
go/README.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Go
|
||||
|
||||
Welcome to Go on Exercism's Gleam 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
|
||||
|
||||
## Results
|
||||
|
||||
Gleam doesn't use exceptions for error handling, instead the generic `Result` type is returned by functions that can either succeed or fail.
|
||||
|
||||
The `Result` type is built into the language so you don't need to define or import it, but if you were to define it yourself it would look like this:
|
||||
|
||||
```gleam
|
||||
pub type Result(value, error) {
|
||||
Ok(value)
|
||||
Error(error)
|
||||
}
|
||||
```
|
||||
|
||||
The `Ok` variant is returned when a function succeeds, and the `Error` variant is returned when a function fails.
|
||||
|
||||
Results are very common in Gleam, and Gleam programmers will commonly use the [`gleam/result` module](https://hexdocs.pm/gleam_stdlib/gleam/result.html) to make working with them easier.
|
||||
|
||||
The `result.map` function can be used to call a function on the value inside a result if it is an `Ok`, or to pass through an `Error` unchanged.
|
||||
|
||||
```gleam
|
||||
Ok(1)
|
||||
|> result.map(fn(x) { x + 1 })
|
||||
// -> Ok(2)
|
||||
|
||||
Error("Oh no!")
|
||||
|> result.map(fn(x) { x + 1 })
|
||||
// -> Error("Oh no!")
|
||||
```
|
||||
|
||||
The `result.try` function is similar, but the callback function is expected to return a result. This is useful for chaining together multiple functions that return results.
|
||||
|
||||
```gleam
|
||||
Ok(1)
|
||||
|> result.try(fn(x) { Ok(x + 1) })
|
||||
// -> Ok(2)
|
||||
|
||||
Ok(1)
|
||||
|> result.try(fn(x) { Error("Nope!") })
|
||||
// -> Error("Nope!")
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
In this exercise, you'll be applying the [rules of the game of Go](https://matmoore.github.io/learngo/). The rules themselves are already written, you just need to apply them in order to update the Game and to handle any errors / violations of the rules.
|
||||
|
||||
The game is represented as follows:
|
||||
|
||||
```gleam
|
||||
pub type Player {
|
||||
Black
|
||||
White
|
||||
}
|
||||
|
||||
|
||||
pub type Game {
|
||||
Game(
|
||||
white_captured_stones: Int,
|
||||
black_captured_stones: Int,
|
||||
player: Player,
|
||||
error: String,
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
There are 4 rules in the game:
|
||||
|
||||
- Each point can only have one stone.
|
||||
- Opposition stones can be captured.
|
||||
- You can not place a stone where it would capture itself.
|
||||
- You can not use the same point twice.
|
||||
|
||||
## 1. Apply the rules
|
||||
|
||||
Write the content of the `apply_rules` function, which takes an initial `Game` and a set of rules, and returns the new `Game` after the rules have been applied.
|
||||
|
||||
Three of the rules all check for violations of the rules and may return an error, and so have the return type of `Result(Game, String)`. If any of these rules fail, the original game should be returned, but with the `error` field updated with the relevant error.
|
||||
|
||||
The other rule does not check for violations and so cannot fail (although it can return a changed `Game`), and so has the return type of `Game`.
|
||||
|
||||
If all the rules pass, then any changes to `Game` from the rules should be kept, and the player should be changed.
|
||||
|
||||
```gleam
|
||||
pub fn apply_rules(
|
||||
game: Game,
|
||||
rule1: fn(Game) -> Result(Game, String),
|
||||
rule2: fn(Game) -> Game,
|
||||
rule3: fn(Game) -> Result(Game, String),
|
||||
rule4: fn(Game) -> Result(Game, String),
|
||||
) -> Game {
|
||||
// -> If all rules pass, return a `Game` with all changes from the rules applied, and change player
|
||||
// -> If any rule fails, return the original Game, but with the error field set
|
||||
}
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
go/gleam.toml
Normal file
14
go/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "go"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
go/manifest.toml
Normal file
31
go/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
39
go/src/go.gleam
Normal file
39
go/src/go.gleam
Normal file
@@ -0,0 +1,39 @@
|
||||
import gleam/result
|
||||
|
||||
pub type Player {
|
||||
Black
|
||||
White
|
||||
}
|
||||
|
||||
pub type Game {
|
||||
Game(
|
||||
white_captured_stones: Int,
|
||||
black_captured_stones: Int,
|
||||
player: Player,
|
||||
error: String,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn apply_rules(
|
||||
game: Game,
|
||||
rule1: fn(Game) -> Result(Game, String),
|
||||
rule2: fn(Game) -> Game,
|
||||
rule3: fn(Game) -> Result(Game, String),
|
||||
rule4: fn(Game) -> Result(Game, String),
|
||||
) -> Game {
|
||||
game
|
||||
|> rule1
|
||||
|> result.map(rule2)
|
||||
|> result.try(rule3)
|
||||
|> result.try(rule4)
|
||||
|> fn(result) {
|
||||
case result {
|
||||
Error(err) -> Game(..game, error: err)
|
||||
Ok(g) ->
|
||||
case g.player {
|
||||
Black -> Game(..g, player: White)
|
||||
White -> Game(..g, player: Black)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
go/test/go_test.gleam
Normal file
110
go/test/go_test.gleam
Normal file
@@ -0,0 +1,110 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import go.{type Game, Black, Game, White}
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
fn identity(x: Game) -> Game {
|
||||
x
|
||||
}
|
||||
|
||||
fn identity_rule(game: Game) -> Result(Game, String) {
|
||||
Ok(game)
|
||||
}
|
||||
|
||||
fn error_rule(_game: Game, message: String) -> Result(Game, String) {
|
||||
Error(message)
|
||||
}
|
||||
|
||||
fn new_game() -> Game {
|
||||
Game(0, 0, White, "")
|
||||
}
|
||||
|
||||
fn ko_rule() -> String {
|
||||
"Cannot repeat a previously played board position"
|
||||
}
|
||||
|
||||
fn liberty_rule() -> String {
|
||||
"Cannot place a stone with no liberties"
|
||||
}
|
||||
|
||||
fn one_stone_per_point_rule() -> String {
|
||||
"You can't put a stone on top of another stone"
|
||||
}
|
||||
|
||||
fn add_white_captured_stone(game: Game) -> Game {
|
||||
Game(..game, white_captured_stones: 1)
|
||||
}
|
||||
|
||||
pub fn change_player_if_all_rules_pass_test() {
|
||||
new_game()
|
||||
|> go.apply_rules(identity_rule, identity, identity_rule, identity_rule)
|
||||
|> should.equal(change_player(new_game()))
|
||||
}
|
||||
|
||||
pub fn retain_error_and_player_if_ko_rule_fails_test() {
|
||||
new_game()
|
||||
|> go.apply_rules(identity_rule, identity, identity_rule, error_rule(
|
||||
_,
|
||||
ko_rule(),
|
||||
))
|
||||
|> should.equal(Game(..new_game(), error: ko_rule()))
|
||||
}
|
||||
|
||||
pub fn retain_error_and_player_if_liberty_rule_fails_test() {
|
||||
new_game()
|
||||
|> go.apply_rules(
|
||||
identity_rule,
|
||||
identity,
|
||||
error_rule(_, liberty_rule()),
|
||||
identity_rule,
|
||||
)
|
||||
|> should.equal(Game(..new_game(), error: liberty_rule()))
|
||||
}
|
||||
|
||||
pub fn retain_error_and_player_if_one_stone_per_point_rule_fails_test() {
|
||||
new_game()
|
||||
|> go.apply_rules(
|
||||
error_rule(_, one_stone_per_point_rule()),
|
||||
identity,
|
||||
identity_rule,
|
||||
identity_rule,
|
||||
)
|
||||
|> should.equal(Game(..new_game(), error: one_stone_per_point_rule()))
|
||||
}
|
||||
|
||||
pub fn retain_changes_from_capture_rule_and_change_player_test() {
|
||||
new_game()
|
||||
|> go.apply_rules(
|
||||
identity_rule,
|
||||
add_white_captured_stone,
|
||||
identity_rule,
|
||||
identity_rule,
|
||||
)
|
||||
|> should.equal(
|
||||
new_game()
|
||||
|> add_white_captured_stone
|
||||
|> change_player,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn discard_changes_from_capture_rule_if_subsequent_rule_fails_test() {
|
||||
new_game()
|
||||
|> go.apply_rules(
|
||||
identity_rule,
|
||||
add_white_captured_stone,
|
||||
identity_rule,
|
||||
error_rule(_, ko_rule()),
|
||||
)
|
||||
|> should.equal(Game(..new_game(), error: ko_rule()))
|
||||
}
|
||||
|
||||
fn change_player(game: Game) -> Game {
|
||||
let new_player = case game.player {
|
||||
White -> Black
|
||||
Black -> White
|
||||
}
|
||||
Game(..game, player: new_player)
|
||||
}
|
||||
24
high-school-sweetheart/.exercism/config.json
Normal file
24
high-school-sweetheart/.exercism/config.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/high_school_sweetheart.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/high_school_sweetheart_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elixir/high-school-sweetheart"
|
||||
],
|
||||
"blurb": "Learn about the pipe operator by helping high school sweethearts profess their love on social media via ASCII art."
|
||||
}
|
||||
1
high-school-sweetheart/.exercism/metadata.json
Normal file
1
high-school-sweetheart/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"high-school-sweetheart","id":"496bd682b8cc4070ab04077da46db44f","url":"https://exercism.org/tracks/gleam/exercises/high-school-sweetheart","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
high-school-sweetheart/.gitignore
vendored
Normal file
4
high-school-sweetheart/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
high-school-sweetheart/HELP.md
Normal file
32
high-school-sweetheart/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/high_school_sweetheart.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
30
high-school-sweetheart/HINTS.md
Normal file
30
high-school-sweetheart/HINTS.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- Browse the [functions available in the _string module_][string-module-functions] to discover which operations on strings Gleam's standard library offers.
|
||||
|
||||
## 1. Get the name's first letter
|
||||
|
||||
- There is a [function][string-first] to get the first character from a string.
|
||||
- There are multiple [functions][string-trim] to remove leading, trailing, or leading and trailing whitespaces from a string.
|
||||
|
||||
## 2. Format the first letter as an initial
|
||||
|
||||
- There is a [function][string-upcase] to convert all characters in a string to their uppercase variant.
|
||||
- The `<>` operator can be used to concatenate strings.
|
||||
|
||||
## 3. Split the full name into the first name and the last name
|
||||
|
||||
- There is a [function][string-split] that splits a string on whitespace characters.
|
||||
- A few first elements of a list can be assigned to variables by pattern matching on the list.
|
||||
|
||||
## 4. Put the initials inside of the heart
|
||||
|
||||
- The `<>` operator can be used to concatenate strings.
|
||||
|
||||
[string-module-functions]: https://hexdocs.pm/gleam_stdlib/gleam/string.html
|
||||
[string-first]: https://hexdocs.pm/gleam_stdlib/gleam/string.html#first
|
||||
[string-trim]: https://hexdocs.pm/gleam_stdlib/gleam/string.html#trim
|
||||
[string-upcase]: https://hexdocs.pm/gleam_stdlib/gleam/string.html#uppercase
|
||||
[string-split]: https://hexdocs.pm/gleam_stdlib/gleam/string.html#split
|
||||
127
high-school-sweetheart/README.md
Normal file
127
high-school-sweetheart/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# High School Sweetheart
|
||||
|
||||
Welcome to High School Sweetheart on Exercism's Gleam 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
|
||||
|
||||
## Pipe Operator
|
||||
|
||||
The `|>` operator is called the pipe operator. It can be used to chain function calls together in such a way that the value returned by the previous function call is passed to the next function call.
|
||||
|
||||
```gleam
|
||||
"hello"
|
||||
|> string.uppercase
|
||||
|> string.append("?!")
|
||||
// -> "HELLO?!"
|
||||
```
|
||||
|
||||
The above code is equivalent to the following:
|
||||
|
||||
```gleam
|
||||
string.append(string.uppercase("hello"), "?!")
|
||||
```
|
||||
|
||||
The pipe operator will either pass the value as the first argument to the function call, or the only argument to a new call, selecting whichever would have the correct type.
|
||||
|
||||
```gleam
|
||||
100
|
||||
|> function_that_takes_two_arguments(1)
|
||||
|
||||
// Is equivalent to
|
||||
function_that_takes_two_arguments(100, 1)
|
||||
```
|
||||
|
||||
```gleam
|
||||
100
|
||||
|> function_that_returns_a_function(1)
|
||||
|
||||
// Is equivalent to
|
||||
function_that_returns_a_function(1)(100)
|
||||
```
|
||||
|
||||
Sometimes we want to pass the value into another position, in this case the `_` placeholder can be used to indicate where the value should be inserted.
|
||||
|
||||
```gleam
|
||||
100
|
||||
|> some_function(1, _, 2)
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
In this exercise, you are going to help high school sweethearts profess their love on social media by generating an ASCII heart with their initials:
|
||||
|
||||
```
|
||||
****** ******
|
||||
** ** ** **
|
||||
** ** ** **
|
||||
** * **
|
||||
** **
|
||||
** J. K. + M. B. **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
***
|
||||
*
|
||||
```
|
||||
|
||||
## 1. Get the name's first letter
|
||||
|
||||
Implement the `first_letter` function. It should take a name and return its first letter. It should clean up any unnecessary whitespace from the name.
|
||||
|
||||
```gleam
|
||||
first_letter("Jane")
|
||||
// -> "J"
|
||||
```
|
||||
|
||||
## 2. Format the first letter as an initial
|
||||
|
||||
Implement the `initial` function. It should take a name and return its first letter, uppercase, followed by a dot. Make sure to reuse `first_letter` that you defined in the previous step.
|
||||
|
||||
```gleam
|
||||
initial("Robert")
|
||||
// -> "R."
|
||||
```
|
||||
|
||||
## 3. Split the full name into the first name and the last name
|
||||
|
||||
Implement the `initials` function. It should take a full name, consisting of a first name and a last name separated by a space, and return the initials. Make sure to reuse `initial` that you defined in the previous step.
|
||||
|
||||
```gleam
|
||||
initials("Lance Green")
|
||||
// -> "L. G."
|
||||
```
|
||||
|
||||
## 4. Put the initials inside of the heart
|
||||
|
||||
Implement the `pair` function. It should take two full names and return the initials inside an ASCII heart. Make sure to reuse `initials` that you defined in the previous step.
|
||||
|
||||
```gleam
|
||||
pair("Blake Miller", "Riley Lewis")
|
||||
// -> "
|
||||
// ****** ******
|
||||
// ** ** ** **
|
||||
// ** ** ** **
|
||||
// ** * **
|
||||
// ** **
|
||||
// ** B. M. + R. L. **
|
||||
// ** **
|
||||
// ** **
|
||||
// ** **
|
||||
// ** **
|
||||
// ** **
|
||||
// ** **
|
||||
// ***
|
||||
// *
|
||||
// "
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
high-school-sweetheart/gleam.toml
Normal file
14
high-school-sweetheart/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "high_school_sweetheart"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
high-school-sweetheart/manifest.toml
Normal file
31
high-school-sweetheart/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
34
high-school-sweetheart/src/high_school_sweetheart.gleam
Normal file
34
high-school-sweetheart/src/high_school_sweetheart.gleam
Normal file
@@ -0,0 +1,34 @@
|
||||
import gleam/list
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
|
||||
pub fn first_letter(name: String) {
|
||||
name |> string.trim |> string.first |> result.unwrap("")
|
||||
}
|
||||
|
||||
pub fn initial(name: String) {
|
||||
name |> first_letter |> string.uppercase |> string.append(".")
|
||||
}
|
||||
|
||||
pub fn initials(full_name: String) {
|
||||
full_name |> string.split(" ") |> list.map(initial) |> string.join(" ")
|
||||
}
|
||||
|
||||
pub fn pair(full_name1: String, full_name2: String) {
|
||||
"
|
||||
****** ******
|
||||
** ** ** **
|
||||
** ** ** **
|
||||
** * **
|
||||
** **
|
||||
** " <> initials(full_name1) <> " + " <> initials(full_name2) <> " **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
***
|
||||
*
|
||||
"
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import high_school_sweetheart
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
pub fn first_letter_test() {
|
||||
high_school_sweetheart.first_letter("Mary")
|
||||
|> should.equal("M")
|
||||
}
|
||||
|
||||
pub fn first_letter_does_not_change_case_test() {
|
||||
high_school_sweetheart.first_letter("john")
|
||||
|> should.equal("j")
|
||||
}
|
||||
|
||||
pub fn first_letter_removes_whitespace_test() {
|
||||
high_school_sweetheart.first_letter("\n\t Sarah ")
|
||||
|> should.equal("S")
|
||||
}
|
||||
|
||||
pub fn initial_test() {
|
||||
high_school_sweetheart.initial("Betty")
|
||||
|> should.equal("B.")
|
||||
}
|
||||
|
||||
pub fn initial_uppercases_letter_test() {
|
||||
high_school_sweetheart.initial("james")
|
||||
|> should.equal("J.")
|
||||
}
|
||||
|
||||
pub fn initials_test() {
|
||||
high_school_sweetheart.initials("Linda Miller")
|
||||
|> should.equal("L. M.")
|
||||
}
|
||||
|
||||
pub fn pair_test() {
|
||||
high_school_sweetheart.pair("Avery Bryant", "Charlie Dixon")
|
||||
|> should.equal(
|
||||
"
|
||||
****** ******
|
||||
** ** ** **
|
||||
** ** ** **
|
||||
** * **
|
||||
** **
|
||||
** A. B. + C. D. **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
** **
|
||||
***
|
||||
*
|
||||
",
|
||||
)
|
||||
}
|
||||
24
high-score-board/.exercism/config.json
Normal file
24
high-score-board/.exercism/config.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/high_score_board.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/high_score_board_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"javascript/high-score-board"
|
||||
],
|
||||
"blurb": "Practice Gleam dicts by tracking high scores of an arcade game."
|
||||
}
|
||||
1
high-score-board/.exercism/metadata.json
Normal file
1
high-score-board/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"high-score-board","id":"51923a5987d74c51bcec5743a623c549","url":"https://exercism.org/tracks/gleam/exercises/high-score-board","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
high-score-board/.gitignore
vendored
Normal file
4
high-score-board/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
high-score-board/HELP.md
Normal file
32
high-score-board/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/high_score_board.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
29
high-score-board/HINTS.md
Normal file
29
high-score-board/HINTS.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Hints
|
||||
|
||||
## 1. Create a new high score board
|
||||
|
||||
- The [`dict.new`][new] and [`dict.from_list`][from_list] functions can be used to create a new dict.
|
||||
|
||||
## 2. Add players to a score board
|
||||
|
||||
- The [`dict.insert`][insert] function can be used to add a new key-value pair to a dict.
|
||||
|
||||
## 3. Remove players from a score board
|
||||
|
||||
- The [`dict.delete`][delete] function can be used to remove a key-value pair from a dict.
|
||||
|
||||
## 4. Increase a player's score
|
||||
|
||||
- The [`dict.get`][get] function can be used to get the value for a key in a dict.
|
||||
- The [`dict.insert`][insert] function can be used to overwrite an existing key-value pair in a dict.
|
||||
|
||||
## 5. Apply Monday bonus points
|
||||
|
||||
- The [`dict.map_values`][map_values] function can be used to modify all the values in a dict.
|
||||
|
||||
[new]: https://hexdocs.pm/gleam_stdlib/gleam/dict.html#new
|
||||
[get]: https://hexdocs.pm/gleam_stdlib/gleam/dict.html#get
|
||||
[insert]: https://hexdocs.pm/gleam_stdlib/gleam/dict.html#insert
|
||||
[delete]: https://hexdocs.pm/gleam_stdlib/gleam/dict.html#delete
|
||||
[from_list]: https://hexdocs.pm/gleam_stdlib/gleam/dict.html#from_list
|
||||
[map_values]: https://hexdocs.pm/gleam_stdlib/gleam/dict.html#map_values
|
||||
123
high-score-board/README.md
Normal file
123
high-score-board/README.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# High Score Board
|
||||
|
||||
Welcome to High Score Board on Exercism's Gleam 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
|
||||
|
||||
## Type Aliases
|
||||
|
||||
### Type aliases
|
||||
|
||||
A type alias can be used in Gleam to give a convenient name for an existing type that would be otherwise cumbersome to write.
|
||||
|
||||
```gleam
|
||||
pub type Headers =
|
||||
List(#(String, String))
|
||||
|
||||
pub fn html_headers() -> Headers {
|
||||
[
|
||||
#("content-type", "text/html"),
|
||||
#("x-frame-options", "DENY"),
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
When written with `pub type` the alias can be used outside of the module it is defined in. If `pub` is omitted then the alias is private and cannot be referenced in other modules.
|
||||
|
||||
## Dicts
|
||||
|
||||
Dicts in Gleam are the data structure for storing information in key-value pairs. In other languages, these might also be known as associative arrays, hashes, or dictionaries.
|
||||
|
||||
Any type can be used for the keys and values in a dict, and they do not guarantee the order of their entries when accessed or returned.
|
||||
|
||||
### Working with dicts
|
||||
|
||||
Dicts are created and manipulated using functions from the `gleam/dict` module.
|
||||
|
||||
```gleam
|
||||
// Create an empty dict
|
||||
let dict1 = dict.new()
|
||||
|
||||
// Create a dict with some values
|
||||
let dict2 = dict.from_list([
|
||||
#("name", "Gleam"),
|
||||
#("colour", "Pink"),
|
||||
])
|
||||
|
||||
// Add a value to a dict
|
||||
let dict3 = dict.insert(dict2, "website", "https://gleam.run")
|
||||
|
||||
// Get a value from a dict
|
||||
let name = dict.get(dict3, "name")
|
||||
// -> Ok("Gleam")
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
In this exercise, you are implementing a way to keep track of the high scores for the most popular game in your local arcade hall.
|
||||
|
||||
You have 5 functions to implement, mostly related to manipulating an object that holds high scores.
|
||||
|
||||
## 1. Create a new high score board
|
||||
|
||||
Create a function `create_score_board` that returns a dict that serves as a high score board.
|
||||
The keys of this object will be the names of the players, the values will be their scores.
|
||||
For testing purposes, you want to directly include one entry in the object.
|
||||
This initial entry should consist of `"The Best Ever"` as player name and `1_000_000` as score.
|
||||
|
||||
```gleam
|
||||
create_score_board()
|
||||
// returns an object with one initial entry
|
||||
```
|
||||
|
||||
## 2. Add players to a score board
|
||||
|
||||
To add a player to the high score board, define the function `add_player`.
|
||||
It accepts 3 parameters:
|
||||
|
||||
- The first parameter is an existing score board dict.
|
||||
- The second parameter is the name of a player as a string.
|
||||
- The third parameter is the score as an int.
|
||||
|
||||
The function returns a dict with the new player and score added.
|
||||
|
||||
## 3. Remove players from a score board
|
||||
|
||||
If players violate the rules of the arcade hall, they are manually removed from the high score board.
|
||||
Define `remove_player` which takes 2 parameters:
|
||||
|
||||
- The first parameter is an existing score board dict.
|
||||
- The second parameter is the name of the player as a string.
|
||||
|
||||
This function should return the dict without the player that was removed.
|
||||
|
||||
If the player was not on the board in the first place, nothing should happen to the board, it should be returned as is.
|
||||
|
||||
## 4. Increase a player's score
|
||||
|
||||
If a player finishes another game at the arcade hall, a certain amount of points will be added to the previous score on the board.
|
||||
Implement `update_score`, which takes 3 parameters:
|
||||
|
||||
- The first parameter is an existing score board dict.
|
||||
- The second parameter is the name of the player whose score should be increased.
|
||||
- The third parameter is the score that you wish to **add** to the stored high score.
|
||||
|
||||
The function should return a dict with the updated score.
|
||||
|
||||
If the player was not on the board in the first place, nothing should happen to the board, it should be returned as is.
|
||||
|
||||
## 5. Apply Monday bonus points
|
||||
|
||||
The arcade hall keeps a separate score board on Mondays.
|
||||
At the end of the day, each player on that board gets 100 additional points.
|
||||
|
||||
Implement the function `apply_monday_bonus` that accepts a score board.
|
||||
The function returns a dict with the bonus points added for each player that is listed on that board.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
high-score-board/gleam.toml
Normal file
14
high-score-board/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "high_score_board"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
high-score-board/manifest.toml
Normal file
31
high-score-board/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
35
high-score-board/src/high_score_board.gleam
Normal file
35
high-score-board/src/high_score_board.gleam
Normal file
@@ -0,0 +1,35 @@
|
||||
import gleam/dict.{type Dict}
|
||||
|
||||
pub type ScoreBoard =
|
||||
Dict(String, Int)
|
||||
|
||||
pub fn create_score_board() -> ScoreBoard {
|
||||
dict.from_list([#("The Best Ever", 1_000_000)])
|
||||
}
|
||||
|
||||
pub fn add_player(
|
||||
score_board: ScoreBoard,
|
||||
player: String,
|
||||
score: Int,
|
||||
) -> ScoreBoard {
|
||||
dict.insert(score_board, player, score)
|
||||
}
|
||||
|
||||
pub fn remove_player(score_board: ScoreBoard, player: String) -> ScoreBoard {
|
||||
dict.delete(score_board, player)
|
||||
}
|
||||
|
||||
pub fn update_score(
|
||||
score_board: ScoreBoard,
|
||||
player: String,
|
||||
points: Int,
|
||||
) -> ScoreBoard {
|
||||
case dict.get(score_board, player) {
|
||||
Error(_) -> score_board
|
||||
Ok(score) -> dict.insert(score_board, player, score + points)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_monday_bonus(score_board: ScoreBoard) -> ScoreBoard {
|
||||
dict.map_values(score_board, fn(_, score) { score + 100 })
|
||||
}
|
||||
76
high-score-board/test/high_score_board_test.gleam
Normal file
76
high-score-board/test/high_score_board_test.gleam
Normal file
@@ -0,0 +1,76 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import gleam/dict
|
||||
import high_score_board
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
pub fn create_score_board_test() {
|
||||
high_score_board.create_score_board()
|
||||
|> should.equal(dict.from_list([#("The Best Ever", 1_000_000)]))
|
||||
}
|
||||
|
||||
pub fn add_player_board_test() {
|
||||
[#("Amil Pastorius", 99_373), #("Min-seo Shin", 0)]
|
||||
|> dict.from_list
|
||||
|> high_score_board.add_player("Jessie Johnson", 1337)
|
||||
|> should.equal(
|
||||
dict.from_list([
|
||||
#("Amil Pastorius", 99_373),
|
||||
#("Min-seo Shin", 0),
|
||||
#("Jessie Johnson", 1337),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn remove_player_test() {
|
||||
[#("Amil Pastorius", 99_373), #("Min-seo Shin", 0), #("Jesse Johnson", 1337)]
|
||||
|> dict.from_list
|
||||
|> high_score_board.remove_player("Jesse Johnson")
|
||||
|> should.equal(
|
||||
dict.from_list([#("Amil Pastorius", 99_373), #("Min-seo Shin", 0)]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn remove_player_unknown_test() {
|
||||
let board =
|
||||
dict.from_list([
|
||||
#("Amil Pastorius", 99_373),
|
||||
#("Min-seo Shin", 0),
|
||||
#("Jesse Johnson", 1337),
|
||||
])
|
||||
|
||||
board
|
||||
|> high_score_board.remove_player("Bruno Santangelo")
|
||||
|> should.equal(board)
|
||||
}
|
||||
|
||||
pub fn update_score_test() {
|
||||
[#("Amil Pastorius", 99_373), #("Min-seo Shin", 0), #("Jesse Johnson", 1337)]
|
||||
|> dict.from_list
|
||||
|> high_score_board.update_score("Min-seo Shin", 1999)
|
||||
|> high_score_board.update_score("Jesse Johnson", 1337)
|
||||
|> high_score_board.update_score("Unknown player", 1)
|
||||
|> should.equal(
|
||||
dict.from_list([
|
||||
#("Amil Pastorius", 99_373),
|
||||
#("Min-seo Shin", 1999),
|
||||
#("Jesse Johnson", 2674),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn apply_monday_bonus_test() {
|
||||
[#("Amil Pastorius", 345), #("Min-seo Shin", 19), #("Jesse Johnson", 122)]
|
||||
|> dict.from_list
|
||||
|> high_score_board.apply_monday_bonus
|
||||
|> should.equal(
|
||||
dict.from_list([
|
||||
#("Amil Pastorius", 445),
|
||||
#("Min-seo Shin", 119),
|
||||
#("Jesse Johnson", 222),
|
||||
]),
|
||||
)
|
||||
}
|
||||
24
newsletter/.exercism/config.json
Normal file
24
newsletter/.exercism/config.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/newsletter.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/newsletter_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elixir/newsletter"
|
||||
],
|
||||
"blurb": "Learn about IO by sending out a newsletter."
|
||||
}
|
||||
1
newsletter/.exercism/metadata.json
Normal file
1
newsletter/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"newsletter","id":"ec3e4622cebd4906aff5b7b7f8a3e90b","url":"https://exercism.org/tracks/gleam/exercises/newsletter","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
6
newsletter/.gitignore
vendored
Normal file
6
newsletter/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
log.txt
|
||||
emails.txt
|
||||
32
newsletter/HELP.md
Normal file
32
newsletter/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/newsletter.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
24
newsletter/HINTS.md
Normal file
24
newsletter/HINTS.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Hints
|
||||
|
||||
## 1. Read email addresses from a file
|
||||
|
||||
- The [`simplifile.read` function][file-read] can be used to read the contents of a file.
|
||||
|
||||
## 2. Create a log file for writing
|
||||
|
||||
- The [`simplifile.create_file` function][file-create] can be used to create an empty file.
|
||||
|
||||
## 3. Log a sent email
|
||||
|
||||
- The [`simplifile.append` function][file-append] can be used to append text to a file.
|
||||
|
||||
## 5. Send the newsletter
|
||||
|
||||
- All the necessary operations on files were already implemented in the previous steps.
|
||||
- The [`result.try` function][result-try] and [`list.try_each` function][list-try-each] can be used to work with the `Result` type.
|
||||
|
||||
[file-read]: https://hexdocs.pm/simplifile/simplifile.html#read
|
||||
[file-create]: https://hexdocs.pm/simplifile/simplifile.html#create_file
|
||||
[file-append]: https://hexdocs.pm/simplifile/simplifile.html#append
|
||||
[result-try]: https://hexdocs.pm/gleam_stdlib/gleam/result.html#try
|
||||
[list-try-each]: https://hexdocs.pm/gleam_stdlib/gleam/list.html#try_each
|
||||
98
newsletter/README.md
Normal file
98
newsletter/README.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Newsletter
|
||||
|
||||
Welcome to Newsletter on Exercism's Gleam 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
|
||||
|
||||
## Nil
|
||||
|
||||
`Nil` in Gleam is a type with a single value, also called `Nil`. It is similar to `void` in other languages in that it is used when a function does not have any more suitable value to return.
|
||||
|
||||
```gleam
|
||||
io.println("Hello, Joe!")
|
||||
// -> Nil
|
||||
```
|
||||
|
||||
Values in Gleam are not "nil-able" or "nullable" like in some other languages. A value can only be `Nil` if it's type is `Nil`, and a value of any other type can never be `Nil`.
|
||||
|
||||
## IO
|
||||
|
||||
Like most programming languages Gleam has "side effects", so functions can read and change the state of the world, as well as returning a value.
|
||||
|
||||
The `gleam/io` module in the Gleam standard library provides functions for printing strings to the console.
|
||||
|
||||
```gleam
|
||||
io.println("Hello, Joe!")
|
||||
// Hello, Joe!
|
||||
// -> Nil
|
||||
```
|
||||
|
||||
Other packages may provide other IO functions, such as `simplifile`, a package which provides functions for reading and writing files.
|
||||
|
||||
```gleam
|
||||
simplifile.read("favourite-colour.txt")
|
||||
// -> Ok("Pink\n")
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
Boris is a big model train enthusiast and has decided to share their passion with the world by starting a newsletter. They'll start by sending the first issue of the newsletter to friends and acquaintances that share the hobby, their email addresses are stored in a text file.
|
||||
|
||||
Hint: Use the [simplifile](https://hexdocs.pm/simplifile/simplifile.html) module for file operations.
|
||||
|
||||
## 1. Read email addresses from a file
|
||||
|
||||
Implement the `read_emails` function. It takes a path string to a text file that contains email addresses separated by newlines, and returns a list of the email addresses from the file.
|
||||
|
||||
```gleam
|
||||
read_emails("/home/my_user/documents/model_train_friends_emails.txt")
|
||||
// -> Ok(["rick@example.com", "choochoo42@example.com", "anna@example.com"])
|
||||
```
|
||||
|
||||
## 2. Create a log file for writing
|
||||
|
||||
Sending an email is a task that might fail for many unpredictable reasons, like a typo in the email address or temporary network issues. To ensure that you can retry sending the emails to all your friends without sending duplicates, you need to log the email addresses that already received the email. For this, you'll need a log file.
|
||||
|
||||
Implement the `create_log_file` function. It takes a file path and creates a new empty file at that location.
|
||||
|
||||
```gleam
|
||||
create_log_file("/home/my_user/documents/newsletter_issue1_log.txt")
|
||||
// -> Ok(Nil)
|
||||
```
|
||||
|
||||
## 3. Log a sent email
|
||||
|
||||
Implement the `log_sent_email` function. It takes a path to a log file and a string with the email address. It writes the email address to the file, followed by a newline.
|
||||
|
||||
```gleam
|
||||
log_sent_email(
|
||||
"/home/my_user/documents/newsletter_issue1_log.txt",
|
||||
"joe@example.com",
|
||||
)
|
||||
// -> Ok(Nil)
|
||||
```
|
||||
|
||||
## 4. Send the newsletter
|
||||
|
||||
Now that you have all of the building blocks of the email sending procedure, you need to combine them together in a single function.
|
||||
|
||||
Implement the `send_newsletter` function. It takes a path of the file with email addresses, a path of a log file, and an anonymous function that sends an email to a given email address.
|
||||
|
||||
It should read all the email addresses from the given file and attempt to send an email to every one of them. If the anonymous function that sends the email returns an `Ok` value, write the email address to the log file. Make sure to do it as soon as the email is sent.
|
||||
|
||||
```gleam
|
||||
send_newsletter(
|
||||
"model_train_friends_emails.txt",
|
||||
"newsletter_issue1_log.txt",
|
||||
send_email,
|
||||
)
|
||||
// -> Ok(Nil)
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
newsletter/gleam.toml
Normal file
14
newsletter/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "newsletter"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
newsletter/manifest.toml
Normal file
31
newsletter/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
55
newsletter/src/newsletter.gleam
Normal file
55
newsletter/src/newsletter.gleam
Normal file
@@ -0,0 +1,55 @@
|
||||
import gleam/string
|
||||
import simplifile
|
||||
|
||||
pub fn read_emails(path: String) -> Result(List(String), Nil) {
|
||||
case simplifile.read(path) {
|
||||
Error(_) -> Error(Nil)
|
||||
Ok(content) ->
|
||||
string.trim(content)
|
||||
|> string.split("\n")
|
||||
|> Ok
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_log_file(path: String) -> Result(Nil, Nil) {
|
||||
case simplifile.create_file(path) {
|
||||
Error(_) -> Error(Nil)
|
||||
Ok(_) -> Ok(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_sent_email(path: String, email: String) -> Result(Nil, Nil) {
|
||||
case simplifile.append(path, email <> "\n") {
|
||||
Error(_) -> Error(Nil)
|
||||
Ok(_) -> Ok(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_newsletter(
|
||||
emails_path: String,
|
||||
log_path: String,
|
||||
send_email: fn(String) -> Result(Nil, Nil),
|
||||
) -> Result(Nil, Nil) {
|
||||
case create_log_file(log_path), read_emails(emails_path) {
|
||||
Ok(_), Ok(emails) -> send_emails_and_log(emails, send_email, log_path)
|
||||
_, _ -> Error(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
fn send_emails_and_log(
|
||||
emails: List(String),
|
||||
send_fn: fn(String) -> Result(Nil, Nil),
|
||||
log_path: String,
|
||||
) -> Result(Nil, Nil) {
|
||||
let _ = case emails {
|
||||
[] -> Ok(Nil)
|
||||
[email, ..rest] -> {
|
||||
let _ = case send_fn(email) {
|
||||
Error(_) -> Error(Nil)
|
||||
Ok(_) -> log_sent_email(log_path, email)
|
||||
}
|
||||
send_emails_and_log(rest, send_fn, log_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
// It should read all the email addresses from the given file and attempt to send an email to every one of them. If the anonymous function that sends the email returns an `Ok` value, write the email address to the log file. Make sure to do it as soon as the email is sent.
|
||||
85
newsletter/test/newsletter_test.gleam
Normal file
85
newsletter/test/newsletter_test.gleam
Normal file
@@ -0,0 +1,85 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import newsletter
|
||||
import simplifile
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
pub fn read_emails_test() {
|
||||
let emails =
|
||||
"lucy@example.com
|
||||
thomas@example.com
|
||||
sid@example.com
|
||||
"
|
||||
let assert Ok(_) = simplifile.write("emails.txt", emails)
|
||||
let assert Ok(emails) = newsletter.read_emails("emails.txt")
|
||||
emails
|
||||
|> should.equal(["lucy@example.com", "thomas@example.com", "sid@example.com"])
|
||||
}
|
||||
|
||||
pub fn create_log_file_test() {
|
||||
let _ = simplifile.delete("log.txt")
|
||||
let assert Ok(Nil) = newsletter.create_log_file("log.txt")
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("")
|
||||
}
|
||||
|
||||
pub fn log_sent_email_test() {
|
||||
let _ = simplifile.delete("log.txt")
|
||||
let assert Ok(Nil) = newsletter.create_log_file("log.txt")
|
||||
let assert Ok(Nil) =
|
||||
newsletter.log_sent_email("log.txt", "janice@example.com")
|
||||
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("janice@example.com\n")
|
||||
|
||||
let assert Ok(Nil) = newsletter.log_sent_email("log.txt", "joe@example.com")
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("janice@example.com\njoe@example.com\n")
|
||||
}
|
||||
|
||||
pub fn send_newsletter_test() {
|
||||
let _ = simplifile.delete("log.txt")
|
||||
let emails =
|
||||
"bushra@example.com
|
||||
abdi@example.com
|
||||
bell@example.com
|
||||
"
|
||||
let assert Ok(Nil) = simplifile.write("emails.txt", emails)
|
||||
|
||||
let send_email = fn(email) {
|
||||
case email {
|
||||
"bushra@example.com" -> {
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("")
|
||||
Ok(Nil)
|
||||
}
|
||||
"abdi@example.com" -> {
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("bushra@example.com\n")
|
||||
Error(Nil)
|
||||
}
|
||||
"bell@example.com" -> {
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("bushra@example.com\n")
|
||||
Ok(Nil)
|
||||
}
|
||||
_ -> panic as "Unexpected email given to send_email function"
|
||||
}
|
||||
}
|
||||
|
||||
let assert Ok(Nil) =
|
||||
newsletter.send_newsletter("emails.txt", "log.txt", send_email)
|
||||
|
||||
let assert Ok(log) = simplifile.read("log.txt")
|
||||
log
|
||||
|> should.equal("bushra@example.com\nbell@example.com\n")
|
||||
}
|
||||
26
resistor-color/.exercism/config.json
Normal file
26
resistor-color/.exercism/config.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"contributors": [
|
||||
"itsgreggreg"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/resistor_color.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/resistor_color_test.gleam"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"blurb": "Convert a resistor band's color to its numeric representation.",
|
||||
"source": "Maud de Vries, Erik Schierboom",
|
||||
"source_url": "https://github.com/exercism/problem-specifications/issues/1458"
|
||||
}
|
||||
1
resistor-color/.exercism/metadata.json
Normal file
1
resistor-color/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"resistor-color","id":"f06cbb641e8b4bb498e5670da2e735a5","url":"https://exercism.org/tracks/gleam/exercises/resistor-color","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
resistor-color/.gitignore
vendored
Normal file
4
resistor-color/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
resistor-color/HELP.md
Normal file
32
resistor-color/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/resistor_color.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
58
resistor-color/README.md
Normal file
58
resistor-color/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Resistor Color
|
||||
|
||||
Welcome to Resistor Color on Exercism's Gleam Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
If you want to build something using a Raspberry Pi, you'll probably use _resistors_.
|
||||
For this exercise, you need to know two things about them:
|
||||
|
||||
- Each resistor has a resistance value.
|
||||
- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read.
|
||||
|
||||
To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values.
|
||||
Each band has a position and a numeric value.
|
||||
|
||||
The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number.
|
||||
|
||||
In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands.
|
||||
|
||||
These colors are encoded as follows:
|
||||
|
||||
- black: 0
|
||||
- brown: 1
|
||||
- red: 2
|
||||
- orange: 3
|
||||
- yellow: 4
|
||||
- green: 5
|
||||
- blue: 6
|
||||
- violet: 7
|
||||
- grey: 8
|
||||
- white: 9
|
||||
|
||||
The goal of this exercise is to create a way:
|
||||
|
||||
- to look up the numerical value associated with a particular color band
|
||||
- to list the different band colors
|
||||
|
||||
Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array:
|
||||
Better Be Right Or Your Great Big Values Go Wrong.
|
||||
|
||||
More information on the color encoding of resistors can be found in the [Electronic color code Wikipedia article][e-color-code].
|
||||
|
||||
[e-color-code]: https://en.wikipedia.org/wiki/Electronic_color_code
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @itsgreggreg
|
||||
|
||||
### Based on
|
||||
|
||||
Maud de Vries, Erik Schierboom - https://github.com/exercism/problem-specifications/issues/1458
|
||||
14
resistor-color/gleam.toml
Normal file
14
resistor-color/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "resistor_color"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
resistor-color/manifest.toml
Normal file
31
resistor-color/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
42
resistor-color/src/resistor_color.gleam
Normal file
42
resistor-color/src/resistor_color.gleam
Normal file
@@ -0,0 +1,42 @@
|
||||
pub type Color {
|
||||
Black
|
||||
Brown
|
||||
Red
|
||||
Orange
|
||||
Yellow
|
||||
Green
|
||||
Blue
|
||||
Violet
|
||||
Grey
|
||||
White
|
||||
}
|
||||
|
||||
pub fn code(color: Color) -> Int {
|
||||
case find_index(colors(), fn(c) { c == color }) {
|
||||
Error(_) -> -1
|
||||
Ok(code) -> code
|
||||
}
|
||||
}
|
||||
|
||||
pub fn colors() -> List(Color) {
|
||||
[Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Grey, White]
|
||||
}
|
||||
|
||||
fn find_index(list: List(a), predicate: fn(a) -> Bool) -> Result(Int, Nil) {
|
||||
find_index_loop(list, predicate, 0)
|
||||
}
|
||||
|
||||
fn find_index_loop(
|
||||
list: List(a),
|
||||
predicate: fn(a) -> Bool,
|
||||
index: Int,
|
||||
) -> Result(Int, Nil) {
|
||||
case list {
|
||||
[] -> Error(Nil)
|
||||
[head, ..tail] ->
|
||||
case predicate(head) {
|
||||
True -> Ok(index)
|
||||
False -> find_index_loop(tail, predicate, index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
77
resistor-color/test/resistor_color_test.gleam
Normal file
77
resistor-color/test/resistor_color_test.gleam
Normal file
@@ -0,0 +1,77 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import resistor_color.{
|
||||
Black, Blue, Brown, Green, Grey, Orange, Red, Violet, White, Yellow,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
pub fn black_test() {
|
||||
resistor_color.code(Black)
|
||||
|> should.equal(0)
|
||||
}
|
||||
|
||||
pub fn brown_test() {
|
||||
resistor_color.code(Brown)
|
||||
|> should.equal(1)
|
||||
}
|
||||
|
||||
pub fn red_test() {
|
||||
resistor_color.code(Red)
|
||||
|> should.equal(2)
|
||||
}
|
||||
|
||||
pub fn orange_test() {
|
||||
resistor_color.code(Orange)
|
||||
|> should.equal(3)
|
||||
}
|
||||
|
||||
pub fn yellow_test() {
|
||||
resistor_color.code(Yellow)
|
||||
|> should.equal(4)
|
||||
}
|
||||
|
||||
pub fn green_test() {
|
||||
resistor_color.code(Green)
|
||||
|> should.equal(5)
|
||||
}
|
||||
|
||||
pub fn blue_test() {
|
||||
resistor_color.code(Blue)
|
||||
|> should.equal(6)
|
||||
}
|
||||
|
||||
pub fn violet_test() {
|
||||
resistor_color.code(Violet)
|
||||
|> should.equal(7)
|
||||
}
|
||||
|
||||
pub fn grey_test() {
|
||||
resistor_color.code(Grey)
|
||||
|> should.equal(8)
|
||||
}
|
||||
|
||||
pub fn white_test() {
|
||||
resistor_color.code(White)
|
||||
|> should.equal(9)
|
||||
}
|
||||
|
||||
pub fn colors_test() {
|
||||
let colors = [
|
||||
Black,
|
||||
Brown,
|
||||
Red,
|
||||
Orange,
|
||||
Yellow,
|
||||
Green,
|
||||
Blue,
|
||||
Violet,
|
||||
Grey,
|
||||
White,
|
||||
]
|
||||
|
||||
resistor_color.colors()
|
||||
|> should.equal(colors)
|
||||
}
|
||||
22
robot-simulator/.exercism/config.json
Normal file
22
robot-simulator/.exercism/config.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"authors": [
|
||||
"jiegillet"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/robot_simulator.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/robot_simulator_test.gleam"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"blurb": "Write a robot simulator.",
|
||||
"source": "Inspired by an interview question at a famous company."
|
||||
}
|
||||
1
robot-simulator/.exercism/metadata.json
Normal file
1
robot-simulator/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"robot-simulator","id":"09f398f0a29f4e6d9e8c542184b210a7","url":"https://exercism.org/tracks/gleam/exercises/robot-simulator","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
robot-simulator/.gitignore
vendored
Normal file
4
robot-simulator/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
robot-simulator/HELP.md
Normal file
32
robot-simulator/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/robot_simulator.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
40
robot-simulator/README.md
Normal file
40
robot-simulator/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Robot Simulator
|
||||
|
||||
Welcome to Robot Simulator on Exercism's Gleam Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Write a robot simulator.
|
||||
|
||||
A robot factory's test facility needs a program to verify robot movements.
|
||||
|
||||
The robots have three possible movements:
|
||||
|
||||
- turn right
|
||||
- turn left
|
||||
- advance
|
||||
|
||||
Robots are placed on a hypothetical infinite grid, facing a particular direction (north, east, south, or west) at a set of {x,y} coordinates,
|
||||
e.g., {3,8}, with coordinates increasing to the north and east.
|
||||
|
||||
The robot then receives a number of instructions, at which point the testing facility verifies the robot's new position, and in which direction it is pointing.
|
||||
|
||||
- The letter-string "RAALAL" means:
|
||||
- Turn right
|
||||
- Advance twice
|
||||
- Turn left
|
||||
- Advance once
|
||||
- Turn left yet again
|
||||
- Say a robot starts at {7, 3} facing north.
|
||||
Then running this stream of instructions should leave it at {9, 4} facing west.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @jiegillet
|
||||
|
||||
### Based on
|
||||
|
||||
Inspired by an interview question at a famous company.
|
||||
14
robot-simulator/gleam.toml
Normal file
14
robot-simulator/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "robot_simulator"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
robot-simulator/manifest.toml
Normal file
31
robot-simulator/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
84
robot-simulator/src/robot_simulator.gleam
Normal file
84
robot-simulator/src/robot_simulator.gleam
Normal file
@@ -0,0 +1,84 @@
|
||||
import gleam/io
|
||||
import gleam/string
|
||||
|
||||
pub type Robot {
|
||||
Robot(direction: Direction, position: Position)
|
||||
}
|
||||
|
||||
pub type Direction {
|
||||
North
|
||||
East
|
||||
South
|
||||
West
|
||||
}
|
||||
|
||||
pub type Turn {
|
||||
Turn(left: Direction, right: Direction)
|
||||
}
|
||||
|
||||
pub type Position {
|
||||
Position(x: Int, y: Int)
|
||||
}
|
||||
|
||||
pub fn create(direction: Direction, position: Position) -> Robot {
|
||||
Robot(direction:, position:)
|
||||
}
|
||||
|
||||
pub fn move(
|
||||
direction: Direction,
|
||||
position: Position,
|
||||
instructions: String,
|
||||
) -> Robot {
|
||||
string.split(instructions, "")
|
||||
|> move_loop(#(direction, position))
|
||||
|> fn(dp) { Robot(dp.0, dp.1) }
|
||||
}
|
||||
|
||||
fn move_loop(
|
||||
instructions: List(String),
|
||||
dp: #(Direction, Position),
|
||||
) -> #(Direction, Position) {
|
||||
io.debug(instructions)
|
||||
io.debug(dp)
|
||||
case instructions {
|
||||
[] -> dp
|
||||
[head, ..tail] -> handle_instruction(head, dp) |> move_loop(tail, _)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_instruction(
|
||||
instruction: String,
|
||||
dp: #(Direction, Position),
|
||||
) -> #(Direction, Position) {
|
||||
case instruction {
|
||||
"L" | "R" -> #(turn(dp.0, instruction), dp.1)
|
||||
"A" -> advance(dp)
|
||||
_ -> dp
|
||||
}
|
||||
}
|
||||
|
||||
fn turn(facing: Direction, to: String) -> Direction {
|
||||
let turn = case facing {
|
||||
North -> Turn(left: West, right: East)
|
||||
East -> Turn(left: North, right: South)
|
||||
South -> Turn(left: East, right: West)
|
||||
West -> Turn(left: South, right: North)
|
||||
}
|
||||
|
||||
case to {
|
||||
"L" -> turn.left
|
||||
"R" -> turn.right
|
||||
_ -> facing
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(dp: #(Direction, Position)) -> #(Direction, Position) {
|
||||
let #(facing, p) = dp
|
||||
case facing {
|
||||
North -> Position(..p, y: p.y + 1)
|
||||
East -> Position(..p, x: p.x + 1)
|
||||
South -> Position(..p, y: p.y - 1)
|
||||
West -> Position(..p, x: p.x - 1)
|
||||
}
|
||||
|> fn(updated_position: Position) { #(facing, updated_position) }
|
||||
}
|
||||
97
robot-simulator/test/robot_simulator_test.gleam
Normal file
97
robot-simulator/test/robot_simulator_test.gleam
Normal file
@@ -0,0 +1,97 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import robot_simulator.{East, North, Position, Robot, South, West}
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
pub fn create_robot_at_origin_facing_north_test() {
|
||||
robot_simulator.create(North, Position(x: 0, y: 0))
|
||||
|> should.equal(Robot(North, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn create_robot_at_negative_position_facing_south_test() {
|
||||
robot_simulator.create(South, Position(x: -1, y: -1))
|
||||
|> should.equal(Robot(South, Position(x: -1, y: -1)))
|
||||
}
|
||||
|
||||
pub fn rotating_clockwise_changes_north_to_east_test() {
|
||||
robot_simulator.move(North, Position(x: 0, y: 0), "R")
|
||||
|> should.equal(Robot(East, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_clockwise_changes_east_to_south_test() {
|
||||
robot_simulator.move(East, Position(x: 0, y: 0), "R")
|
||||
|> should.equal(Robot(South, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_clockwise_changes_south_to_west_test() {
|
||||
robot_simulator.move(South, Position(x: 0, y: 0), "R")
|
||||
|> should.equal(Robot(West, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_clockwise_changes_west_to_north_test() {
|
||||
robot_simulator.move(West, Position(x: 0, y: 0), "R")
|
||||
|> should.equal(Robot(North, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_counter_clockwise_changes_north_to_west_test() {
|
||||
robot_simulator.move(North, Position(x: 0, y: 0), "L")
|
||||
|> should.equal(Robot(West, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_counter_clockwise_changes_west_to_south_test() {
|
||||
robot_simulator.move(West, Position(x: 0, y: 0), "L")
|
||||
|> should.equal(Robot(South, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_counter_clockwise_changes_south_to_east_test() {
|
||||
robot_simulator.move(South, Position(x: 0, y: 0), "L")
|
||||
|> should.equal(Robot(East, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn rotating_counter_clockwise_changes_east_to_north_test() {
|
||||
robot_simulator.move(East, Position(x: 0, y: 0), "L")
|
||||
|> should.equal(Robot(North, Position(x: 0, y: 0)))
|
||||
}
|
||||
|
||||
pub fn moving_forward_one_facing_north_increments_y_test() {
|
||||
robot_simulator.move(North, Position(x: 0, y: 0), "A")
|
||||
|> should.equal(Robot(North, Position(x: 0, y: 1)))
|
||||
}
|
||||
|
||||
pub fn moving_forward_one_facing_south_decrements_y_test() {
|
||||
robot_simulator.move(South, Position(x: 0, y: 0), "A")
|
||||
|> should.equal(Robot(South, Position(x: 0, y: -1)))
|
||||
}
|
||||
|
||||
pub fn moving_forward_one_facing_east_increments_x_test() {
|
||||
robot_simulator.move(East, Position(x: 0, y: 0), "A")
|
||||
|> should.equal(Robot(East, Position(x: 1, y: 0)))
|
||||
}
|
||||
|
||||
pub fn moving_forward_one_facing_west_decrements_x_test() {
|
||||
robot_simulator.move(West, Position(x: 0, y: 0), "A")
|
||||
|> should.equal(Robot(West, Position(x: -1, y: 0)))
|
||||
}
|
||||
|
||||
pub fn follow_series_of_instructions_moving_east_and_north_from_readme_test() {
|
||||
robot_simulator.move(North, Position(x: 7, y: 3), "RAALAL")
|
||||
|> should.equal(Robot(West, Position(x: 9, y: 4)))
|
||||
}
|
||||
|
||||
pub fn follow_series_of_instructions_moving_west_and_north_test() {
|
||||
robot_simulator.move(North, Position(x: 0, y: 0), "LAAARALA")
|
||||
|> should.equal(Robot(West, Position(x: -4, y: 1)))
|
||||
}
|
||||
|
||||
pub fn follow_series_of_instructions_moving_west_and_south_test() {
|
||||
robot_simulator.move(East, Position(x: 2, y: -7), "RRAAAAALA")
|
||||
|> should.equal(Robot(South, Position(x: -3, y: -8)))
|
||||
}
|
||||
|
||||
pub fn follow_series_of_instructions_moving_east_and_north_test() {
|
||||
robot_simulator.move(South, Position(x: 8, y: 4), "LAAARRRALLLL")
|
||||
|> should.equal(Robot(North, Position(x: 11, y: 5)))
|
||||
}
|
||||
24
secure-treasure-chest/.exercism/config.json
Normal file
24
secure-treasure-chest/.exercism/config.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/secure_treasure_chest.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/secure_treasure_chest_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elm/secure-treasure-chest"
|
||||
],
|
||||
"blurb": "Learn about opaque types by making a more secure treasure chest"
|
||||
}
|
||||
1
secure-treasure-chest/.exercism/metadata.json
Normal file
1
secure-treasure-chest/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"secure-treasure-chest","id":"c5dbff3c2a1342d389388a95cc2a7f88","url":"https://exercism.org/tracks/gleam/exercises/secure-treasure-chest","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
secure-treasure-chest/.gitignore
vendored
Normal file
4
secure-treasure-chest/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
secure-treasure-chest/HELP.md
Normal file
32
secure-treasure-chest/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/secure_treasure_chest.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
15
secure-treasure-chest/HINTS.md
Normal file
15
secure-treasure-chest/HINTS.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Hints
|
||||
|
||||
## 1. Define the `TreasureChest` opaque type.
|
||||
|
||||
- Opaque types are defined using the `opaque` keyword.
|
||||
|
||||
## 2. Define the `create` function.
|
||||
|
||||
- The [`string.length` function][length] can be used to get the length of a string.
|
||||
|
||||
## 3. Define `open` function.
|
||||
|
||||
- The `==` operator can be used to compare two strings for equality.
|
||||
|
||||
[length]: https://hexdocs.pm/gleam_stdlib/gleam/string.html#length
|
||||
79
secure-treasure-chest/README.md
Normal file
79
secure-treasure-chest/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Secure Treasure Chest
|
||||
|
||||
Welcome to Secure Treasure Chest on Exercism's Gleam 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
|
||||
|
||||
## Opaque Types
|
||||
|
||||
Opaque types in Gleam are custom types where only the module that defines the type can construct or pattern match values of the type. This is useful for creating types that should only be used in a specific way.
|
||||
|
||||
Opaque types are defined using the `opaque` keyword.
|
||||
|
||||
```gleam
|
||||
pub opaque type PositiveInt {
|
||||
PositiveInt(inner: Int)
|
||||
}
|
||||
```
|
||||
|
||||
This `PositiveInt` type is to be used in situations where an int is wanted, but it has to be zero or greater. A regular Gleam `Int` could not be used as they can also be negative.
|
||||
|
||||
The module that defines this type can define a function to get the inner int value, and a function for creating the `PositiveInt` type which will return an error if the value is not positive.
|
||||
|
||||
```gleam
|
||||
pub fn from_int(i: Int) -> Result(PositiveInt, String) {
|
||||
case i {
|
||||
_ if i < 0 -> Error("Value must be positive")
|
||||
_ -> Ok(PositiveInt(i))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_int(i: PositiveInt) -> Int {
|
||||
i.inner
|
||||
}
|
||||
```
|
||||
|
||||
With this API other modules cannot construct a `PositiveInt` with a negative value, so any function that takes a `PositiveInt` can be sure that the value is positive.
|
||||
|
||||
## Instructions
|
||||
|
||||
Sharp eyed students will have noticed that the `TreasureChest` type in the previous exercise wasn't that secure!
|
||||
|
||||
If you used the `get_treasure` function you had to supply the password, but you could still destructure the `TreasureChest` type to get the treasure without having to know the password.
|
||||
|
||||
Let's fix that by using an Opaque Type.
|
||||
|
||||
## 1. Define the `TreasureChest` opaque type.
|
||||
|
||||
The `TreasureChest` contains two fields:
|
||||
- A password that is a `String`.
|
||||
- A treasure that is a generic type.
|
||||
|
||||
The `TreasureChest` type must be opaque.
|
||||
|
||||
## 2. Define the `create` function.
|
||||
|
||||
This function takes two arguments:
|
||||
- A password `String`.
|
||||
- A treasure value of any type.
|
||||
|
||||
The function returns a `TreasureChest` containing the password and the value.
|
||||
|
||||
If the password is shorter than 8 characters then the function should return an error saying `Password must be at least 8 characters long`.
|
||||
|
||||
## 3. Define `open` function.
|
||||
|
||||
This function takes two arguments:
|
||||
|
||||
- A `TreasureChest`.
|
||||
- A password `String`.
|
||||
|
||||
If the password matches the password in the `TreasureChest` then the function should return the treasure, otherwise it should return an error saying `Incorrect password`.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
secure-treasure-chest/gleam.toml
Normal file
14
secure-treasure-chest/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "secure_treasure_chest"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
secure-treasure-chest/manifest.toml
Normal file
31
secure-treasure-chest/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
25
secure-treasure-chest/src/secure_treasure_chest.gleam
Normal file
25
secure-treasure-chest/src/secure_treasure_chest.gleam
Normal file
@@ -0,0 +1,25 @@
|
||||
import gleam/string
|
||||
|
||||
pub opaque type TreasureChest(a) {
|
||||
TreasureChest(password: String, treasure: a)
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
password: String,
|
||||
contents: treasure,
|
||||
) -> Result(TreasureChest(treasure), String) {
|
||||
case string.length(password) {
|
||||
pass if pass >= 8 -> Ok(TreasureChest(password, contents))
|
||||
_ -> Error("Password must be at least 8 characters long")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(
|
||||
chest: TreasureChest(treasure),
|
||||
password: String,
|
||||
) -> Result(treasure, String) {
|
||||
case chest.password == password {
|
||||
False -> Error("Incorrect password")
|
||||
True -> Ok(chest.treasure)
|
||||
}
|
||||
}
|
||||
55
secure-treasure-chest/test/secure_treasure_chest_test.gleam
Normal file
55
secure-treasure-chest/test/secure_treasure_chest_test.gleam
Normal file
@@ -0,0 +1,55 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import gleam/string
|
||||
import secure_treasure_chest
|
||||
import simplifile
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
fn compact_whitespace(graphemes: List(String), acc: String) -> String {
|
||||
case graphemes {
|
||||
[] -> acc
|
||||
[" ", " ", ..rest] -> compact_whitespace([" ", ..rest], acc)
|
||||
[grapheme, ..rest] -> compact_whitespace(rest, acc <> grapheme)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_source() -> String {
|
||||
let assert Ok(src) = simplifile.read("src/secure_treasure_chest.gleam")
|
||||
compact_whitespace(string.to_graphemes(src), "")
|
||||
}
|
||||
|
||||
pub fn type_must_be_opaque_test() {
|
||||
let src = read_source()
|
||||
case string.contains(src, "pub opaque type TreasureChest") {
|
||||
True -> Nil
|
||||
False -> panic as "The TreasureChest type must exist and be opaque"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_is_ok_with_long_password_test() {
|
||||
let assert Ok(_) = secure_treasure_chest.create("12345678", "My treasure")
|
||||
}
|
||||
|
||||
pub fn create_is_error_with_short_password_test() {
|
||||
secure_treasure_chest.create("1234567", "My treasure")
|
||||
|> should.equal(Error("Password must be at least 8 characters long"))
|
||||
}
|
||||
|
||||
pub fn open_is_ok_with_the_correct_password_test() {
|
||||
let assert Ok(chest) = secure_treasure_chest.create("wwwibble", 100)
|
||||
secure_treasure_chest.open(chest, "wwwibble")
|
||||
|> should.equal(Ok(100))
|
||||
|
||||
let assert Ok(chest) = secure_treasure_chest.create("wwwobble", 1.5)
|
||||
secure_treasure_chest.open(chest, "wwwobble")
|
||||
|> should.equal(Ok(1.5))
|
||||
}
|
||||
|
||||
pub fn open_is_an_error_with_an_incorrect_password_test() {
|
||||
let assert Ok(chest) = secure_treasure_chest.create("wwwibble", 100)
|
||||
secure_treasure_chest.open(chest, "wwwobble")
|
||||
|> should.equal(Error("Incorrect password"))
|
||||
}
|
||||
25
tisbury-treasure-hunt/.exercism/config.json
Normal file
25
tisbury-treasure-hunt/.exercism/config.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/tisbury_treasure_hunt.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/tisbury_treasure_hunt_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elm/tisbury-treasure-hunt",
|
||||
"fsharp/tisbury-treasure-hunt"
|
||||
],
|
||||
"blurb": "Learn usage of Tuples by designing a pirate treasure game"
|
||||
}
|
||||
1
tisbury-treasure-hunt/.exercism/metadata.json
Normal file
1
tisbury-treasure-hunt/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"tisbury-treasure-hunt","id":"44a79fd118554307960fba0f9a0d6637","url":"https://exercism.org/tracks/gleam/exercises/tisbury-treasure-hunt","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
4
tisbury-treasure-hunt/.gitignore
vendored
Normal file
4
tisbury-treasure-hunt/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.beam
|
||||
*.ez
|
||||
build
|
||||
erl_crash.dump
|
||||
32
tisbury-treasure-hunt/HELP.md
Normal file
32
tisbury-treasure-hunt/HELP.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests, run the command `gleam test` from within the exercise directory.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit src/tisbury_treasure_hunt.gleam` 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 [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
|
||||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
|
||||
- [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.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
|
||||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
13
tisbury-treasure-hunt/HINTS.md
Normal file
13
tisbury-treasure-hunt/HINTS.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Hints
|
||||
|
||||
## 1. Convert locations
|
||||
|
||||
- Elements can be accessed from a tuple using pattern matching or indexing.
|
||||
|
||||
## 2. Compare treasure and place locations
|
||||
|
||||
- Tuples can be compared for equality if they have the same length and the same types in the same order.
|
||||
|
||||
## 3. Count treasure locations
|
||||
|
||||
- The `filter` function from the `gleam/list` module can be used to remove elements from a list based on a function that returns a bool.
|
||||
155
tisbury-treasure-hunt/README.md
Normal file
155
tisbury-treasure-hunt/README.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# Tisbury Treasure Hunt
|
||||
|
||||
Welcome to Tisbury Treasure Hunt on Exercism's Gleam 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
|
||||
|
||||
## Tuples
|
||||
|
||||
A tuple is an ordered container of values. Like all Gleam data types tuples are immutable.
|
||||
Each element of a tuple can be of a different type -- they can even be other tuples.
|
||||
|
||||
Tuples are defined as comma-separated values between `#(` and `)`: `#(1, 2.0, "Three")`.
|
||||
|
||||
```gleam
|
||||
#("one", 2) // Tuple pair (2 values)
|
||||
#("one", 2, 3.0) // Tuple triplet (3 values)
|
||||
```
|
||||
|
||||
Tuples with the same length and the same types (in the same order) can be compared for equality.
|
||||
|
||||
```gleam
|
||||
#(1, 2) == #(1, 2) // Same length, same types, same values, same order
|
||||
// -> True
|
||||
|
||||
#(1, 2) == #(2, 1) // Same length, same types, same values, different order
|
||||
// -> False
|
||||
|
||||
#(1, 2) == #(1, "2") // Same length, different types
|
||||
// Compile error!
|
||||
|
||||
#(1, 2) == #(1, 2, 3) // Different length
|
||||
// Compile error!
|
||||
```
|
||||
|
||||
There are three ways in which you can get the contained values out of a tuple:
|
||||
|
||||
- Indexing.
|
||||
- Pattern matching with `let`.
|
||||
- Pattern matching with `case`.
|
||||
|
||||
```gleam
|
||||
let person = #("Jordan", 170)
|
||||
|
||||
// Option 1: Indexing
|
||||
person.0 // -> "Jordan"
|
||||
person.1 // -> 170
|
||||
|
||||
// Option 2: let
|
||||
let #(name2, length2) = person
|
||||
// -> name2 = "Jordan"
|
||||
// -> length2 = 170
|
||||
|
||||
// Option 3: case
|
||||
case person {
|
||||
#(name3, length3) -> {
|
||||
name3 // -> "Jordan"
|
||||
length3 // -> 170
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
Aazra and Rui are designing a pirate-themed treasure hunt. There is a list of treasures with map locations, the other a list of place names with map locations.
|
||||
|
||||
<table>
|
||||
<tr><th>Azara's List</th><th></th><th>Rui's List</th></tr>
|
||||
<tr><td>
|
||||
|
||||
| Treasure | Location |
|
||||
| --------------------------- | -------- |
|
||||
| Amethyst Octopus | (1, F) |
|
||||
| Angry Monkey Figurine | (5, B) |
|
||||
| Antique Glass Fishnet Float | (3, D) |
|
||||
| Brass Spyglass | (4, B) |
|
||||
| Carved Wooden Elephant | (8, C) |
|
||||
| Crystal Crab | (6, A) |
|
||||
| Glass Starfish | (6, D) |
|
||||
| Model Ship in Large Bottle | (8, A) |
|
||||
| Pirate Flag | (7, F) |
|
||||
| Robot Parrot | (1, C) |
|
||||
| Scrimshaw Whale's Tooth | (1, F) |
|
||||
| Silver Seahorse | (4, E) |
|
||||
| Vintage Pirate Hat | (7, E) |
|
||||
|
||||
</td><td></td><td>
|
||||
|
||||
| Place Name | Location | Quadrant |
|
||||
| ------------------------------------- | -------- | -------- |
|
||||
| Seaside Cottages | (C, 1) | Blue |
|
||||
| Aqua Lagoon (Island of Mystery) | (F, 1) | Yellow |
|
||||
| Deserted Docks | (A, 2) | Blue |
|
||||
| Spiky Rocks | (D, 3) | Yellow |
|
||||
| Abandoned Lighthouse | (B, 4) | Blue |
|
||||
| Hidden Spring (Island of Mystery) | (E, 4) | Yellow |
|
||||
| Stormy Breakwater | (B, 5) | Purple |
|
||||
| Old Schooner | (A, 6) | Purple |
|
||||
| Tangled Seaweed Patch | (D, 6) | Orange |
|
||||
| Quiet Inlet (Island of Mystery) | (E, 7) | Orange |
|
||||
| Windswept Hilltop (Island of Mystery) | (F, 7) | Orange |
|
||||
| Harbor Managers Office | (A, 8) | Purple |
|
||||
| Foggy Seacave | (C, 8) | Purple |
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
But things are a bit disorganized: Aazra's coordinates appear to be formatted and sorted differently from Rui's, and they have to keep looking from one list to the other to figure out which treasures go with which locations. Being budding Gleamlins, they have come to you for help in writing a small program (a set of functions, really) to better organize their hunt information.
|
||||
|
||||
## 1. Convert locations
|
||||
|
||||
Implement the `place_location_to_treasure_location` function that takes a place Location (such as `#("C", 1)`) and converts it to a treasure location (such as `#(1, "C")`).
|
||||
|
||||
```gleam
|
||||
place_location_to_treasure_location(#("C", 1))
|
||||
// -> #(1, "C")
|
||||
```
|
||||
|
||||
## 2. Compare treasure and place locations
|
||||
|
||||
Implement the `treasure_location_matches_place_location` function that takes a place location (such as `#("C", 1)`) and returns `True` if it matches a treasure location (such as `#(1, "C")`).
|
||||
|
||||
```gleam
|
||||
treasure_location_matches_place_location(#("C", 1), #(1, "C"))
|
||||
// -> True
|
||||
|
||||
treasure_location_matches_place_location(#("C", 1), #(2, "C"))
|
||||
// -> False
|
||||
```
|
||||
|
||||
## 3. Count treasure locations
|
||||
|
||||
Implement the `count_place_treasures` function, that takes a place (such as `#("Aqua Lagoon (Island of Mystery)", #("F", 1))`), and the list of treasures, and returns the number of treasures that can be found there.
|
||||
|
||||
```gleam
|
||||
let place = #("Aqua Lagoon (Island of Mystery)", #("F", 1))
|
||||
|
||||
count_place_treasures(place, treasures)
|
||||
// -> 2
|
||||
```
|
||||
|
||||
## 4. Special Places
|
||||
|
||||
Implement the `special_case_swap_possible` function, which takes a treasure (such as `#("Amethyst Octopus", #(1, "F"))`), a Place (such as `#("Seaside Cottages", #("C", 1))`) and a desired treasure (such as `#("Crystal Crab", #(6, "A"))`), and returns `True` for the following combinations:
|
||||
|
||||
- The Brass Spyglass can be swapped for any other treasure at the Abandoned Lighthouse.
|
||||
- The Amethyst Octopus can be swapped for the Crystal Crab or the Glass Starfish at the Stormy Breakwater.
|
||||
- The Vintage Pirate Hat can be swapped for the Model Ship in Large Bottle or the Antique Glass Fishnet Float at the Harbor Managers Office.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @lpil
|
||||
14
tisbury-treasure-hunt/gleam.toml
Normal file
14
tisbury-treasure-hunt/gleam.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
name = "tisbury_treasure_hunt"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_otp = "~> 0.7 or ~> 1.0"
|
||||
gleam_stdlib = ">= 0.54.0 or ~> 1.0"
|
||||
simplifile = "~> 1.0"
|
||||
gleam_erlang = ">= 0.25.0 and < 1.0.0"
|
||||
gleam_yielder = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_regexp = ">= 1.1.0 and < 2.0.0"
|
||||
gleam_deque = ">= 1.0.0 and < 2.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
exercism_test_runner = "~> 1.9"
|
||||
31
tisbury-treasure-hunt/manifest.toml
Normal file
31
tisbury-treasure-hunt/manifest.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||
{ name = "exercism_test_runner", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "0B17BB25F2FF1E60266467C24FE0CA04005410306AA05E9A4B41B1852D72865C" },
|
||||
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
|
||||
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
|
||||
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
|
||||
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
|
||||
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
|
||||
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
|
||||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
|
||||
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
|
||||
{ name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" },
|
||||
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
|
||||
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
exercism_test_runner = { version = "~> 1.9" }
|
||||
gleam_deque = { version = ">= 1.0.0 and < 2.0.0" }
|
||||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
|
||||
gleam_otp = { version = "~> 0.7 or ~> 1.0" }
|
||||
gleam_regexp = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
gleam_stdlib = { version = ">= 0.54.0 or ~> 1.0" }
|
||||
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
|
||||
simplifile = { version = "~> 1.0" }
|
||||
48
tisbury-treasure-hunt/src/tisbury_treasure_hunt.gleam
Normal file
48
tisbury-treasure-hunt/src/tisbury_treasure_hunt.gleam
Normal file
@@ -0,0 +1,48 @@
|
||||
import gleam/list
|
||||
|
||||
pub fn place_location_to_treasure_location(
|
||||
place_location: #(String, Int),
|
||||
) -> #(Int, String) {
|
||||
#(place_location.1, place_location.0)
|
||||
}
|
||||
|
||||
pub fn treasure_location_matches_place_location(
|
||||
place_location: #(String, Int),
|
||||
treasure_location: #(Int, String),
|
||||
) -> Bool {
|
||||
place_location_to_treasure_location(place_location) == treasure_location
|
||||
}
|
||||
|
||||
pub fn count_place_treasures(
|
||||
place: #(String, #(String, Int)),
|
||||
treasures: List(#(String, #(Int, String))),
|
||||
) -> Int {
|
||||
treasures
|
||||
|> list.filter(fn(t) {
|
||||
treasure_location_matches_place_location(place.1, t.1)
|
||||
})
|
||||
|> list.length
|
||||
}
|
||||
|
||||
pub fn special_case_swap_possible(
|
||||
found_treasure: #(String, #(Int, String)),
|
||||
place: #(String, #(String, Int)),
|
||||
desired_treasure: #(String, #(Int, String)),
|
||||
) -> Bool {
|
||||
case found_treasure, desired_treasure, place {
|
||||
#("Brass Spyglass", _), _, #("Abandoned Lighthouse", _) -> True
|
||||
#("Amethyst Octopus", _), #("Crystal Crab", _), #("Stormy Breakwater", _) ->
|
||||
True
|
||||
#("Amethyst Octopus", _), #("Glass Starfish", _), #("Stormy Breakwater", _) ->
|
||||
True
|
||||
#("Vintage Pirate Hat", _),
|
||||
#("Model Ship in Large Bottle", _),
|
||||
#("Harbor Managers Office", _)
|
||||
-> True
|
||||
#("Vintage Pirate Hat", _),
|
||||
#("Antique Glass Fishnet Float", _),
|
||||
#("Harbor Managers Office", _)
|
||||
-> True
|
||||
_, _, _ -> False
|
||||
}
|
||||
}
|
||||
103
tisbury-treasure-hunt/test/tisbury_treasure_hunt_test.gleam
Normal file
103
tisbury-treasure-hunt/test/tisbury_treasure_hunt_test.gleam
Normal file
@@ -0,0 +1,103 @@
|
||||
import exercism/should
|
||||
import exercism/test_runner
|
||||
import tisbury_treasure_hunt
|
||||
|
||||
pub fn main() {
|
||||
test_runner.main()
|
||||
}
|
||||
|
||||
pub fn place_location_to_treasure_location_test() {
|
||||
tisbury_treasure_hunt.place_location_to_treasure_location(#("C", 1))
|
||||
|> should.equal(#(1, "C"))
|
||||
}
|
||||
|
||||
pub fn seaside_cottages_is_not_at_1f_test() {
|
||||
let assert False =
|
||||
tisbury_treasure_hunt.treasure_location_matches_place_location(#("C", 1), #(
|
||||
1,
|
||||
"F",
|
||||
))
|
||||
}
|
||||
|
||||
pub fn aqua_lagoon_is_at_1f_test() {
|
||||
let assert True =
|
||||
tisbury_treasure_hunt.treasure_location_matches_place_location(#("F", 1), #(
|
||||
1,
|
||||
"F",
|
||||
))
|
||||
}
|
||||
|
||||
pub fn places_should_know_how_many_treasures_are_available_test() {
|
||||
let treasures = [
|
||||
#("Amethyst Octopus", #(1, "F")),
|
||||
#("Scrimshaw Whale's Tooth", #(1, "F")),
|
||||
]
|
||||
let assert 2 =
|
||||
tisbury_treasure_hunt.count_place_treasures(
|
||||
#("Aqua Lagoon (Island of Mystery)", #("F", 1)),
|
||||
treasures,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn can_swap_amethyst_octopus_for_crystal_crab_at_stormy_breakwater_test() {
|
||||
let assert True =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Amethyst Octopus", #(1, "F")),
|
||||
#("Stormy Breakwater", #("B", 5)),
|
||||
#("Crystal Crab", #(6, "A")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn can_swap_amethyst_octopus_for_glass_starfish_at_stormy_breakwater_test() {
|
||||
let assert True =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Amethyst Octopus", #(1, "F")),
|
||||
#("Stormy Breakwater", #("B", 5)),
|
||||
#("Glass Starfish", #(6, "D")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cannot_swap_amethyst_octopus_for_angry_monkey_figurine_at_stormy_breakwater_test() {
|
||||
let assert False =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Amethyst Octopus", #(1, "F")),
|
||||
#("Stormy Breakwater", #("B", 5)),
|
||||
#("Angry Monkey Figurine", #(5, "B")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn can_swap_vintage_pirate_hat_for_model_ship_in_large_bottle_at_harbor_managers_office_test() {
|
||||
let assert True =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Vintage Pirate Hat", #(7, "E")),
|
||||
#("Harbor Managers Office", #("A", 8)),
|
||||
#("Model Ship in Large Bottle", #(8, "A")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn can_swap_vintage_pirate_hat_for_antique_glass_fishnet_float_at_harbor_managers_office_test() {
|
||||
let assert True =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Vintage Pirate Hat", #(7, "E")),
|
||||
#("Harbor Managers Office", #("A", 8)),
|
||||
#("Antique Glass Fishnet Float", #(3, "D")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cannot_swap_vintage_pirate_hat_for_carved_wooden_elephant_at_harbor_managers_office_test() {
|
||||
let assert False =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Vintage Pirate Hat", #(7, "E")),
|
||||
#("Harbor Managers Office", #("A", 8)),
|
||||
#("Carved Wooden Elephant", #(8, "C")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cannot_swap_vintage_pirate_hat_for_model_ship_in_large_bottle_at_old_schooner_test() {
|
||||
let assert False =
|
||||
tisbury_treasure_hunt.special_case_swap_possible(
|
||||
#("Vintage Pirate Hat", #(7, "E")),
|
||||
#("Old Schooner", #("A", 6)),
|
||||
#("Model Ship in Large Bottle", #(8, "A")),
|
||||
)
|
||||
}
|
||||
25
tracks-on-tracks-on-tracks/.exercism/config.json
Normal file
25
tracks-on-tracks-on-tracks/.exercism/config.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"authors": [
|
||||
"lpil"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"src/tracks_on_tracks_on_tracks.gleam"
|
||||
],
|
||||
"test": [
|
||||
"test/tracks_on_tracks_on_tracks_test.gleam"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/example.gleam"
|
||||
],
|
||||
"invalidator": [
|
||||
"gleam.toml",
|
||||
"manifest.toml"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"fsharp/tracks-on-tracks-on-tracks",
|
||||
"elm/tracks-on-tracks-on-tracks"
|
||||
],
|
||||
"blurb": "Learn abouts lists by keeping track of the programming languages you want to learn."
|
||||
}
|
||||
1
tracks-on-tracks-on-tracks/.exercism/metadata.json
Normal file
1
tracks-on-tracks-on-tracks/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"gleam","exercise":"tracks-on-tracks-on-tracks","id":"45633801cbc44ee598fd630722a10e7e","url":"https://exercism.org/tracks/gleam/exercises/tracks-on-tracks-on-tracks","handle":"fw353qwgs","is_requester":true,"auto_approve":false}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user