go
This commit is contained in:
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" }
|
||||
32
go/src/go.gleam
Normal file
32
go/src/go.gleam
Normal file
@@ -0,0 +1,32 @@
|
||||
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 {
|
||||
case rule2(game) |> rule1 |> result.try(rule3) |> result.try(rule4) {
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user