From 02481656966b0a8dfc95cf3c22bcc049660ff7d4 Mon Sep 17 00:00:00 2001 From: Federico Igne Date: Sat, 26 Dec 2020 17:48:38 +0000 Subject: Move Rust exercises in a subdirectory --- rust/armstrong-numbers/.exercism/metadata.json | 1 + rust/armstrong-numbers/.gitignore | 8 + rust/armstrong-numbers/Cargo.toml | 4 + rust/armstrong-numbers/README.md | 94 +++++ rust/armstrong-numbers/src/lib.rs | 15 + rust/armstrong-numbers/tests/armstrong-numbers.rs | 46 +++ rust/beer-song/.exercism/metadata.json | 1 + rust/beer-song/.gitignore | 8 + rust/beer-song/Cargo.toml | 7 + rust/beer-song/README.md | 401 +++++++++++++++++++++ rust/beer-song/src/intersperse.rs | 52 +++ rust/beer-song/src/lib.rs | 20 + rust/beer-song/tests/beer-song.rs | 31 ++ rust/bob/.exercism/metadata.json | 1 + rust/bob/.gitignore | 8 + rust/bob/Cargo.toml | 4 + rust/bob/README.md | 96 +++++ rust/bob/src/lib.rs | 75 ++++ rust/bob/tests/bob.rs | 179 +++++++++ rust/clock/.exercism/metadata.json | 1 + rust/clock/.gitignore | 8 + rust/clock/Cargo.toml | 6 + rust/clock/README.md | 102 ++++++ rust/clock/src/lib.rs | 44 +++ rust/clock/tests/clock.rs | 294 +++++++++++++++ rust/difference-of-squares/.exercism/metadata.json | 1 + rust/difference-of-squares/.gitignore | 8 + rust/difference-of-squares/Cargo.toml | 4 + rust/difference-of-squares/README.md | 97 +++++ rust/difference-of-squares/src/lib.rs | 14 + .../tests/difference-of-squares.rs | 46 +++ rust/dot-dsl/.exercism/metadata.json | 1 + rust/dot-dsl/.gitignore | 8 + rust/dot-dsl/Cargo.toml | 7 + rust/dot-dsl/README.md | 121 +++++++ rust/dot-dsl/src/lib.rs | 119 ++++++ rust/dot-dsl/tests/dot-dsl.rs | 138 +++++++ rust/gigasecond/.exercism/metadata.json | 1 + rust/gigasecond/.gitignore | 8 + rust/gigasecond/Cargo.toml | 8 + rust/gigasecond/README.md | 89 +++++ rust/gigasecond/src/lib.rs | 7 + rust/gigasecond/tests/gigasecond.rs | 51 +++ rust/grains/.exercism/metadata.json | 1 + rust/grains/.gitignore | 8 + rust/grains/Cargo.toml | 4 + rust/grains/README.md | 107 ++++++ rust/grains/src/lib.rs | 23 ++ rust/grains/tests/grains.rs | 65 ++++ rust/hello-world/.exercism/metadata.json | 1 + rust/hello-world/.gitignore | 8 + rust/hello-world/Cargo.toml | 4 + rust/hello-world/GETTING_STARTED.md | 92 +++++ rust/hello-world/README.md | 95 +++++ rust/hello-world/src/lib.rs | 5 + rust/hello-world/tests/hello-world.rs | 6 + rust/high-scores/.exercism/metadata.json | 1 + rust/high-scores/.gitignore | 8 + rust/high-scores/Cargo.toml | 6 + rust/high-scores/README.md | 95 +++++ rust/high-scores/src/lib.rs | 29 ++ rust/high-scores/tests/high-scores.rs | 68 ++++ rust/leap/.exercism/metadata.json | 1 + rust/leap/.gitignore | 8 + rust/leap/Cargo.toml | 4 + rust/leap/README.md | 105 ++++++ rust/leap/src/lib.rs | 3 + rust/leap/tests/leap.rs | 89 +++++ rust/matching-brackets/.exercism/metadata.json | 1 + rust/matching-brackets/.gitignore | 8 + rust/matching-brackets/Cargo.toml | 4 + rust/matching-brackets/README.md | 85 +++++ rust/matching-brackets/src/lib.rs | 12 + rust/matching-brackets/tests/matching-brackets.rs | 98 +++++ rust/nth-prime/.exercism/metadata.json | 1 + rust/nth-prime/.gitignore | 8 + rust/nth-prime/Cargo.toml | 6 + rust/nth-prime/README.md | 92 +++++ rust/nth-prime/src/lib.rs | 8 + rust/nth-prime/tests/nth-prime.rs | 21 ++ rust/nucleotide-count/.exercism/metadata.json | 1 + rust/nucleotide-count/.gitignore | 8 + rust/nucleotide-count/Cargo.toml | 7 + rust/nucleotide-count/README.md | 110 ++++++ rust/nucleotide-count/src/lib.rs | 21 ++ rust/nucleotide-count/tests/nucleotide-count.rs | 88 +++++ rust/paasio/.exercism/metadata.json | 1 + rust/paasio/.gitignore | 8 + rust/paasio/Cargo.toml | 4 + rust/paasio/README.md | 102 ++++++ rust/paasio/src/lib.rs | 82 +++++ rust/paasio/tests/paasio.rs | 192 ++++++++++ rust/pascals-triangle/.exercism/metadata.json | 1 + rust/pascals-triangle/.gitignore | 8 + rust/pascals-triangle/Cargo.toml | 4 + rust/pascals-triangle/README.md | 95 +++++ rust/pascals-triangle/src/lib.rs | 34 ++ rust/pascals-triangle/tests/pascals-triangle.rs | 96 +++++ rust/prime-factors/.exercism/metadata.json | 1 + rust/prime-factors/.gitignore | 8 + rust/prime-factors/Cargo.toml | 6 + rust/prime-factors/README.md | 110 ++++++ rust/prime-factors/src/lib.rs | 18 + rust/prime-factors/tests/prime-factors.rs | 36 ++ rust/proverb/.exercism/metadata.json | 1 + rust/proverb/.gitignore | 8 + rust/proverb/Cargo.toml | 6 + rust/proverb/README.md | 97 +++++ rust/proverb/src/lib.rs | 15 + rust/proverb/tests/proverb.rs | 70 ++++ rust/raindrops/.exercism/metadata.json | 1 + rust/raindrops/.gitignore | 8 + rust/raindrops/Cargo.toml | 4 + rust/raindrops/README.md | 96 +++++ rust/raindrops/src/lib.rs | 28 ++ rust/raindrops/tests/raindrops.rs | 96 +++++ rust/reverse-string/.exercism/metadata.json | 1 + rust/reverse-string/.gitignore | 8 + rust/reverse-string/Cargo.toml | 10 + rust/reverse-string/README.md | 103 ++++++ rust/reverse-string/src/lib.rs | 5 + rust/reverse-string/tests/reverse-string.rs | 62 ++++ rust/saddle-points/.exercism/metadata.json | 1 + rust/saddle-points/.gitignore | 8 + rust/saddle-points/Cargo.toml | 6 + rust/saddle-points/README.md | 132 +++++++ rust/saddle-points/src/lib.rs | 16 + rust/saddle-points/tests/saddle-points.rs | 98 +++++ rust/simple-linked-list/.exercism/metadata.json | 1 + rust/simple-linked-list/.gitignore | 8 + rust/simple-linked-list/Cargo.toml | 6 + rust/simple-linked-list/README.md | 137 +++++++ rust/simple-linked-list/src/lib.rs | 109 ++++++ .../simple-linked-list/tests/simple-linked-list.rs | 118 ++++++ rust/sum-of-multiples/.exercism/metadata.json | 1 + rust/sum-of-multiples/.gitignore | 8 + rust/sum-of-multiples/Cargo.toml | 4 + rust/sum-of-multiples/README.md | 89 +++++ rust/sum-of-multiples/src/lib.rs | 3 + rust/sum-of-multiples/tests/sum-of-multiples.rs | 81 +++++ 140 files changed, 5900 insertions(+) create mode 100644 rust/armstrong-numbers/.exercism/metadata.json create mode 100644 rust/armstrong-numbers/.gitignore create mode 100644 rust/armstrong-numbers/Cargo.toml create mode 100644 rust/armstrong-numbers/README.md create mode 100644 rust/armstrong-numbers/src/lib.rs create mode 100644 rust/armstrong-numbers/tests/armstrong-numbers.rs create mode 100644 rust/beer-song/.exercism/metadata.json create mode 100644 rust/beer-song/.gitignore create mode 100644 rust/beer-song/Cargo.toml create mode 100644 rust/beer-song/README.md create mode 100644 rust/beer-song/src/intersperse.rs create mode 100644 rust/beer-song/src/lib.rs create mode 100644 rust/beer-song/tests/beer-song.rs create mode 100644 rust/bob/.exercism/metadata.json create mode 100644 rust/bob/.gitignore create mode 100644 rust/bob/Cargo.toml create mode 100644 rust/bob/README.md create mode 100644 rust/bob/src/lib.rs create mode 100644 rust/bob/tests/bob.rs create mode 100644 rust/clock/.exercism/metadata.json create mode 100644 rust/clock/.gitignore create mode 100644 rust/clock/Cargo.toml create mode 100644 rust/clock/README.md create mode 100644 rust/clock/src/lib.rs create mode 100644 rust/clock/tests/clock.rs create mode 100644 rust/difference-of-squares/.exercism/metadata.json create mode 100644 rust/difference-of-squares/.gitignore create mode 100644 rust/difference-of-squares/Cargo.toml create mode 100644 rust/difference-of-squares/README.md create mode 100644 rust/difference-of-squares/src/lib.rs create mode 100644 rust/difference-of-squares/tests/difference-of-squares.rs create mode 100644 rust/dot-dsl/.exercism/metadata.json create mode 100644 rust/dot-dsl/.gitignore create mode 100644 rust/dot-dsl/Cargo.toml create mode 100644 rust/dot-dsl/README.md create mode 100644 rust/dot-dsl/src/lib.rs create mode 100644 rust/dot-dsl/tests/dot-dsl.rs create mode 100644 rust/gigasecond/.exercism/metadata.json create mode 100644 rust/gigasecond/.gitignore create mode 100644 rust/gigasecond/Cargo.toml create mode 100644 rust/gigasecond/README.md create mode 100644 rust/gigasecond/src/lib.rs create mode 100644 rust/gigasecond/tests/gigasecond.rs create mode 100644 rust/grains/.exercism/metadata.json create mode 100644 rust/grains/.gitignore create mode 100644 rust/grains/Cargo.toml create mode 100644 rust/grains/README.md create mode 100644 rust/grains/src/lib.rs create mode 100644 rust/grains/tests/grains.rs create mode 100644 rust/hello-world/.exercism/metadata.json create mode 100644 rust/hello-world/.gitignore create mode 100644 rust/hello-world/Cargo.toml create mode 100644 rust/hello-world/GETTING_STARTED.md create mode 100644 rust/hello-world/README.md create mode 100644 rust/hello-world/src/lib.rs create mode 100644 rust/hello-world/tests/hello-world.rs create mode 100644 rust/high-scores/.exercism/metadata.json create mode 100644 rust/high-scores/.gitignore create mode 100644 rust/high-scores/Cargo.toml create mode 100644 rust/high-scores/README.md create mode 100644 rust/high-scores/src/lib.rs create mode 100644 rust/high-scores/tests/high-scores.rs create mode 100644 rust/leap/.exercism/metadata.json create mode 100644 rust/leap/.gitignore create mode 100644 rust/leap/Cargo.toml create mode 100644 rust/leap/README.md create mode 100644 rust/leap/src/lib.rs create mode 100644 rust/leap/tests/leap.rs create mode 100644 rust/matching-brackets/.exercism/metadata.json create mode 100644 rust/matching-brackets/.gitignore create mode 100644 rust/matching-brackets/Cargo.toml create mode 100644 rust/matching-brackets/README.md create mode 100644 rust/matching-brackets/src/lib.rs create mode 100644 rust/matching-brackets/tests/matching-brackets.rs create mode 100644 rust/nth-prime/.exercism/metadata.json create mode 100644 rust/nth-prime/.gitignore create mode 100644 rust/nth-prime/Cargo.toml create mode 100644 rust/nth-prime/README.md create mode 100644 rust/nth-prime/src/lib.rs create mode 100644 rust/nth-prime/tests/nth-prime.rs create mode 100644 rust/nucleotide-count/.exercism/metadata.json create mode 100644 rust/nucleotide-count/.gitignore create mode 100644 rust/nucleotide-count/Cargo.toml create mode 100644 rust/nucleotide-count/README.md create mode 100644 rust/nucleotide-count/src/lib.rs create mode 100644 rust/nucleotide-count/tests/nucleotide-count.rs create mode 100644 rust/paasio/.exercism/metadata.json create mode 100644 rust/paasio/.gitignore create mode 100644 rust/paasio/Cargo.toml create mode 100644 rust/paasio/README.md create mode 100644 rust/paasio/src/lib.rs create mode 100644 rust/paasio/tests/paasio.rs create mode 100644 rust/pascals-triangle/.exercism/metadata.json create mode 100644 rust/pascals-triangle/.gitignore create mode 100644 rust/pascals-triangle/Cargo.toml create mode 100644 rust/pascals-triangle/README.md create mode 100644 rust/pascals-triangle/src/lib.rs create mode 100644 rust/pascals-triangle/tests/pascals-triangle.rs create mode 100644 rust/prime-factors/.exercism/metadata.json create mode 100644 rust/prime-factors/.gitignore create mode 100644 rust/prime-factors/Cargo.toml create mode 100644 rust/prime-factors/README.md create mode 100644 rust/prime-factors/src/lib.rs create mode 100644 rust/prime-factors/tests/prime-factors.rs create mode 100644 rust/proverb/.exercism/metadata.json create mode 100644 rust/proverb/.gitignore create mode 100644 rust/proverb/Cargo.toml create mode 100644 rust/proverb/README.md create mode 100644 rust/proverb/src/lib.rs create mode 100644 rust/proverb/tests/proverb.rs create mode 100644 rust/raindrops/.exercism/metadata.json create mode 100644 rust/raindrops/.gitignore create mode 100644 rust/raindrops/Cargo.toml create mode 100644 rust/raindrops/README.md create mode 100644 rust/raindrops/src/lib.rs create mode 100644 rust/raindrops/tests/raindrops.rs create mode 100644 rust/reverse-string/.exercism/metadata.json create mode 100644 rust/reverse-string/.gitignore create mode 100644 rust/reverse-string/Cargo.toml create mode 100644 rust/reverse-string/README.md create mode 100644 rust/reverse-string/src/lib.rs create mode 100644 rust/reverse-string/tests/reverse-string.rs create mode 100644 rust/saddle-points/.exercism/metadata.json create mode 100644 rust/saddle-points/.gitignore create mode 100644 rust/saddle-points/Cargo.toml create mode 100644 rust/saddle-points/README.md create mode 100644 rust/saddle-points/src/lib.rs create mode 100644 rust/saddle-points/tests/saddle-points.rs create mode 100644 rust/simple-linked-list/.exercism/metadata.json create mode 100644 rust/simple-linked-list/.gitignore create mode 100644 rust/simple-linked-list/Cargo.toml create mode 100644 rust/simple-linked-list/README.md create mode 100644 rust/simple-linked-list/src/lib.rs create mode 100644 rust/simple-linked-list/tests/simple-linked-list.rs create mode 100644 rust/sum-of-multiples/.exercism/metadata.json create mode 100644 rust/sum-of-multiples/.gitignore create mode 100644 rust/sum-of-multiples/Cargo.toml create mode 100644 rust/sum-of-multiples/README.md create mode 100644 rust/sum-of-multiples/src/lib.rs create mode 100644 rust/sum-of-multiples/tests/sum-of-multiples.rs (limited to 'rust') diff --git a/rust/armstrong-numbers/.exercism/metadata.json b/rust/armstrong-numbers/.exercism/metadata.json new file mode 100644 index 0000000..cfda14e --- /dev/null +++ b/rust/armstrong-numbers/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"armstrong-numbers","id":"f53447212bdd4e1c96e26911eb961199","url":"https://exercism.io/my/solutions/f53447212bdd4e1c96e26911eb961199","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/armstrong-numbers/.gitignore b/rust/armstrong-numbers/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/armstrong-numbers/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/armstrong-numbers/Cargo.toml b/rust/armstrong-numbers/Cargo.toml new file mode 100644 index 0000000..22e66de --- /dev/null +++ b/rust/armstrong-numbers/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "armstrong_numbers" +version = "1.1.0" diff --git a/rust/armstrong-numbers/README.md b/rust/armstrong-numbers/README.md new file mode 100644 index 0000000..6437ffe --- /dev/null +++ b/rust/armstrong-numbers/README.md @@ -0,0 +1,94 @@ +# Armstrong Numbers + +An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) +is a number that is the sum of its own digits each raised to the power +of the number of digits. + +For example: + +- 9 is an Armstrong number, because `9 = 9^1 = 9` +- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 1` +- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` +- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` + +Write some code to determine whether a number is an Armstrong number. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Narcissistic_number](https://en.wikipedia.org/wiki/Narcissistic_number) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/armstrong-numbers/src/lib.rs b/rust/armstrong-numbers/src/lib.rs new file mode 100644 index 0000000..41b0824 --- /dev/null +++ b/rust/armstrong-numbers/src/lib.rs @@ -0,0 +1,15 @@ + +fn digits(mut n: u32) -> (usize,Vec) { + let mut v = vec![]; + while n > 9 { + v.push(n % 10); + n /= 10; + } + v.push(n); + (v.len(),v) +} + +pub fn is_armstrong_number(num: u32) -> bool { + let (l,v) = digits(num); + v.iter().map(|x| x.pow(l as u32)).sum::() == num +} diff --git a/rust/armstrong-numbers/tests/armstrong-numbers.rs b/rust/armstrong-numbers/tests/armstrong-numbers.rs new file mode 100644 index 0000000..9ac51d0 --- /dev/null +++ b/rust/armstrong-numbers/tests/armstrong-numbers.rs @@ -0,0 +1,46 @@ +use armstrong_numbers::*; + +#[test] +fn test_zero_is_an_armstrong_number() { + assert!(is_armstrong_number(0)) +} + +#[test] +fn test_single_digit_numbers_are_armstrong_numbers() { + assert!(is_armstrong_number(5)) +} + +#[test] +fn test_there_are_no_2_digit_armstrong_numbers() { + assert!(!is_armstrong_number(10)) +} + +#[test] +fn test_three_digit_armstrong_number() { + assert!(is_armstrong_number(153)) +} + +#[test] +fn test_three_digit_non_armstrong_number() { + assert!(!is_armstrong_number(100)) +} + +#[test] +fn test_four_digit_armstrong_number() { + assert!(is_armstrong_number(9474)) +} + +#[test] +fn test_four_digit_non_armstrong_number() { + assert!(!is_armstrong_number(9475)) +} + +#[test] +fn test_seven_digit_armstrong_number() { + assert!(is_armstrong_number(9_926_315)) +} + +#[test] +fn test_seven_digit_non_armstrong_number() { + assert!(!is_armstrong_number(9_926_316)) +} diff --git a/rust/beer-song/.exercism/metadata.json b/rust/beer-song/.exercism/metadata.json new file mode 100644 index 0000000..640fbbc --- /dev/null +++ b/rust/beer-song/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"beer-song","id":"d7320f8ac9c543dc853815bbb5b4d4d5","url":"https://exercism.io/my/solutions/d7320f8ac9c543dc853815bbb5b4d4d5","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/beer-song/.gitignore b/rust/beer-song/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/beer-song/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/beer-song/Cargo.toml b/rust/beer-song/Cargo.toml new file mode 100644 index 0000000..ff6683e --- /dev/null +++ b/rust/beer-song/Cargo.toml @@ -0,0 +1,7 @@ +[package] +edition = "2018" +name = "beer-song" +version = "0.0.0" + +[dependencies] +itertools = "0.9" diff --git a/rust/beer-song/README.md b/rust/beer-song/README.md new file mode 100644 index 0000000..2ed305c --- /dev/null +++ b/rust/beer-song/README.md @@ -0,0 +1,401 @@ +# Beer Song + +Recite the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall. + +Note that not all verses are identical. + +```text +99 bottles of beer on the wall, 99 bottles of beer. +Take one down and pass it around, 98 bottles of beer on the wall. + +98 bottles of beer on the wall, 98 bottles of beer. +Take one down and pass it around, 97 bottles of beer on the wall. + +97 bottles of beer on the wall, 97 bottles of beer. +Take one down and pass it around, 96 bottles of beer on the wall. + +96 bottles of beer on the wall, 96 bottles of beer. +Take one down and pass it around, 95 bottles of beer on the wall. + +95 bottles of beer on the wall, 95 bottles of beer. +Take one down and pass it around, 94 bottles of beer on the wall. + +94 bottles of beer on the wall, 94 bottles of beer. +Take one down and pass it around, 93 bottles of beer on the wall. + +93 bottles of beer on the wall, 93 bottles of beer. +Take one down and pass it around, 92 bottles of beer on the wall. + +92 bottles of beer on the wall, 92 bottles of beer. +Take one down and pass it around, 91 bottles of beer on the wall. + +91 bottles of beer on the wall, 91 bottles of beer. +Take one down and pass it around, 90 bottles of beer on the wall. + +90 bottles of beer on the wall, 90 bottles of beer. +Take one down and pass it around, 89 bottles of beer on the wall. + +89 bottles of beer on the wall, 89 bottles of beer. +Take one down and pass it around, 88 bottles of beer on the wall. + +88 bottles of beer on the wall, 88 bottles of beer. +Take one down and pass it around, 87 bottles of beer on the wall. + +87 bottles of beer on the wall, 87 bottles of beer. +Take one down and pass it around, 86 bottles of beer on the wall. + +86 bottles of beer on the wall, 86 bottles of beer. +Take one down and pass it around, 85 bottles of beer on the wall. + +85 bottles of beer on the wall, 85 bottles of beer. +Take one down and pass it around, 84 bottles of beer on the wall. + +84 bottles of beer on the wall, 84 bottles of beer. +Take one down and pass it around, 83 bottles of beer on the wall. + +83 bottles of beer on the wall, 83 bottles of beer. +Take one down and pass it around, 82 bottles of beer on the wall. + +82 bottles of beer on the wall, 82 bottles of beer. +Take one down and pass it around, 81 bottles of beer on the wall. + +81 bottles of beer on the wall, 81 bottles of beer. +Take one down and pass it around, 80 bottles of beer on the wall. + +80 bottles of beer on the wall, 80 bottles of beer. +Take one down and pass it around, 79 bottles of beer on the wall. + +79 bottles of beer on the wall, 79 bottles of beer. +Take one down and pass it around, 78 bottles of beer on the wall. + +78 bottles of beer on the wall, 78 bottles of beer. +Take one down and pass it around, 77 bottles of beer on the wall. + +77 bottles of beer on the wall, 77 bottles of beer. +Take one down and pass it around, 76 bottles of beer on the wall. + +76 bottles of beer on the wall, 76 bottles of beer. +Take one down and pass it around, 75 bottles of beer on the wall. + +75 bottles of beer on the wall, 75 bottles of beer. +Take one down and pass it around, 74 bottles of beer on the wall. + +74 bottles of beer on the wall, 74 bottles of beer. +Take one down and pass it around, 73 bottles of beer on the wall. + +73 bottles of beer on the wall, 73 bottles of beer. +Take one down and pass it around, 72 bottles of beer on the wall. + +72 bottles of beer on the wall, 72 bottles of beer. +Take one down and pass it around, 71 bottles of beer on the wall. + +71 bottles of beer on the wall, 71 bottles of beer. +Take one down and pass it around, 70 bottles of beer on the wall. + +70 bottles of beer on the wall, 70 bottles of beer. +Take one down and pass it around, 69 bottles of beer on the wall. + +69 bottles of beer on the wall, 69 bottles of beer. +Take one down and pass it around, 68 bottles of beer on the wall. + +68 bottles of beer on the wall, 68 bottles of beer. +Take one down and pass it around, 67 bottles of beer on the wall. + +67 bottles of beer on the wall, 67 bottles of beer. +Take one down and pass it around, 66 bottles of beer on the wall. + +66 bottles of beer on the wall, 66 bottles of beer. +Take one down and pass it around, 65 bottles of beer on the wall. + +65 bottles of beer on the wall, 65 bottles of beer. +Take one down and pass it around, 64 bottles of beer on the wall. + +64 bottles of beer on the wall, 64 bottles of beer. +Take one down and pass it around, 63 bottles of beer on the wall. + +63 bottles of beer on the wall, 63 bottles of beer. +Take one down and pass it around, 62 bottles of beer on the wall. + +62 bottles of beer on the wall, 62 bottles of beer. +Take one down and pass it around, 61 bottles of beer on the wall. + +61 bottles of beer on the wall, 61 bottles of beer. +Take one down and pass it around, 60 bottles of beer on the wall. + +60 bottles of beer on the wall, 60 bottles of beer. +Take one down and pass it around, 59 bottles of beer on the wall. + +59 bottles of beer on the wall, 59 bottles of beer. +Take one down and pass it around, 58 bottles of beer on the wall. + +58 bottles of beer on the wall, 58 bottles of beer. +Take one down and pass it around, 57 bottles of beer on the wall. + +57 bottles of beer on the wall, 57 bottles of beer. +Take one down and pass it around, 56 bottles of beer on the wall. + +56 bottles of beer on the wall, 56 bottles of beer. +Take one down and pass it around, 55 bottles of beer on the wall. + +55 bottles of beer on the wall, 55 bottles of beer. +Take one down and pass it around, 54 bottles of beer on the wall. + +54 bottles of beer on the wall, 54 bottles of beer. +Take one down and pass it around, 53 bottles of beer on the wall. + +53 bottles of beer on the wall, 53 bottles of beer. +Take one down and pass it around, 52 bottles of beer on the wall. + +52 bottles of beer on the wall, 52 bottles of beer. +Take one down and pass it around, 51 bottles of beer on the wall. + +51 bottles of beer on the wall, 51 bottles of beer. +Take one down and pass it around, 50 bottles of beer on the wall. + +50 bottles of beer on the wall, 50 bottles of beer. +Take one down and pass it around, 49 bottles of beer on the wall. + +49 bottles of beer on the wall, 49 bottles of beer. +Take one down and pass it around, 48 bottles of beer on the wall. + +48 bottles of beer on the wall, 48 bottles of beer. +Take one down and pass it around, 47 bottles of beer on the wall. + +47 bottles of beer on the wall, 47 bottles of beer. +Take one down and pass it around, 46 bottles of beer on the wall. + +46 bottles of beer on the wall, 46 bottles of beer. +Take one down and pass it around, 45 bottles of beer on the wall. + +45 bottles of beer on the wall, 45 bottles of beer. +Take one down and pass it around, 44 bottles of beer on the wall. + +44 bottles of beer on the wall, 44 bottles of beer. +Take one down and pass it around, 43 bottles of beer on the wall. + +43 bottles of beer on the wall, 43 bottles of beer. +Take one down and pass it around, 42 bottles of beer on the wall. + +42 bottles of beer on the wall, 42 bottles of beer. +Take one down and pass it around, 41 bottles of beer on the wall. + +41 bottles of beer on the wall, 41 bottles of beer. +Take one down and pass it around, 40 bottles of beer on the wall. + +40 bottles of beer on the wall, 40 bottles of beer. +Take one down and pass it around, 39 bottles of beer on the wall. + +39 bottles of beer on the wall, 39 bottles of beer. +Take one down and pass it around, 38 bottles of beer on the wall. + +38 bottles of beer on the wall, 38 bottles of beer. +Take one down and pass it around, 37 bottles of beer on the wall. + +37 bottles of beer on the wall, 37 bottles of beer. +Take one down and pass it around, 36 bottles of beer on the wall. + +36 bottles of beer on the wall, 36 bottles of beer. +Take one down and pass it around, 35 bottles of beer on the wall. + +35 bottles of beer on the wall, 35 bottles of beer. +Take one down and pass it around, 34 bottles of beer on the wall. + +34 bottles of beer on the wall, 34 bottles of beer. +Take one down and pass it around, 33 bottles of beer on the wall. + +33 bottles of beer on the wall, 33 bottles of beer. +Take one down and pass it around, 32 bottles of beer on the wall. + +32 bottles of beer on the wall, 32 bottles of beer. +Take one down and pass it around, 31 bottles of beer on the wall. + +31 bottles of beer on the wall, 31 bottles of beer. +Take one down and pass it around, 30 bottles of beer on the wall. + +30 bottles of beer on the wall, 30 bottles of beer. +Take one down and pass it around, 29 bottles of beer on the wall. + +29 bottles of beer on the wall, 29 bottles of beer. +Take one down and pass it around, 28 bottles of beer on the wall. + +28 bottles of beer on the wall, 28 bottles of beer. +Take one down and pass it around, 27 bottles of beer on the wall. + +27 bottles of beer on the wall, 27 bottles of beer. +Take one down and pass it around, 26 bottles of beer on the wall. + +26 bottles of beer on the wall, 26 bottles of beer. +Take one down and pass it around, 25 bottles of beer on the wall. + +25 bottles of beer on the wall, 25 bottles of beer. +Take one down and pass it around, 24 bottles of beer on the wall. + +24 bottles of beer on the wall, 24 bottles of beer. +Take one down and pass it around, 23 bottles of beer on the wall. + +23 bottles of beer on the wall, 23 bottles of beer. +Take one down and pass it around, 22 bottles of beer on the wall. + +22 bottles of beer on the wall, 22 bottles of beer. +Take one down and pass it around, 21 bottles of beer on the wall. + +21 bottles of beer on the wall, 21 bottles of beer. +Take one down and pass it around, 20 bottles of beer on the wall. + +20 bottles of beer on the wall, 20 bottles of beer. +Take one down and pass it around, 19 bottles of beer on the wall. + +19 bottles of beer on the wall, 19 bottles of beer. +Take one down and pass it around, 18 bottles of beer on the wall. + +18 bottles of beer on the wall, 18 bottles of beer. +Take one down and pass it around, 17 bottles of beer on the wall. + +17 bottles of beer on the wall, 17 bottles of beer. +Take one down and pass it around, 16 bottles of beer on the wall. + +16 bottles of beer on the wall, 16 bottles of beer. +Take one down and pass it around, 15 bottles of beer on the wall. + +15 bottles of beer on the wall, 15 bottles of beer. +Take one down and pass it around, 14 bottles of beer on the wall. + +14 bottles of beer on the wall, 14 bottles of beer. +Take one down and pass it around, 13 bottles of beer on the wall. + +13 bottles of beer on the wall, 13 bottles of beer. +Take one down and pass it around, 12 bottles of beer on the wall. + +12 bottles of beer on the wall, 12 bottles of beer. +Take one down and pass it around, 11 bottles of beer on the wall. + +11 bottles of beer on the wall, 11 bottles of beer. +Take one down and pass it around, 10 bottles of beer on the wall. + +10 bottles of beer on the wall, 10 bottles of beer. +Take one down and pass it around, 9 bottles of beer on the wall. + +9 bottles of beer on the wall, 9 bottles of beer. +Take one down and pass it around, 8 bottles of beer on the wall. + +8 bottles of beer on the wall, 8 bottles of beer. +Take one down and pass it around, 7 bottles of beer on the wall. + +7 bottles of beer on the wall, 7 bottles of beer. +Take one down and pass it around, 6 bottles of beer on the wall. + +6 bottles of beer on the wall, 6 bottles of beer. +Take one down and pass it around, 5 bottles of beer on the wall. + +5 bottles of beer on the wall, 5 bottles of beer. +Take one down and pass it around, 4 bottles of beer on the wall. + +4 bottles of beer on the wall, 4 bottles of beer. +Take one down and pass it around, 3 bottles of beer on the wall. + +3 bottles of beer on the wall, 3 bottles of beer. +Take one down and pass it around, 2 bottles of beer on the wall. + +2 bottles of beer on the wall, 2 bottles of beer. +Take one down and pass it around, 1 bottle of beer on the wall. + +1 bottle of beer on the wall, 1 bottle of beer. +Take it down and pass it around, no more bottles of beer on the wall. + +No more bottles of beer on the wall, no more bottles of beer. +Go to the store and buy some more, 99 bottles of beer on the wall. +``` + +## For bonus points + +Did you get the tests passing and the code clean? If you want to, these +are some additional things you could try: + +* Remove as much duplication as you possibly can. +* Optimize for readability, even if it means introducing duplication. +* If you've removed all the duplication, do you have a lot of + conditionals? Try replacing the conditionals with polymorphism, if it + applies in this language. How readable is it? + +Then please share your thoughts in a comment on the submission. Did this +experiment make the code better? Worse? Did you learn anything from it? + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Learn to Program by Chris Pine [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/beer-song/src/intersperse.rs b/rust/beer-song/src/intersperse.rs new file mode 100644 index 0000000..51580e6 --- /dev/null +++ b/rust/beer-song/src/intersperse.rs @@ -0,0 +1,52 @@ +use std::rc::Rc; + +/// An iterator that allows to insert a given element `elem` every `interval` elements of the input +/// iterator. +/// +/// The interleaved element is wrapped in a `Rc` smart pointer to avoid hard copies. +pub struct Intersperse { + inner: std::iter::Peekable, // required to have `peek(..)` + elem: Rc, + interval: u32, + intersperse: u32, +} + +impl Intersperse { + pub fn new(inner: I, elem: I::Item, interval: u32) -> Intersperse { + Intersperse { + inner: inner.peekable(), + elem: Rc::new(elem), + interval: interval + 1, // `+ 1` needed to align semantics and implementation + intersperse: 0, + } + } +} + +impl Iterator for Intersperse { + type Item = Rc; + + fn next(&mut self) -> Option { + // Counter rotation + self.intersperse = (self.intersperse + 1) % self.interval; + // Insert a copy of the element only when counter goes to 0 and we haven't reached the end + // of the inner iterator. + if self.intersperse == 0 && self.inner.peek().is_some() { + Some(Rc::clone(&self.elem)) + } else { + self.inner.next() + .map(|x| Rc::new(x)) // Go from Option to Option> + } + } +} + +/// Extend `Iterator`s with `intersperse` function. +pub trait IntersperseIterator: Iterator { + fn intersperse(self, elem: Self::Item, interval: u32) -> Intersperse + where + Self: Sized, + { + Intersperse::new(self, elem, interval) + } +} + +impl IntersperseIterator for I {} diff --git a/rust/beer-song/src/lib.rs b/rust/beer-song/src/lib.rs new file mode 100644 index 0000000..990fbbf --- /dev/null +++ b/rust/beer-song/src/lib.rs @@ -0,0 +1,20 @@ +use itertools::Itertools; + +pub fn verse(n: u32) -> String { + match n { + 0 => format!( "No more bottles of beer on the wall, no more bottles of beer.\n\ + Go to the store and buy some more, 99 bottles of beer on the wall.\n"), + 1 => format!( "1 bottle of beer on the wall, 1 bottle of beer.\n\ + Take it down and pass it around, no more bottles of beer on the wall.\n"), + 2 => format!( "2 bottles of beer on the wall, 2 bottles of beer.\n\ + Take one down and pass it around, 1 bottle of beer on the wall.\n"), + _ => format!( "{} bottles of beer on the wall, {} bottles of beer.\n\ + Take one down and pass it around, {} bottles of beer on the wall.\n", + n, n, n - 1) + } +} + +pub fn sing(start: u32, end: u32) -> String { + // Note: call to `join` can be substituted with `.intersperse(String::from("\n")).collect()` + (end..=start).rev().map(|x| verse(x)).join("\n") +} diff --git a/rust/beer-song/tests/beer-song.rs b/rust/beer-song/tests/beer-song.rs new file mode 100644 index 0000000..2f2ad11 --- /dev/null +++ b/rust/beer-song/tests/beer-song.rs @@ -0,0 +1,31 @@ +use beer_song as beer; + +#[test] +fn test_verse_0() { + assert_eq!(beer::verse(0), "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n"); +} + +#[test] +fn test_verse_1() { + assert_eq!(beer::verse(1), "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n"); +} + +#[test] +fn test_verse_2() { + assert_eq!(beer::verse(2), "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n"); +} + +#[test] +fn test_verse_8() { + assert_eq!(beer::verse(8), "8 bottles of beer on the wall, 8 bottles of beer.\nTake one down and pass it around, 7 bottles of beer on the wall.\n"); +} + +#[test] +fn test_song_8_6() { + assert_eq!(beer::sing(8, 6), "8 bottles of beer on the wall, 8 bottles of beer.\nTake one down and pass it around, 7 bottles of beer on the wall.\n\n7 bottles of beer on the wall, 7 bottles of beer.\nTake one down and pass it around, 6 bottles of beer on the wall.\n\n6 bottles of beer on the wall, 6 bottles of beer.\nTake one down and pass it around, 5 bottles of beer on the wall.\n"); +} + +#[test] +fn test_song_3_0() { + assert_eq!(beer::sing(3, 0), "3 bottles of beer on the wall, 3 bottles of beer.\nTake one down and pass it around, 2 bottles of beer on the wall.\n\n2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n\n1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n\nNo more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n"); +} diff --git a/rust/bob/.exercism/metadata.json b/rust/bob/.exercism/metadata.json new file mode 100644 index 0000000..c9dfddb --- /dev/null +++ b/rust/bob/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"bob","id":"4e53ee4ebf414ac3b9da60e7011c04f9","url":"https://exercism.io/my/solutions/4e53ee4ebf414ac3b9da60e7011c04f9","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/bob/.gitignore b/rust/bob/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/bob/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/bob/Cargo.toml b/rust/bob/Cargo.toml new file mode 100644 index 0000000..34a7fbf --- /dev/null +++ b/rust/bob/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "bob" +version = "1.6.0" diff --git a/rust/bob/README.md b/rust/bob/README.md new file mode 100644 index 0000000..dd84948 --- /dev/null +++ b/rust/bob/README.md @@ -0,0 +1,96 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question, such as "How are you?". + +He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals). + +He answers 'Calm down, I know what I'm doing!' if you yell a question at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/bob/src/lib.rs b/rust/bob/src/lib.rs new file mode 100644 index 0000000..ae18a3d --- /dev/null +++ b/rust/bob/src/lib.rs @@ -0,0 +1,75 @@ +/* The solution consists of an implementation of a simple Finite State Automaton whose states and + * transition messages are represented by the `State` and `Message` enums. + * + * `process(State, Message) -> State` represents the main transition function for the FSA. This + * allows us to compute the answer with a single visit of the input string. + * + * Note: some duplicate states (`QuestLow`, `ElseLow`) are needed in order to remember whether we + * have seen a lowercase character already or not. This is probably not the minimal number of + * states required to solve the problem. + */ +enum State { Nothing, QuestLow, Quest, Yell, YellQ, ElseLow, Else } +enum Message { Whitespace, Upper, Lower, Symbol, Question } + +fn to_message(c: char) -> Message { + match c as u8 { + 0..=32 => Message::Whitespace, // All controll characters are considered whitespace + 63 => Message::Question, + 65..=90 => Message::Upper, + 97..=122 => Message::Lower, + _ => Message::Symbol // Anything else (numbers incl.) is a symbol + } +} + +fn process(s: State, m: Message) -> State { + match s { + State::Nothing => match m { + Message::Whitespace => s, + Message::Upper => State::Yell, + Message::Lower => State::ElseLow, + Message::Question => State::Quest, + Message::Symbol => State::Else + }, + State::QuestLow => match m { + Message::Whitespace | Message::Question => s, + _ => State::ElseLow + }, + State::Quest => match m { + Message::Upper => State::Yell, + Message::Lower => State::ElseLow, + Message::Symbol => State::Else, + _ => s + }, + State::Yell => match m { + Message::Lower => State::ElseLow, + Message::Question => State::YellQ, + _ => s + }, + State::YellQ => match m { + Message::Symbol | Message::Upper => State::Yell, + Message::Lower => State::ElseLow, + _ => s + }, + State::ElseLow => match m { + Message::Question => State::QuestLow, + _ => s + }, + State::Else => match m { + Message::Upper => State::Yell, + Message::Lower => State::ElseLow, + Message::Question => State::Quest, + _ => s + } + } +} + +pub fn reply(message: &str) -> &str { + let state = message.chars().fold(State::Nothing, |s, c| process(s,to_message(c))); + match state { + State::Nothing => "Fine. Be that way!", + State::QuestLow | State::Quest => "Sure.", + State::Yell => "Whoa, chill out!", + State::YellQ => "Calm down, I know what I'm doing!", + _ => "Whatever." + } +} diff --git a/rust/bob/tests/bob.rs b/rust/bob/tests/bob.rs new file mode 100644 index 0000000..b6221eb --- /dev/null +++ b/rust/bob/tests/bob.rs @@ -0,0 +1,179 @@ +fn process_response_case(phrase: &str, expected_response: &str) { + assert_eq!(bob::reply(phrase), expected_response); +} + +#[test] +/// stating something +fn test_stating_something() { + process_response_case("Tom-ay-to, tom-aaaah-to.", "Whatever."); +} + + +#[test] +/// ending with whitespace +fn test_ending_with_whitespace() { + process_response_case("Okay if like my spacebar quite a bit? ", "Sure."); +} + + +#[test] +/// shouting numbers +fn test_shouting_numbers() { + process_response_case("1, 2, 3 GO!", "Whoa, chill out!"); +} + + +#[test] +/// other whitespace +fn test_other_whitespace() { + process_response_case("\r\r ", "Fine. Be that way!"); +} + + +#[test] +/// shouting with special characters +fn test_shouting_with_special_characters() { + process_response_case("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!", "Whoa, chill out!"); +} + + +#[test] +/// talking forcefully +fn test_talking_forcefully() { + process_response_case("Hi there!", "Whatever."); +} + + +#[test] +/// prattling on +fn test_prattling_on() { + process_response_case("Wait! Hang on. Are you going to be OK?", "Sure."); +} + + +#[test] +/// forceful question +fn test_forceful_question() { + process_response_case("WHAT'S GOING ON?", "Calm down, I know what I'm doing!"); +} + + +#[test] +/// shouting with no exclamation mark +fn test_shouting_with_no_exclamation_mark() { + process_response_case("I HATE THE DENTIST", "Whoa, chill out!"); +} + + +#[test] +/// asking gibberish +fn test_asking_gibberish() { + process_response_case("fffbbcbeab?", "Sure."); +} + + +#[test] +/// question with no letters +fn test_question_with_no_letters() { + process_response_case("4?", "Sure."); +} + + +#[test] +/// no letters +fn test_no_letters() { + process_response_case("1, 2, 3", "Whatever."); +} + + +#[test] +/// statement containing question mark +fn test_statement_containing_question_mark() { + process_response_case("Ending with ? means a question.", "Whatever."); +} + + +//NEW +#[test] +/// multiple line question +fn test_multiple_line_question() { + process_response_case("\rDoes this cryogenic chamber make me look fat?\rNo.", "Whatever."); +} + + +#[test] +/// non-question ending with whitespace +fn test_nonquestion_ending_with_whitespace() { + process_response_case("This is a statement ending with whitespace ", "Whatever."); +} + + +#[test] +/// shouting +fn test_shouting() { + process_response_case("WATCH OUT!", "Whoa, chill out!"); +} + + +#[test] +/// non-letters with question +fn test_nonletters_with_question() { + process_response_case(":) ?", "Sure."); +} + + +#[test] +/// shouting gibberish +fn test_shouting_gibberish() { + process_response_case("FCECDFCAAB", "Whoa, chill out!"); +} + + +#[test] +/// asking a question +fn test_asking_a_question() { + process_response_case("Does this cryogenic chamber make me look fat?", "Sure."); +} + + +#[test] +/// asking a numeric question +fn test_asking_a_numeric_question() { + process_response_case("You are, what, like 15?", "Sure."); +} + + +#[test] +/// silence +fn test_silence() { + process_response_case("", "Fine. Be that way!"); +} + + +#[test] +/// starting with whitespace +fn test_starting_with_whitespace() { + process_response_case(" hmmmmmmm...", "Whatever."); +} + + +#[test] +/// using acronyms in regular speech +fn test_using_acronyms_in_regular_speech() { + process_response_case("It's OK if you don't want to go work for NASA.", "Whatever."); +} + + +#[test] +/// alternate silence +fn test_alternate_silence() { + process_response_case(" ", "Fine. Be that way!"); +} + + +#[test] +/// prolonged silence +fn test_prolonged_silence() { + process_response_case(" ", "Fine. Be that way!"); +} + diff --git a/rust/clock/.exercism/metadata.json b/rust/clock/.exercism/metadata.json new file mode 100644 index 0000000..cbe366b --- /dev/null +++ b/rust/clock/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"clock","id":"f95dd1061dd34278af4d6838330bd546","url":"https://exercism.io/my/solutions/f95dd1061dd34278af4d6838330bd546","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/clock/.gitignore b/rust/clock/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/clock/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/clock/Cargo.toml b/rust/clock/Cargo.toml new file mode 100644 index 0000000..376e7f1 --- /dev/null +++ b/rust/clock/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2018" +name = "clock" +version = "2.4.0" + +[dependencies] diff --git a/rust/clock/README.md b/rust/clock/README.md new file mode 100644 index 0000000..8348e33 --- /dev/null +++ b/rust/clock/README.md @@ -0,0 +1,102 @@ +# Clock + +Implement a clock that handles times without dates. + +You should be able to add and subtract minutes to it. + +Two clocks that represent the same time should be equal to each other. + +## Rust Traits for `.to_string()` + +Did you implement `.to_string()` for the `Clock` struct? + +If so, try implementing the +[Display trait](https://doc.rust-lang.org/std/fmt/trait.Display.html) for `Clock` instead. + +Traits allow for a common way to implement functionality for various types. + +For additional learning, consider how you might implement `String::from` for the `Clock` type. +You don't have to actually implement this—it's redundant with `Display`, which is generally the +better choice when the destination type is `String`—but it's useful to have a few type-conversion +traits in your toolkit. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Pairing session with Erin Drummond [https://twitter.com/ebdrummond](https://twitter.com/ebdrummond) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/clock/src/lib.rs b/rust/clock/src/lib.rs new file mode 100644 index 0000000..3ae8a62 --- /dev/null +++ b/rust/clock/src/lib.rs @@ -0,0 +1,44 @@ +use std::fmt; +use std::ops::Add; + +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Clock { + hours: i32, + minutes: i32, +} + +impl fmt::Display for Clock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:02}:{:02}", self.hours, self.minutes) + } +} + +impl Add for Clock { + type Output = Self; + + fn add(self, minutes: i32) -> Self { + Self::new(self.hours, self.minutes + minutes) + } +} + +/* impl From for String { + * fn from(c: Clock) -> String { + * format!("{}",c) + * } + * } + */ + +impl Clock { + pub fn new(hours: i32, minutes: i32) -> Self { + let hours = hours + minutes / 60 - if minutes % 60 < 0 { 1 } else { 0 }; + let hours = hours % 24; + let hours = hours + if hours < 0 { 24 } else { 0 }; + let minutes = minutes % 60; + let minutes = minutes + if minutes < 0 { 60 } else { 0 }; + Clock { hours, minutes } + } + + pub fn add_minutes(self, minutes: i32) -> Self { + self + minutes + } +} diff --git a/rust/clock/tests/clock.rs b/rust/clock/tests/clock.rs new file mode 100644 index 0000000..04f5241 --- /dev/null +++ b/rust/clock/tests/clock.rs @@ -0,0 +1,294 @@ +use clock::Clock; + +// +// Clock Creation +// + +#[test] +fn test_on_the_hour() { + assert_eq!(Clock::new(8, 0).to_string(), "08:00"); +} + +#[test] +fn test_past_the_hour() { + assert_eq!(Clock::new(11, 9).to_string(), "11:09"); +} + +#[test] +fn test_midnight_is_zero_hours() { + assert_eq!(Clock::new(24, 0).to_string(), "00:00"); +} + +#[test] +fn test_hour_rolls_over() { + assert_eq!(Clock::new(25, 0).to_string(), "01:00"); +} + +#[test] +fn test_hour_rolls_over_continuously() { + assert_eq!(Clock::new(100, 0).to_string(), "04:00"); +} + +#[test] +fn test_sixty_minutes_is_next_hour() { + assert_eq!(Clock::new(1, 60).to_string(), "02:00"); +} + +#[test] +fn test_minutes_roll_over() { + assert_eq!(Clock::new(0, 160).to_string(), "02:40"); +} + +#[test] +fn test_minutes_roll_over_continuously() { + assert_eq!(Clock::new(0, 1723).to_string(), "04:43"); +} + +#[test] +fn test_hours_and_minutes_roll_over() { + assert_eq!(Clock::new(25, 160).to_string(), "03:40"); +} + +#[test] +fn test_hours_and_minutes_roll_over_continuously() { + assert_eq!(Clock::new(201, 3001).to_string(), "11:01"); +} + +#[test] +fn test_hours_and_minutes_roll_over_to_exactly_midnight() { + assert_eq!(Clock::new(72, 8640).to_string(), "00:00"); +} + +#[test] +fn test_negative_hour() { + assert_eq!(Clock::new(-1, 15).to_string(), "23:15"); +} + +#[test] +fn test_negative_hour_roll_over() { + assert_eq!(Clock::new(-25, 00).to_string(), "23:00"); +} + +#[test] +fn test_negative_hour_roll_over_continuously() { + assert_eq!(Clock::new(-91, 00).to_string(), "05:00"); +} + +#[test] +fn test_negative_minutes() { + assert_eq!(Clock::new(1, -40).to_string(), "00:20"); +} + +#[test] +fn test_negative_minutes_roll_over() { + assert_eq!(Clock::new(1, -160).to_string(), "22:20"); +} + +#[test] +fn test_negative_minutes_roll_over_continuously() { + assert_eq!(Clock::new(1, -4820).to_string(), "16:40"); +} + +#[test] +fn test_negative_sixty_minutes_is_prev_hour() { + assert_eq!(Clock::new(2, -60).to_string(), "01:00"); +} + +#[test] +fn test_negative_hour_and_minutes_both_roll_over() { + assert_eq!(Clock::new(-25, -160).to_string(), "20:20"); +} + +#[test] +fn test_negative_hour_and_minutes_both_roll_over_continuously() { + assert_eq!(Clock::new(-121, -5810).to_string(), "22:10"); +} + +#[test] +fn test_zero_hour_and_negative_minutes() { + assert_eq!(Clock::new(0, -22).to_string(), "23:38"); +} + +// +// Clock Math +// + +#[test] +fn test_add_minutes() { + let clock = Clock::new(10, 0).add_minutes(3); + assert_eq!(clock.to_string(), "10:03"); +} + +#[test] +fn test_add_no_minutes() { + let clock = Clock::new(6, 41).add_minutes(0); + assert_eq!(clock.to_string(), "06:41"); +} + +#[test] +fn test_add_to_next_hour() { + let clock = Clock::new(0, 45).add_minutes(40); + assert_eq!(clock.to_string(), "01:25"); +} + +#[test] +fn test_add_more_than_one_hour() { + let clock = Clock::new(10, 0).add_minutes(61); + assert_eq!(clock.to_string(), "11:01"); +} + +#[test] +fn test_add_more_than_two_hours_with_carry() { + let clock = Clock::new(0, 45).add_minutes(160); + assert_eq!(clock.to_string(), "03:25"); +} + +#[test] +fn test_add_across_midnight() { + let clock = Clock::new(23, 59).add_minutes(2); + assert_eq!(clock.to_string(), "00:01"); +} + +#[test] +fn test_add_more_than_one_day() { + let clock = Clock::new(5, 32).add_minutes(1500); + assert_eq!(clock.to_string(), "06:32"); +} + +#[test] +fn test_add_more_than_two_days() { + let clock = Clock::new(1, 1).add_minutes(3500); + assert_eq!(clock.to_string(), "11:21"); +} + +#[test] +fn test_subtract_minutes() { + let clock = Clock::new(10, 3).add_minutes(-3); + assert_eq!(clock.to_string(), "10:00"); +} + +#[test] +fn test_subtract_to_previous_hour() { + let clock = Clock::new(10, 3).add_minutes(-30); + assert_eq!(clock.to_string(), "09:33"); +} + +#[test] +fn test_subtract_more_than_an_hour() { + let clock = Clock::new(10, 3).add_minutes(-70); + assert_eq!(clock.to_string(), "08:53"); +} + +#[test] +fn test_subtract_across_midnight() { + let clock = Clock::new(0, 3).add_minutes(-4); + assert_eq!(clock.to_string(), "23:59"); +} + +#[test] +fn test_subtract_more_than_two_hours() { + let clock = Clock::new(0, 0).add_minutes(-160); + assert_eq!(clock.to_string(), "21:20"); +} + +#[test] +fn test_subtract_more_than_two_hours_with_borrow() { + let clock = Clock::new(6, 15).add_minutes(-160); + assert_eq!(clock.to_string(), "03:35"); +} + +#[test] +fn test_subtract_more_than_one_day() { + let clock = Clock::new(5, 32).add_minutes(-1500); + assert_eq!(clock.to_string(), "04:32"); +} + +#[test] +fn test_subtract_mores_than_two_days() { + let clock = Clock::new(2, 20).add_minutes(-3000); + assert_eq!(clock.to_string(), "00:20"); +} + +// +// Test Equality +// + +#[test] +fn test_compare_clocks_for_equality() { + assert_eq!(Clock::new(15, 37), Clock::new(15, 37)); +} + +#[test] +fn test_compare_clocks_a_minute_apart() { + assert_ne!(Clock::new(15, 36), Clock::new(15, 37)); +} + +#[test] +fn test_compare_clocks_an_hour_apart() { + assert_ne!(Clock::new(14, 37), Clock::new(15, 37)); +} + +#[test] +fn test_compare_clocks_with_hour_overflow() { + assert_eq!(Clock::new(10, 37), Clock::new(34, 37)); +} + +#[test] +fn test_compare_clocks_with_hour_overflow_by_several_days() { + assert_eq!(Clock::new(3, 11), Clock::new(99, 11)); +} + +#[test] +fn test_compare_clocks_with_negative_hour() { + assert_eq!(Clock::new(22, 40), Clock::new(-2, 40)); +} + +#[test] +fn test_compare_clocks_with_negative_hour_that_wraps() { + assert_eq!(Clock::new(17, 3), Clock::new(-31, 3)); +} + +#[test] +fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() { + assert_eq!(Clock::new(13, 49), Clock::new(-83, 49)); +} + +#[test] +fn test_compare_clocks_with_minutes_overflow() { + assert_eq!(Clock::new(0, 1), Clock::new(0, 1441)); +} + +#[test] +fn test_compare_clocks_with_minutes_overflow_by_several_days() { + assert_eq!(Clock::new(2, 2), Clock::new(2, 4322)); +} + +#[test] +fn test_compare_clocks_with_negative_minute() { + assert_eq!(Clock::new(2, 40), Clock::new(3, -20)) +} + +#[test] +fn test_compare_clocks_with_negative_minute_that_wraps() { + assert_eq!(Clock::new(4, 10), Clock::new(5, -1490)) +} + +#[test] +fn test_compare_clocks_with_negative_minute_that_wraps_multiple() { + assert_eq!(Clock::new(6, 15), Clock::new(6, -4305)) +} + +#[test] +fn test_compare_clocks_with_negative_hours_and_minutes() { + assert_eq!(Clock::new(7, 32), Clock::new(-12, -268)) +} + +#[test] +fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() { + assert_eq!(Clock::new(18, 7), Clock::new(-54, -11_513)) +} + +#[test] +fn test_compare_full_clock_and_zeroed_clock() { + assert_eq!(Clock::new(24, 0), Clock::new(0, 0)) +} diff --git a/rust/difference-of-squares/.exercism/metadata.json b/rust/difference-of-squares/.exercism/metadata.json new file mode 100644 index 0000000..7e844ee --- /dev/null +++ b/rust/difference-of-squares/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"difference-of-squares","id":"9ad3be19e839435282ee30ce156fdb07","url":"https://exercism.io/my/solutions/9ad3be19e839435282ee30ce156fdb07","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/difference-of-squares/.gitignore b/rust/difference-of-squares/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/difference-of-squares/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/difference-of-squares/Cargo.toml b/rust/difference-of-squares/Cargo.toml new file mode 100644 index 0000000..41e2b29 --- /dev/null +++ b/rust/difference-of-squares/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "difference-of-squares" +version = "1.2.0" diff --git a/rust/difference-of-squares/README.md b/rust/difference-of-squares/README.md new file mode 100644 index 0000000..d940ad5 --- /dev/null +++ b/rust/difference-of-squares/README.md @@ -0,0 +1,97 @@ +# Difference Of Squares + +Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. + +The square of the sum of the first ten natural numbers is +(1 + 2 + ... + 10)² = 55² = 3025. + +The sum of the squares of the first ten natural numbers is +1² + 2² + ... + 10² = 385. + +Hence the difference between the square of the sum of the first +ten natural numbers and the sum of the squares of the first ten +natural numbers is 3025 - 385 = 2640. + +You are not expected to discover an efficient solution to this yourself from +first principles; research is allowed, indeed, encouraged. Finding the best +algorithm for the problem is a key skill in software engineering. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Problem 6 at Project Euler [http://projecteuler.net/problem=6](http://projecteuler.net/problem=6) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/difference-of-squares/src/lib.rs b/rust/difference-of-squares/src/lib.rs new file mode 100644 index 0000000..4599733 --- /dev/null +++ b/rust/difference-of-squares/src/lib.rs @@ -0,0 +1,14 @@ +/// Implements square of Gauss' formula +pub fn square_of_sum(n: u32) -> u32 { + (n * (n + 1) / 2).pow(2) +} + +/// Implements the formula reported in Wolfram|Alpha at this +/// [link](https://www.wolframalpha.com/input/?i=sum+of+squares&assumption=%7B%22F%22%2C+%22SumOfSquaresOfIntegers%22%2C+%22sumlowerlimit%22%7D+-%3E%221%22&assumption=%7B%22F%22%2C+%22SumOfSquaresOfIntegers%22%2C+%22sumupperlimit2%22%7D+-%3E%22n%22) +pub fn sum_of_squares(n: u32) -> u32 { + n * (1 + n) * (1 + 2 * n) / 6 +} + +pub fn difference(n: u32) -> u32 { + square_of_sum(n) - sum_of_squares(n) +} diff --git a/rust/difference-of-squares/tests/difference-of-squares.rs b/rust/difference-of-squares/tests/difference-of-squares.rs new file mode 100644 index 0000000..4a029b3 --- /dev/null +++ b/rust/difference-of-squares/tests/difference-of-squares.rs @@ -0,0 +1,46 @@ +use difference_of_squares as squares; + +#[test] +fn test_square_of_sum_1() { + assert_eq!(1, squares::square_of_sum(1)); +} + +#[test] +fn test_square_of_sum_5() { + assert_eq!(225, squares::square_of_sum(5)); +} + +#[test] +fn test_square_of_sum_100() { + assert_eq!(25_502_500, squares::square_of_sum(100)); +} + +#[test] +fn test_sum_of_squares_1() { + assert_eq!(1, squares::sum_of_squares(1)); +} + +#[test] +fn test_sum_of_squares_5() { + assert_eq!(55, squares::sum_of_squares(5)); +} + +#[test] +fn test_sum_of_squares_100() { + assert_eq!(338_350, squares::sum_of_squares(100)); +} + +#[test] +fn test_difference_1() { + assert_eq!(0, squares::difference(1)); +} + +#[test] +fn test_difference_5() { + assert_eq!(170, squares::difference(5)); +} + +#[test] +fn test_difference_100() { + assert_eq!(25_164_150, squares::difference(100)); +} diff --git a/rust/dot-dsl/.exercism/metadata.json b/rust/dot-dsl/.exercism/metadata.json new file mode 100644 index 0000000..5399056 --- /dev/null +++ b/rust/dot-dsl/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"dot-dsl","id":"57ca2e502fdf482aa52e91c4f4f7f51e","url":"https://exercism.io/my/solutions/57ca2e502fdf482aa52e91c4f4f7f51e","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/dot-dsl/.gitignore b/rust/dot-dsl/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/dot-dsl/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/dot-dsl/Cargo.toml b/rust/dot-dsl/Cargo.toml new file mode 100644 index 0000000..3da0d67 --- /dev/null +++ b/rust/dot-dsl/Cargo.toml @@ -0,0 +1,7 @@ +[package] +edition = "2018" +name = "dot-dsl" +version = "0.1.0" + +[dependencies] +maplit = "1.0.1" diff --git a/rust/dot-dsl/README.md b/rust/dot-dsl/README.md new file mode 100644 index 0000000..29e0e7a --- /dev/null +++ b/rust/dot-dsl/README.md @@ -0,0 +1,121 @@ +# DOT DSL + +A [Domain Specific Language (DSL)](https://en.wikipedia.org/wiki/Domain-specific_language) is a +small language optimized for a specific domain. Since a DSL is +targeted, it can greatly impact productivity/understanding by allowing the +writer to declare *what* they want rather than *how*. + +One problem area where they are applied are complex customizations/configurations. + +For example the [DOT language](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) allows +you to write a textual description of a graph which is then transformed into a picture by one of +the [Graphviz](http://graphviz.org/) tools (such as `dot`). A simple graph looks like this: + + graph { + graph [bgcolor="yellow"] + a [color="red"] + b [color="blue"] + a -- b [color="green"] + } + +Putting this in a file `example.dot` and running `dot example.dot -T png +-o example.png` creates an image `example.png` with red and blue circle +connected by a green line on a yellow background. + +Write a Domain Specific Language similar to the Graphviz dot language. + +Our DSL is similar to the Graphviz dot language in that our DSL will be used +to create graph data structures. However, unlike the DOT Language, our DSL will +be an internal DSL for use only in our language. + +More information about the difference between internal and external DSLs can be +found [here](https://martinfowler.com/bliki/DomainSpecificLanguage.html). + +## Builder pattern + +This exercise expects you to build several structs using `builder pattern`. +In short, this pattern allows you to split the construction function of your struct, that contains a lot of arguments, into +several separate functions. This approach gives you the means to make compact but highly-flexible struct construction and +configuration. +You can read more about it on the [following page](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html). + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/DOT_(graph_description_language)](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/dot-dsl/src/lib.rs b/rust/dot-dsl/src/lib.rs new file mode 100644 index 0000000..654ee09 --- /dev/null +++ b/rust/dot-dsl/src/lib.rs @@ -0,0 +1,119 @@ +pub mod graph { + + use graph_items::edge::Edge; + use graph_items::node::Node; + use std::collections::HashMap; + + pub mod graph_items { + + pub mod node { + + use std::collections::HashMap; + + #[derive(Default, Debug, PartialEq, Eq, Clone)] + pub struct Node<'a> { + pub name: &'a str, + attrs: HashMap, + } + + impl<'a> Node<'a> { + pub fn new(name: &'a str) -> Node<'a> { + Node { + name, + ..Default::default() + } + } + + pub fn with_attrs(mut self, attrs: &[(&'a str, &'a str)]) -> Node<'a> { + for (key, value) in attrs { + self.attrs.insert(key.to_string(), value.to_string()); + } + self + } + + pub fn get_attr(&self, key: &str) -> Option<&str> { + self.attrs.get(key).map(|s| &s[..]) + } + } + } + + pub mod edge { + + use std::collections::HashMap; + + #[derive(Default, Debug, PartialEq, Eq, Clone)] + pub struct Edge<'a> { + pub x: &'a str, + pub y: &'a str, + attrs: HashMap, + } + + impl<'a> Edge<'a> { + pub fn new(x: &'a str, y: &'a str) -> Edge<'a> { + Edge { + x, + y, + ..Default::default() + } + } + + pub fn with_attrs(mut self, attrs: &[(&'a str, &'a str)]) -> Edge<'a> { + for (key, value) in attrs { + self.attrs.insert(key.to_string(), value.to_string()); + } + self + } + + pub fn get_attr(&self, key: &str) -> Option<&str> { + self.attrs.get(key).map(|s| &s[..]) + } + } + } + } + + #[derive(Default, Debug)] + pub struct Graph<'a> { + pub nodes: Vec>, + pub edges: Vec>, + pub attrs: HashMap, + } + + impl<'a> Graph<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn with_attrs(mut self, attrs: &[(&'a str, &'a str)]) -> Graph<'a> { + for (key, value) in attrs { + self.attrs.insert(key.to_string(), value.to_string()); + } + self + } + + pub fn with_nodes(mut self, nodes: &[Node<'a>]) -> Graph<'a> { + for node in nodes { + self.nodes.push(node.clone()); + } + self + } + + pub fn with_edges(mut self, edges: &[Edge<'a>]) -> Graph<'a> { + for edge in edges { + self.edges.push(edge.clone()) + } + self + } + + pub fn get_node(&self, name: &str) -> Option<&Node<'a>> { + self.nodes.iter().find(|&node| node.name == name) + } + + pub fn get_edge(&self, x: &str, y: &str) -> Option<&Edge<'a>> { + self.edges.iter().find(|&edge| edge.x == x && edge.y == y) + } + + pub fn get_attr(&self, key: &str) -> Option<&str> { + self.attrs.get(key).map(|s| &s[..]) + } + } +} diff --git a/rust/dot-dsl/tests/dot-dsl.rs b/rust/dot-dsl/tests/dot-dsl.rs new file mode 100644 index 0000000..ae469b7 --- /dev/null +++ b/rust/dot-dsl/tests/dot-dsl.rs @@ -0,0 +1,138 @@ +use dot_dsl::graph::graph_items::edge::Edge; +use dot_dsl::graph::graph_items::node::Node; +use dot_dsl::graph::Graph; +use maplit::hashmap; + +#[test] +fn test_empty_graph() { + let graph = Graph::new(); + + assert!(graph.nodes.is_empty()); + + assert!(graph.edges.is_empty()); + + assert!(graph.attrs.is_empty()); +} + +#[test] +fn test_graph_with_one_node() { + let nodes = vec![Node::new("a")]; + + let graph = Graph::new().with_nodes(&nodes); + + assert!(graph.edges.is_empty()); + + assert!(graph.attrs.is_empty()); + + assert_eq!(graph.nodes, vec![Node::new("a")]); +} + +#[test] +fn test_graph_with_one_node_with_keywords() { + let nodes = vec![Node::new("a").with_attrs(&[("color", "green")])]; + + let graph = Graph::new().with_nodes(&nodes); + + assert!(graph.edges.is_empty()); + + assert!(graph.attrs.is_empty()); + + assert_eq!( + graph.nodes, + vec![Node::new("a").with_attrs(&[("color", "green")])] + ); +} + +#[test] +fn test_graph_with_one_edge() { + let edges = vec![Edge::new("a", "b")]; + + let graph = Graph::new().with_edges(&edges); + + assert!(graph.nodes.is_empty()); + + assert!(graph.attrs.is_empty()); + + assert_eq!(graph.edges, vec![Edge::new("a", "b")]); +} + +#[test] +fn test_graph_with_one_attribute() { + let graph = Graph::new().with_attrs(&[("foo", "1")]); + + let expected_attrs = hashmap! { + "foo".to_string() => "1".to_string(), + }; + + assert!(graph.nodes.is_empty()); + + assert!(graph.edges.is_empty()); + + assert_eq!(graph.attrs, expected_attrs); +} + +#[test] +fn test_graph_with_attributes() { + let nodes = vec![ + Node::new("a").with_attrs(&[("color", "green")]), + Node::new("c"), + Node::new("b").with_attrs(&[("label", "Beta!")]), + ]; + + let edges = vec![ + Edge::new("b", "c"), + Edge::new("a", "b").with_attrs(&[("color", "blue")]), + ]; + + let attrs = vec![("foo", "1"), ("title", "Testing Attrs"), ("bar", "true")]; + + let expected_attrs = hashmap! { + "foo".to_string() => "1".to_string(), + "title".to_string() => "Testing Attrs".to_string(), + "bar".to_string() => "true".to_string(), + }; + + let graph = Graph::new() + .with_nodes(&nodes) + .with_edges(&edges) + .with_attrs(&attrs); + + assert_eq!( + graph.nodes, + vec![ + Node::new("a").with_attrs(&[("color", "green")]), + Node::new("c"), + Node::new("b").with_attrs(&[("label", "Beta!")]), + ] + ); + + assert_eq!( + graph.edges, + vec![ + Edge::new("b", "c"), + Edge::new("a", "b").with_attrs(&[("color", "blue")]), + ] + ); + + assert_eq!(graph.attrs, expected_attrs); +} + +#[test] +fn test_graph_stores_attributes() { + let attributes = [("foo", "bar"), ("bat", "baz"), ("bim", "bef")]; + let graph = Graph::new().with_nodes( + &["a", "b", "c"] + .iter() + .zip(attributes.iter()) + .map(|(name, &attr)| Node::new(&name).with_attrs(&[attr])) + .collect::>(), + ); + + assert_eq!( + graph + .get_node("c") + .expect("node must be stored") + .get_attr("bim"), + Some("bef") + ); +} diff --git a/rust/gigasecond/.exercism/metadata.json b/rust/gigasecond/.exercism/metadata.json new file mode 100644 index 0000000..7bd17ac --- /dev/null +++ b/rust/gigasecond/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"gigasecond","id":"2131caf991cf446292290bef2e6d64da","url":"https://exercism.io/my/solutions/2131caf991cf446292290bef2e6d64da","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/gigasecond/.gitignore b/rust/gigasecond/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/gigasecond/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/gigasecond/Cargo.toml b/rust/gigasecond/Cargo.toml new file mode 100644 index 0000000..1a8fb2c --- /dev/null +++ b/rust/gigasecond/Cargo.toml @@ -0,0 +1,8 @@ +[package] +edition = "2018" +name = "gigasecond" +version = "2.0.0" + +[dependencies] +chrono = "0.4" + diff --git a/rust/gigasecond/README.md b/rust/gigasecond/README.md new file mode 100644 index 0000000..9368f91 --- /dev/null +++ b/rust/gigasecond/README.md @@ -0,0 +1,89 @@ +# Gigasecond + +Given a moment, determine the moment that would be after a gigasecond +has passed. + +A gigasecond is 10^9 (1,000,000,000) seconds. + +If you're unsure what operations you can perform on `DateTime` take a look at the [chrono crate](https://docs.rs/chrono) which is listed as a dependency in the `Cargo.toml` file for this exercise. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Chapter 9 in Chris Pine's online Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=09](http://pine.fm/LearnToProgram/?Chapter=09) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/gigasecond/src/lib.rs b/rust/gigasecond/src/lib.rs new file mode 100644 index 0000000..0abd90b --- /dev/null +++ b/rust/gigasecond/src/lib.rs @@ -0,0 +1,7 @@ +use chrono::{DateTime, Duration, Utc}; + +// Returns a Utc DateTime one billion seconds after start. +pub fn after(start: DateTime) -> DateTime { + let gigasecond = Duration::seconds(1_000_000_000); + start + gigasecond +} diff --git a/rust/gigasecond/tests/gigasecond.rs b/rust/gigasecond/tests/gigasecond.rs new file mode 100644 index 0000000..4fe139b --- /dev/null +++ b/rust/gigasecond/tests/gigasecond.rs @@ -0,0 +1,51 @@ +use chrono::{TimeZone, Utc}; + +#[test] +fn test_date() { + let start_date = Utc.ymd(2011, 4, 25).and_hms(0, 0, 0); + + assert_eq!( + gigasecond::after(start_date), + Utc.ymd(2043, 1, 1).and_hms(1, 46, 40) + ); +} + +#[test] +fn test_another_date() { + let start_date = Utc.ymd(1977, 6, 13).and_hms(0, 0, 0); + + assert_eq!( + gigasecond::after(start_date), + Utc.ymd(2009, 2, 19).and_hms(1, 46, 40) + ); +} + +#[test] +fn test_third_date() { + let start_date = Utc.ymd(1959, 7, 19).and_hms(0, 0, 0); + + assert_eq!( + gigasecond::after(start_date), + Utc.ymd(1991, 3, 27).and_hms(1, 46, 40) + ); +} + +#[test] +fn test_datetime() { + let start_date = Utc.ymd(2015, 1, 24).and_hms(22, 0, 0); + + assert_eq!( + gigasecond::after(start_date), + Utc.ymd(2046, 10, 2).and_hms(23, 46, 40) + ); +} + +#[test] +fn test_another_datetime() { + let start_date = Utc.ymd(2015, 1, 24).and_hms(23, 59, 59); + + assert_eq!( + gigasecond::after(start_date), + Utc.ymd(2046, 10, 3).and_hms(1, 46, 39) + ); +} diff --git a/rust/grains/.exercism/metadata.json b/rust/grains/.exercism/metadata.json new file mode 100644 index 0000000..c20eb3a --- /dev/null +++ b/rust/grains/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"grains","id":"cfeb306e73c0483aa2a6e1fcc8d1029b","url":"https://exercism.io/my/solutions/cfeb306e73c0483aa2a6e1fcc8d1029b","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/grains/.gitignore b/rust/grains/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/grains/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/grains/Cargo.toml b/rust/grains/Cargo.toml new file mode 100644 index 0000000..6bf141e --- /dev/null +++ b/rust/grains/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "grains" +version = "1.2.0" diff --git a/rust/grains/README.md b/rust/grains/README.md new file mode 100644 index 0000000..e54de2c --- /dev/null +++ b/rust/grains/README.md @@ -0,0 +1,107 @@ +# Grains + +Calculate the number of grains of wheat on a chessboard given that the number +on each square doubles. + +There once was a wise servant who saved the life of a prince. The king +promised to pay whatever the servant could dream up. Knowing that the +king loved chess, the servant told the king he would like to have grains +of wheat. One grain on the first square of a chess board, with the number +of grains doubling on each successive square. + +There are 64 squares on a chessboard (where square 1 has one grain, square 2 has two grains, and so on). + +Write code that shows: +- how many grains were on a given square, and +- the total number of grains on the chessboard + +## For bonus points + +Did you get the tests passing and the code clean? If you want to, these +are some additional things you could try: + +- Optimize for speed. +- Optimize for readability. + +Then please share your thoughts in a comment on the submission. Did this +experiment make the code better? Worse? Did you learn anything from it? + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +JavaRanch Cattle Drive, exercise 6 [http://www.javaranch.com/grains.jsp](http://www.javaranch.com/grains.jsp) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/grains/src/lib.rs b/rust/grains/src/lib.rs new file mode 100644 index 0000000..05449be --- /dev/null +++ b/rust/grains/src/lib.rs @@ -0,0 +1,23 @@ +pub fn square(s: u32) -> u64 { + assert!(s > 0 && s < 65,"Square must be between 1 and 64"); + 2_u64.pow(s-1) +} + +/// This version uses the already defined `square(s)` function. +/// +/// There is also a faster way to compute this according to +/// [Wolfram|Alpha](https://www.wolframalpha.com/input/?i=sum_0%5En+2%5En) +/// +/// 2_u64.pow(65) - 1 == 18_446_744_073_709_551_615 +/// +/// this solution however doesn't work because +/// +/// 2_u64.pow(65) == 18_446_744_073_709_551_616 +/// +/// which overflows since +/// +/// std::u64::MAX == 18_446_744_073_709_551_615 +/// +pub fn total() -> u64 { + (1..65).map(square).sum() // std::u64::MAX +} diff --git a/rust/grains/tests/grains.rs b/rust/grains/tests/grains.rs new file mode 100644 index 0000000..405eb4d --- /dev/null +++ b/rust/grains/tests/grains.rs @@ -0,0 +1,65 @@ +use grains; + +fn process_square_case(input: u32, expected: u64) { + assert_eq!(grains::square(input), expected); +} + +#[test] +/// 1 +fn test_1() { + process_square_case(1, 1); +} + +#[test] +/// 2 +fn test_2() { + process_square_case(2, 2); +} + +#[test] +/// 3 +fn test_3() { + process_square_case(3, 4); +} + +#[test] +/// 4 +fn test_4() { + process_square_case(4, 8); +} + +//NEW +#[test] +/// 16 +fn test_16() { + process_square_case(16, 32_768); +} + +#[test] +/// 32 +fn test_32() { + process_square_case(32, 2_147_483_648); +} + +#[test] +/// 64 +fn test_64() { + process_square_case(64, 9_223_372_036_854_775_808); +} + +#[test] +#[should_panic(expected = "Square must be between 1 and 64")] +fn test_square_0_raises_an_exception() { + grains::square(0); +} + +#[test] +#[should_panic(expected = "Square must be between 1 and 64")] +fn test_square_greater_than_64_raises_an_exception() { + grains::square(65); +} + +#[test] +fn test_returns_the_total_number_of_grains_on_the_board() { + assert_eq!(grains::total(), 18_446_744_073_709_551_615); +} diff --git a/rust/hello-world/.exercism/metadata.json b/rust/hello-world/.exercism/metadata.json new file mode 100644 index 0000000..0e3e354 --- /dev/null +++ b/rust/hello-world/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"hello-world","id":"aac7852c428e494ca701dc74d200c468","url":"https://exercism.io/my/solutions/aac7852c428e494ca701dc74d200c468","handle":"dyamon","is_requester":true,"auto_approve":true} \ No newline at end of file diff --git a/rust/hello-world/.gitignore b/rust/hello-world/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/hello-world/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/hello-world/Cargo.toml b/rust/hello-world/Cargo.toml new file mode 100644 index 0000000..4d9f8bb --- /dev/null +++ b/rust/hello-world/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "hello-world" +version = "1.1.0" diff --git a/rust/hello-world/GETTING_STARTED.md b/rust/hello-world/GETTING_STARTED.md new file mode 100644 index 0000000..5eeea95 --- /dev/null +++ b/rust/hello-world/GETTING_STARTED.md @@ -0,0 +1,92 @@ +# Getting Started + +These exercises lean on Test-Driven Development (TDD), but they're not +an exact match. + +The following steps assume that you are in the same directory as the exercise. + +You must have rust installed. +Follow the [Installation chapter in the Rust book](https://doc.rust-lang.org/book/ch01-01-installation.html). +The [Rust language section](http://exercism.io/languages/rust) +section from exercism is also useful. + +## Step 1 + +Run the test suite. It can be run with `cargo`, which is installed with rust. + +``` +$ cargo test +``` + +This will compile the `hello-world` crate and run the test, which fails. + +``` +running 1 test +test test_hello_world ... FAILED + +failures: + +---- test_hello_world stdout ---- +thread 'test_hello_world' panicked at 'assertion failed: `(left == right)` +(left: `"Hello, World!"`, right: `"Goodbye, World!"`)', tests/hello-world.rs:5 + +failures: + test_hello_world + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured +``` + +### Understanding Test Failures + +The `test_hello_world` failure states that it is expecting the value, +`"Hello, World!"`, to be returned from `hello()`. +The left side of the assertion (at line 5) should be equal to the right side. + +``` +---- test_hello_world stdout ---- +thread 'test_hello_world' panicked at 'assertion failed: `(left == right)` +(left: `"Hello, World!"`, right: `"Goodbye, World!"`)', tests/hello-world.rs:5 +``` + +### Fixing the Error + +To fix it, open up `src/lib.rs` and change the `hello` function to return +`"Hello, World!"` instead of `"Goodbye, World!"`. + +```rust +pub fn hello() -> &'static str { + "Hello, World!" +} +``` + +## Step 2 + +Run the test again. This time, it will pass. + +``` +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured + + Running target/debug/deps/hello_world-bd1f06dc726ef14f + +running 1 test +test test_hello_world ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests hello-world + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +## Submit + +Once the test is passing, you can submit your code with the following +command: + +``` +$ exercism submit src/lib.rs +``` diff --git a/rust/hello-world/README.md b/rust/hello-world/README.md new file mode 100644 index 0000000..775dd89 --- /dev/null +++ b/rust/hello-world/README.md @@ -0,0 +1,95 @@ +# Hello World + +The classical introductory exercise. Just say "Hello, World!". + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is +the traditional first program for beginning programming in a new language +or environment. + +The objectives are simple: + +- Write a function that returns the string "Hello, World!". +- Run the test suite and make sure that it succeeds. +- Submit your solution and check it at the website. + +If everything goes well, you will be ready to fetch your first real exercise. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/hello-world/src/lib.rs b/rust/hello-world/src/lib.rs new file mode 100644 index 0000000..8f68273 --- /dev/null +++ b/rust/hello-world/src/lib.rs @@ -0,0 +1,5 @@ +// The &'static here means the return type has a static lifetime. +// This is a Rust feature that you don't need to worry about now. +pub fn hello() -> &'static str { + "Hello, World!" +} diff --git a/rust/hello-world/tests/hello-world.rs b/rust/hello-world/tests/hello-world.rs new file mode 100644 index 0000000..c0d9536 --- /dev/null +++ b/rust/hello-world/tests/hello-world.rs @@ -0,0 +1,6 @@ +use hello_world; + +#[test] +fn test_hello_world() { + assert_eq!("Hello, World!", hello_world::hello()); +} diff --git a/rust/high-scores/.exercism/metadata.json b/rust/high-scores/.exercism/metadata.json new file mode 100644 index 0000000..467784c --- /dev/null +++ b/rust/high-scores/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"high-scores","id":"4454fe8e84a84eb9860d6790c283b2c3","url":"https://exercism.io/my/solutions/4454fe8e84a84eb9860d6790c283b2c3","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/high-scores/.gitignore b/rust/high-scores/.gitignore new file mode 100644 index 0000000..e130ceb --- /dev/null +++ b/rust/high-scores/.gitignore @@ -0,0 +1,8 @@ +# Generated by exercism rust track exercise tool +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/high-scores/Cargo.toml b/rust/high-scores/Cargo.toml new file mode 100644 index 0000000..f4d70fe --- /dev/null +++ b/rust/high-scores/Cargo.toml @@ -0,0 +1,6 @@ +[dependencies] + +[package] +edition = "2018" +name = "high-scores" +version = "4.0.0" diff --git a/rust/high-scores/README.md b/rust/high-scores/README.md new file mode 100644 index 0000000..f60b890 --- /dev/null +++ b/rust/high-scores/README.md @@ -0,0 +1,95 @@ +# High Scores + +Manage a game player's High Score list. + +Your task is to build a high-score component of the classic Frogger +game, one of the highest selling and addictive games of all time, and a +classic of the arcade era. Your task is to write methods that return the +highest score from the list, the last added score and the three highest +scores. + +## Hints + +Consider retaining a reference to `scores` in the struct - copying is not +necessary. You will require some lifetime annotations, though. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Tribute to the eighties' arcade game Frogger + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/high-scores/src/lib.rs b/rust/high-scores/src/lib.rs new file mode 100644 index 0000000..a7e6c3d --- /dev/null +++ b/rust/high-scores/src/lib.rs @@ -0,0 +1,29 @@ +#[derive(Debug)] +pub struct HighScores<'a> { + scores: &'a [u32] +} + +impl<'a> HighScores<'a> { + pub fn new(scores: &'a [u32]) -> Self { + HighScores{ scores } + } + + pub fn scores(&self) -> &[u32] { + self.scores + } + + pub fn latest(&self) -> Option { + self.scores.last().copied() + } + + pub fn personal_best(&self) -> Option { + self.scores.iter().max().copied() + } + + pub fn personal_top_three(&self) -> Vec { + let mut top3 = self.scores.to_vec(); + top3.sort_unstable_by(|a,b| b.cmp(a)); + top3.truncate(3); + top3 + } +} diff --git a/rust/high-scores/tests/high-scores.rs b/rust/high-scores/tests/high-scores.rs new file mode 100644 index 0000000..4d2feb7 --- /dev/null +++ b/rust/high-scores/tests/high-scores.rs @@ -0,0 +1,68 @@ +use high_scores::HighScores; + +#[test] +fn test_list_of_scores() { + let expected = [30, 50, 20, 70]; + let high_scores = HighScores::new(&expected); + assert_eq!(high_scores.scores(), &expected); +} + +#[test] +fn test_latest_score() { + let high_scores = HighScores::new(&[100, 0, 90, 30]); + assert_eq!(high_scores.latest(), Some(30)); +} + +#[test] +fn test_latest_score_empty() { + let high_scores = HighScores::new(&[]); + assert_eq!(high_scores.latest(), None); +} + +#[test] +fn test_personal_best() { + let high_scores = HighScores::new(&[40, 100, 70]); + assert_eq!(high_scores.personal_best(), Some(100)); +} + +#[test] +fn test_personal_best_empty() { + let high_scores = HighScores::new(&[]); + assert_eq!(high_scores.personal_best(), None); +} + +#[test] +fn test_personal_top_three() { + let high_scores = HighScores::new(&[10, 30, 90, 30, 100, 20, 10, 0, 30, 40, 40, 70, 70]); + assert_eq!(high_scores.personal_top_three(), vec![100, 90, 70]); +} + +#[test] +fn test_personal_top_three_highest_to_lowest() { + let high_scores = HighScores::new(&[20, 10, 30]); + assert_eq!(high_scores.personal_top_three(), vec![30, 20, 10]); +} + +#[test] +fn test_personal_top_three_with_tie() { + let high_scores = HighScores::new(&[40, 20, 40, 30]); + assert_eq!(high_scores.personal_top_three(), vec![40, 40, 30]); +} + +#[test] +fn test_personal_top_three_with_less_than_three_scores() { + let high_scores = HighScores::new(&[30, 70]); + assert_eq!(high_scores.personal_top_three(), vec![70, 30]); +} + +#[test] +fn test_personal_top_three_only_one_score() { + let high_scores = HighScores::new(&[40]); + assert_eq!(high_scores.personal_top_three(), vec![40]); +} + +#[test] +fn test_personal_top_three_empty() { + let high_scores = HighScores::new(&[]); + assert!(high_scores.personal_top_three().is_empty()); +} diff --git a/rust/leap/.exercism/metadata.json b/rust/leap/.exercism/metadata.json new file mode 100644 index 0000000..1ec33f3 --- /dev/null +++ b/rust/leap/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"leap","id":"bc3b9538660b445abd5c2ee1398141db","url":"https://exercism.io/my/solutions/bc3b9538660b445abd5c2ee1398141db","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/leap/.gitignore b/rust/leap/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/leap/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/leap/Cargo.toml b/rust/leap/Cargo.toml new file mode 100644 index 0000000..c125e67 --- /dev/null +++ b/rust/leap/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "leap" +version = "1.6.0" diff --git a/rust/leap/README.md b/rust/leap/README.md new file mode 100644 index 0000000..6a6bac4 --- /dev/null +++ b/rust/leap/README.md @@ -0,0 +1,105 @@ +# Leap Given a year, report if it is a leap year. + +The tricky thing here is that a leap year in the Gregorian calendar occurs: + +```text +on every year that is evenly divisible by 4 +except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +## Notes + +Though our exercise adopts some very simple rules, there is more to +learn! + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + +You may use the [`arithmetic remainder` operator](https://doc.rust-lang.org/book/appendix-02-operators.html) to test for divisibility. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +JavaRanch Cattle Drive, exercise 3 [http://www.javaranch.com/leap.jsp](http://www.javaranch.com/leap.jsp) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/leap/src/lib.rs b/rust/leap/src/lib.rs new file mode 100644 index 0000000..1b40300 --- /dev/null +++ b/rust/leap/src/lib.rs @@ -0,0 +1,3 @@ +pub fn is_leap_year(year: u64) -> bool { + year % 4 == 0 && year % 100 != 0 || year % 400 == 0 +} diff --git a/rust/leap/tests/leap.rs b/rust/leap/tests/leap.rs new file mode 100644 index 0000000..88d2c77 --- /dev/null +++ b/rust/leap/tests/leap.rs @@ -0,0 +1,89 @@ +use leap; + +fn process_leapyear_case(year: u64, expected: bool) { + assert_eq!(leap::is_leap_year(year), expected); +} + +#[test] +fn test_year_not_divisible_by_4_common_year() { + process_leapyear_case(2015, false); +} + +#[test] +fn test_year_divisible_by_2_not_divisible_by_4_in_common_year() { + process_leapyear_case(1970, false); +} + +#[test] +fn test_year_divisible_by_4_not_divisible_by_100_leap_year() { + process_leapyear_case(1996, true); +} + +#[test] +fn test_year_divisible_by_4_and_5_is_still_a_leap_year() { + process_leapyear_case(1960, true); +} + +#[test] +fn test_year_divisible_by_100_not_divisible_by_400_common_year() { + process_leapyear_case(2100, false); +} + +#[test] +fn test_year_divisible_by_100_but_not_by_3_is_still_not_a_leap_year() { + process_leapyear_case(1900, false); +} + +#[test] +fn test_year_divisible_by_400_leap_year() { + process_leapyear_case(2000, true); +} + +#[test] +fn test_year_divisible_by_400_but_not_by_125_is_still_a_leap_year() { + process_leapyear_case(2400, true); +} + +#[test] +fn test_year_divisible_by_200_not_divisible_by_400_common_year() { + process_leapyear_case(1800, false); +} + +#[test] +fn test_any_old_year() { + assert_eq!(leap::is_leap_year(1997), false); +} + +#[test] +fn test_early_years() { + assert_eq!(leap::is_leap_year(1), false); + assert_eq!(leap::is_leap_year(4), true); + assert_eq!(leap::is_leap_year(100), false); + assert_eq!(leap::is_leap_year(400), true); + assert_eq!(leap::is_leap_year(900), false); +} + +#[test] +fn test_century() { + assert_eq!(leap::is_leap_year(1700), false); + assert_eq!(leap::is_leap_year(1800), false); + assert_eq!(leap::is_leap_year(1900), false); +} + +#[test] +fn test_exceptional_centuries() { + assert_eq!(leap::is_leap_year(1600), true); + assert_eq!(leap::is_leap_year(2000), true); + assert_eq!(leap::is_leap_year(2400), true); +} + +#[test] +fn test_years_1600_to_1699() { + let incorrect_years = (1600..1700) + .filter(|&year| leap::is_leap_year(year) != (year % 4 == 0)) + .collect::>(); + + if !incorrect_years.is_empty() { + panic!("incorrect result for years: {:?}", incorrect_years); + } +} diff --git a/rust/matching-brackets/.exercism/metadata.json b/rust/matching-brackets/.exercism/metadata.json new file mode 100644 index 0000000..7b5495d --- /dev/null +++ b/rust/matching-brackets/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"matching-brackets","id":"568307886f5d4f38afb0394b1e981c76","url":"https://exercism.io/my/solutions/568307886f5d4f38afb0394b1e981c76","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/matching-brackets/.gitignore b/rust/matching-brackets/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/matching-brackets/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/matching-brackets/Cargo.toml b/rust/matching-brackets/Cargo.toml new file mode 100644 index 0000000..2e7dafa --- /dev/null +++ b/rust/matching-brackets/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "matching-brackets" +version = "2.0.0" diff --git a/rust/matching-brackets/README.md b/rust/matching-brackets/README.md new file mode 100644 index 0000000..049e3fa --- /dev/null +++ b/rust/matching-brackets/README.md @@ -0,0 +1,85 @@ +# Matching Brackets + +Given a string containing brackets `[]`, braces `{}`, parentheses `()`, +or any combination thereof, verify that any and all pairs are matched +and nested correctly. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Ginna Baker + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/matching-brackets/src/lib.rs b/rust/matching-brackets/src/lib.rs new file mode 100644 index 0000000..03e39ca --- /dev/null +++ b/rust/matching-brackets/src/lib.rs @@ -0,0 +1,12 @@ +pub fn brackets_are_balanced(string: &str) -> bool { + let mut stack = vec![]; + for c in string.chars() { + match c { + '(' => stack.push(((c as u8) + 1) as char), + '[' | '{' => stack.push(((c as u8) + 2) as char), + ')' | ']' | '}' if stack.pop() != Some(c) => return false, + _ => () + } + } + stack.is_empty() +} diff --git a/rust/matching-brackets/tests/matching-brackets.rs b/rust/matching-brackets/tests/matching-brackets.rs new file mode 100644 index 0000000..0826dad --- /dev/null +++ b/rust/matching-brackets/tests/matching-brackets.rs @@ -0,0 +1,98 @@ +use matching_brackets::brackets_are_balanced; + +#[test] +fn paired_square_brackets() { + assert!(brackets_are_balanced("[]")); +} + +#[test] +fn empty_string() { + assert!(brackets_are_balanced("")); +} + +#[test] +fn unpaired_brackets() { + assert!(!brackets_are_balanced("[[")); +} + +#[test] +fn wrong_ordered_brackets() { + assert!(!brackets_are_balanced("}{")); +} + +#[test] +fn wrong_closing_bracket() { + assert!(!brackets_are_balanced("{]")); +} + +#[test] +fn paired_with_whitespace() { + assert!(brackets_are_balanced("{ }")); +} + +#[test] +fn partially_paired_brackets() { + assert!(!brackets_are_balanced("{[])")); +} + +#[test] +fn simple_nested_brackets() { + assert!(brackets_are_balanced("{[]}")); +} + +#[test] +fn several_paired_brackets() { + assert!(brackets_are_balanced("{}[]")); +} + +#[test] +fn paired_and_nested_brackets() { + assert!(brackets_are_balanced("([{}({}[])])")); +} + +#[test] +fn unopened_closing_brackets() { + assert!(!brackets_are_balanced("{[)][]}")); +} + +#[test] +fn unpaired_and_nested_brackets() { + assert!(!brackets_are_balanced("([{])")); +} + +#[test] +fn paired_and_wrong_nested_brackets() { + assert!(!brackets_are_balanced("[({]})")); +} + +#[test] +fn paired_and_incomplete_brackets() { + assert!(!brackets_are_balanced("{}[")); +} + +#[test] +fn too_many_closing_brackets() { + assert!(!brackets_are_balanced("[]]")); +} + +#[test] +fn early_incomplete_brackets() { + assert!(!brackets_are_balanced(")()")); +} + +#[test] +fn early_mismatched_brackets() { + assert!(!brackets_are_balanced("{)()")); +} + +#[test] +fn math_expression() { + assert!(brackets_are_balanced("(((185 + 223.85) * 15) - 543)/2")); +} + +#[test] +fn complex_latex_expression() { + let input = "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \ + \\end{array}\\right)"; + assert!(brackets_are_balanced(input)); +} diff --git a/rust/nth-prime/.exercism/metadata.json b/rust/nth-prime/.exercism/metadata.json new file mode 100644 index 0000000..5c5337e --- /dev/null +++ b/rust/nth-prime/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"nth-prime","id":"7ed3faca556f4c23a55b30fae8b69047","url":"https://exercism.io/my/solutions/7ed3faca556f4c23a55b30fae8b69047","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/nth-prime/.gitignore b/rust/nth-prime/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/nth-prime/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/nth-prime/Cargo.toml b/rust/nth-prime/Cargo.toml new file mode 100644 index 0000000..fc1c776 --- /dev/null +++ b/rust/nth-prime/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2018" +name = "nth_prime" +version = "2.1.0" + +[dependencies] diff --git a/rust/nth-prime/README.md b/rust/nth-prime/README.md new file mode 100644 index 0000000..425abde --- /dev/null +++ b/rust/nth-prime/README.md @@ -0,0 +1,92 @@ +# Nth Prime + +Given a number n, determine what the nth prime is. + +By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that +the 6th prime is 13. + +If your language provides methods in the standard library to deal with prime +numbers, pretend they don't exist and implement them yourself. + +Remember that while people commonly count with 1-based indexing (i.e. "the 6th prime is 13"), many programming languages, including Rust, use 0-based indexing (i.e. `primes[5] == 13`). Use 0-based indexing for your implementation. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +A variation on Problem 7 at Project Euler [http://projecteuler.net/problem=7](http://projecteuler.net/problem=7) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/nth-prime/src/lib.rs b/rust/nth-prime/src/lib.rs new file mode 100644 index 0000000..ef9d7ea --- /dev/null +++ b/rust/nth-prime/src/lib.rs @@ -0,0 +1,8 @@ +fn is_prime(n: u32) -> bool { + let limit = (n as f64).sqrt() as u32; + (2..=limit).all(|x| n % x != 0) +} + +pub fn nth(n: u32) -> u32 { + (2..).filter(|x| is_prime(*x)).nth(n as usize).unwrap() +} diff --git a/rust/nth-prime/tests/nth-prime.rs b/rust/nth-prime/tests/nth-prime.rs new file mode 100644 index 0000000..b313ff2 --- /dev/null +++ b/rust/nth-prime/tests/nth-prime.rs @@ -0,0 +1,21 @@ +use nth_prime as np; + +#[test] +fn test_first_prime() { + assert_eq!(np::nth(0), 2); +} + +#[test] +fn test_second_prime() { + assert_eq!(np::nth(1), 3); +} + +#[test] +fn test_sixth_prime() { + assert_eq!(np::nth(5), 13); +} + +#[test] +fn test_big_prime() { + assert_eq!(np::nth(10_000), 104_743); +} diff --git a/rust/nucleotide-count/.exercism/metadata.json b/rust/nucleotide-count/.exercism/metadata.json new file mode 100644 index 0000000..3cb94c8 --- /dev/null +++ b/rust/nucleotide-count/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"nucleotide-count","id":"2e44b94b9e1648c2876e1882f15bd9de","url":"https://exercism.io/my/solutions/2e44b94b9e1648c2876e1882f15bd9de","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/nucleotide-count/.gitignore b/rust/nucleotide-count/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/nucleotide-count/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/nucleotide-count/Cargo.toml b/rust/nucleotide-count/Cargo.toml new file mode 100644 index 0000000..3eb8759 --- /dev/null +++ b/rust/nucleotide-count/Cargo.toml @@ -0,0 +1,7 @@ +[package] +edition = "2018" +name = "nucleotide-count" +version = "1.3.0" + +[dependencies] +maplit = "1.0.1" diff --git a/rust/nucleotide-count/README.md b/rust/nucleotide-count/README.md new file mode 100644 index 0000000..9a85942 --- /dev/null +++ b/rust/nucleotide-count/README.md @@ -0,0 +1,110 @@ +# Nucleotide Count + +Each of us inherits from our biological parents a set of chemical +instructions known as DNA that influence how our bodies are constructed. +All known life depends on DNA! + +> Note: You do not need to understand anything about nucleotides or DNA +> to complete this exercise. + +DNA is a long chain of other chemicals and the most important are the +four nucleotides, adenine, cytosine, guanine and thymine. A single DNA +chain can contain billions of these four nucleotides and the order in +which they occur is important! We call the order of these nucleotides in +a bit of DNA a "DNA sequence". + +We represent a DNA sequence as an ordered collection of these four +nucleotides and a common way to do that is with a string of characters +such as "ATTACG" for a DNA sequence of 6 nucleotides. 'A' for adenine, +'C' for cytosine, 'G' for guanine, and 'T' for thymine. + +Given a string representing a DNA sequence, count how many of each +nucleotide is present. If the string contains characters that aren't A, +C, G, or T then it is invalid and you should signal an error. + +For example: + +``` +"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2 +"INVALID" -> error +``` + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +The Calculating DNA Nucleotides_problem at Rosalind [http://rosalind.info/problems/dna/](http://rosalind.info/problems/dna/) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/nucleotide-count/src/lib.rs b/rust/nucleotide-count/src/lib.rs new file mode 100644 index 0000000..98b0c38 --- /dev/null +++ b/rust/nucleotide-count/src/lib.rs @@ -0,0 +1,21 @@ +use maplit::hashmap; +use std::collections::HashMap; + +pub fn count(nucleotide: char, dna: &str) -> Result { + nucleotide_counts(dna)? + .remove(&nucleotide) + .ok_or(nucleotide) +} + +pub fn nucleotide_counts(dna: &str) -> Result, char> { + dna.chars().fold( + Ok(hashmap![ 'A' => 0, 'C' => 0, 'G' => 0, 'T' => 0 ]), + |acc, n| match n { + 'A' | 'C' | 'G' | 'T' => acc.map(|mut hmap| { + hmap.entry(n).and_modify(|e| *e += 1).or_insert(0); + hmap + }), + _ => Err(n), + }, + ) +} diff --git a/rust/nucleotide-count/tests/nucleotide-count.rs b/rust/nucleotide-count/tests/nucleotide-count.rs new file mode 100644 index 0000000..8190580 --- /dev/null +++ b/rust/nucleotide-count/tests/nucleotide-count.rs @@ -0,0 +1,88 @@ +use nucleotide_count as dna; + +use std::collections::HashMap; + +fn process_nucleotidecounts_case(s: &str, pairs: &[(char, usize)]) { + // The reason for the awkward code in here is to ensure that the failure + // message for assert_eq! is as informative as possible. A simpler + // solution would simply check the length of the map, and then + // check for the presence and value of each key in the given pairs vector. + let mut m: HashMap = dna::nucleotide_counts(s).unwrap(); + for &(k, v) in pairs.iter() { + assert_eq!((k, m.remove(&k)), (k, Some(v))); + } + + // may fail with a message that clearly shows all extra pairs in the map + assert_eq!(m.iter().collect::>(), vec![]); +} + +#[test] +fn count_returns_result() { + assert!(dna::count('A', "").is_ok()); +} + +#[test] +fn test_count_empty() { + assert_eq!(dna::count('A', ""), Ok(0)); +} + +#[test] +fn count_invalid_nucleotide() { + assert_eq!(dna::count('X', "A"), Err('X')); +} + +#[test] +fn count_invalid_dna() { + assert_eq!(dna::count('A', "AX"), Err('X')); +} + +#[test] +fn test_count_repetitive_cytosine() { + assert_eq!(dna::count('C', "CCCCC"), Ok(5)); +} + +#[test] +fn test_count_only_thymine() { + assert_eq!(dna::count('T', "GGGGGTAACCCGG"), Ok(1)); +} + +#[test] +fn counts_returns_result() { + assert!(dna::nucleotide_counts("ACGT").is_ok()); +} + +#[test] +fn test_empty_strand() { + process_nucleotidecounts_case("", &[('A', 0), ('T', 0), ('C', 0), ('G', 0)]); +} + +#[test] +/// can count one nucleotide in single-character input +fn test_can_count_one_nucleotide_in_singlecharacter_input() { + process_nucleotidecounts_case("G", &[('A', 0), ('C', 0), ('G', 1), ('T', 0)]); +} + +#[test] +fn test_strand_with_repeated_nucleotide() { + process_nucleotidecounts_case("GGGGGGG", &[('A', 0), ('T', 0), ('C', 0), ('G', 7)]); +} + +#[test] +/// strand with multiple nucleotides +fn test_strand_with_multiple_nucleotides() { + process_nucleotidecounts_case( + "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC", + &[('A', 20), ('T', 21), ('C', 12), ('G', 17)], + ); +} + +#[test] +fn counts_invalid_nucleotide_results_in_err() { + assert_eq!(dna::nucleotide_counts("GGXXX"), Err('X')); +} + +#[test] +/// strand with invalid nucleotides +fn test_strand_with_invalid_nucleotides() { + assert_eq!(dna::nucleotide_counts("AGXXACT"), Err('X'),); +} diff --git a/rust/paasio/.exercism/metadata.json b/rust/paasio/.exercism/metadata.json new file mode 100644 index 0000000..e6e8012 --- /dev/null +++ b/rust/paasio/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"paasio","id":"6ac29a8082a94a0a91b43185846bcfe7","url":"https://exercism.io/my/solutions/6ac29a8082a94a0a91b43185846bcfe7","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/paasio/.gitignore b/rust/paasio/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/paasio/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/paasio/Cargo.toml b/rust/paasio/Cargo.toml new file mode 100644 index 0000000..83a8e73 --- /dev/null +++ b/rust/paasio/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "paasio" +version = "0.0.0" diff --git a/rust/paasio/README.md b/rust/paasio/README.md new file mode 100644 index 0000000..03e5a4d --- /dev/null +++ b/rust/paasio/README.md @@ -0,0 +1,102 @@ +# PaaS I/O + +Report network IO statistics. + +You are writing a [PaaS][], and you need a way to bill customers based +on network and filesystem usage. + +Create a wrapper for network connections and files that can report IO +statistics. The wrapper must report: + +- The total number of bytes read/written. +- The total number of read/write operations. + +[PaaS]: http://en.wikipedia.org/wiki/Platform_as_a_service + +## Abstraction over Networks and Files + +Network and file operations are implemented in terms of the [`io::Read`][read] and [`io::Write`][write] traits. It will therefore be necessary to implement those traits for your types. + +[read]: https://doc.rust-lang.org/std/io/trait.Read.html +[write]: https://doc.rust-lang.org/std/io/trait.Write.html + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Brian Matsuo [https://github.com/bmatsuo](https://github.com/bmatsuo) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/paasio/src/lib.rs b/rust/paasio/src/lib.rs new file mode 100644 index 0000000..71f4c9d --- /dev/null +++ b/rust/paasio/src/lib.rs @@ -0,0 +1,82 @@ +use std::io::{Read, Result, Write}; + +pub struct ReadStats { + source: R, + reads: usize, + bytes: usize, +} + +impl ReadStats { + pub fn new(wrapped: R) -> ReadStats { + ReadStats { + source: wrapped, + reads: 0, + bytes: 0, + } + } + + pub fn get_ref(&self) -> &R { + &self.source + } + + pub fn bytes_through(&self) -> usize { + self.bytes + } + + pub fn reads(&self) -> usize { + self.reads + } +} + +impl Read for ReadStats { + fn read(&mut self, buf: &mut [u8]) -> Result { + let bytes = self.source.read(buf)?; + self.reads += 1; + self.bytes += bytes; + Ok(bytes) + } +} + +pub struct WriteStats { + sink: W, + writes: usize, + bytes: usize, +} + +impl WriteStats { + // _wrapped is ignored because W is not bounded on Debug or Display and therefore + // can't be passed through format!(). For actual implementation you will likely + // wish to remove the leading underscore so the variable is not ignored. + pub fn new(wrapped: W) -> WriteStats { + WriteStats { + sink: wrapped, + writes: 0, + bytes: 0, + } + } + + pub fn get_ref(&self) -> &W { + &self.sink + } + + pub fn bytes_through(&self) -> usize { + self.bytes + } + + pub fn writes(&self) -> usize { + self.writes + } +} + +impl Write for WriteStats { + fn write(&mut self, buf: &[u8]) -> Result { + let bytes = self.sink.write(buf)?; + self.writes += 1; + self.bytes += bytes; + Ok(bytes) + } + + fn flush(&mut self) -> Result<()> { + self.sink.flush() + } +} diff --git a/rust/paasio/tests/paasio.rs b/rust/paasio/tests/paasio.rs new file mode 100644 index 0000000..6b44199 --- /dev/null +++ b/rust/paasio/tests/paasio.rs @@ -0,0 +1,192 @@ +/// test a few read scenarios +macro_rules! test_read { + ($(#[$attr:meta])* $modname:ident ($input:expr, $len:expr)) => { + mod $modname { + use std::io::{Read, BufReader}; + use paasio::*; + + const CHUNK_SIZE: usize = 2; + + $(#[$attr])* + #[test] + fn test_read_passthrough() { + let data = $input; + let size = $len(&data); + let mut reader = ReadStats::new(data); + + let mut buffer = Vec::with_capacity(size); + let qty_read = reader.read_to_end(&mut buffer); + + assert!(qty_read.is_ok()); + assert_eq!(size, qty_read.unwrap()); + assert_eq!(size, buffer.len()); + // 2: first to read all the data, second to check that + // there wasn't any more pending data which simply didn't + // fit into the existing buffer + assert_eq!(2, reader.reads()); + assert_eq!(size, reader.bytes_through()); + } + + $(#[$attr])* + #[test] + fn test_read_chunks() { + let data = $input; + let size = $len(&data); + let mut reader = ReadStats::new(data); + + let mut buffer = [0_u8; CHUNK_SIZE]; + let mut chunks_read = 0; + while reader.read(&mut buffer[..]).unwrap_or_else(|_| panic!("read failed at chunk {}", chunks_read+1)) > 0 { + chunks_read += 1; + } + + assert_eq!(size / CHUNK_SIZE + std::cmp::min(1, size % CHUNK_SIZE), chunks_read); + // we read once more than the number of chunks, because the final + // read returns 0 new bytes + assert_eq!(1+chunks_read, reader.reads()); + assert_eq!(size, reader.bytes_through()); + } + + $(#[$attr])* + #[test] + fn test_read_buffered_chunks() { + let data = $input; + let size = $len(&data); + let mut reader = BufReader::new(ReadStats::new(data)); + + let mut buffer = [0_u8; CHUNK_SIZE]; + let mut chunks_read = 0; + while reader.read(&mut buffer[..]).unwrap_or_else(|_| panic!("read failed at chunk {}", chunks_read+1)) > 0 { + chunks_read += 1; + } + + assert_eq!(size / CHUNK_SIZE + std::cmp::min(1, size % CHUNK_SIZE), chunks_read); + // the BufReader should smooth out the reads, collecting into + // a buffer and performing only two read operations: + // the first collects everything into the buffer, + // and the second ensures that no data remains + assert_eq!(2, reader.get_ref().reads()); + assert_eq!(size, reader.get_ref().bytes_through()); + } + } + }; +} + +/// test a few write scenarios +macro_rules! test_write { + ($(#[$attr:meta])* $modname:ident ($input:expr, $len:expr)) => { + mod $modname { + use std::io::{self, Write, BufWriter}; + use paasio::*; + + const CHUNK_SIZE: usize = 2; + $(#[$attr])* + #[test] + fn test_write_passthrough() { + let data = $input; + let size = $len(&data); + let mut writer = WriteStats::new(Vec::with_capacity(size)); + let written = writer.write(data); + assert!(written.is_ok()); + assert_eq!(size, written.unwrap()); + assert_eq!(size, writer.bytes_through()); + assert_eq!(1, writer.writes()); + assert_eq!(data, writer.get_ref().as_slice()); + } + + $(#[$attr])* + #[test] + fn test_sink_oneshot() { + let data = $input; + let size = $len(&data); + let mut writer = WriteStats::new(io::sink()); + let written = writer.write(data); + assert!(written.is_ok()); + assert_eq!(size, written.unwrap()); + assert_eq!(size, writer.bytes_through()); + assert_eq!(1, writer.writes()); + } + + $(#[$attr])* + #[test] + fn test_sink_windowed() { + let data = $input; + let size = $len(&data); + let mut writer = WriteStats::new(io::sink()); + + let mut chunk_count = 0; + for chunk in data.chunks(CHUNK_SIZE) { + chunk_count += 1; + let written = writer.write(chunk); + assert!(written.is_ok()); + assert_eq!(CHUNK_SIZE, written.unwrap()); + } + assert_eq!(size, writer.bytes_through()); + assert_eq!(chunk_count, writer.writes()); + } + + $(#[$attr])* + #[test] + fn test_sink_buffered_windowed() { + let data = $input; + let size = $len(&data); + let mut writer = BufWriter::new(WriteStats::new(io::sink())); + + for chunk in data.chunks(CHUNK_SIZE) { + let written = writer.write(chunk); + assert!(written.is_ok()); + assert_eq!(CHUNK_SIZE, written.unwrap()); + } + // at this point, nothing should have yet been passed through to + // our writer + assert_eq!(0, writer.get_ref().bytes_through()); + assert_eq!(0, writer.get_ref().writes()); + + // after flushing, everything should pass through in one go + assert!(writer.flush().is_ok()); + assert_eq!(size, writer.get_ref().bytes_through()); + assert_eq!(1, writer.get_ref().writes()); + } + } + }; +} + +#[test] +fn test_create_stats() { + let mut data: Vec = Vec::new(); + let _ = paasio::ReadStats::new(data.as_slice()); + let _ = paasio::WriteStats::new(data.as_mut_slice()); +} + +test_read!(read_string ( + "Twas brillig, and the slithy toves/Did gyre and gimble in the wabe:/All mimsy were the borogoves,/And the mome raths outgrabe.".as_bytes(), + |d: &[u8]| d.len() +)); +test_write!(write_string ( + "Beware the Jabberwock, my son!/The jaws that bite, the claws that catch!/Beware the Jubjub bird, and shun/The frumious Bandersnatch!".as_bytes(), + |d: &[u8]| d.len() +)); + +test_read!(read_byte_literal( + &[1_u8, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144][..], + |d: &[u8]| d.len() +)); +test_write!(write_byte_literal( + &[2_u8, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,][..], + |d: &[u8]| d.len() +)); + +test_read!(read_file( + ::std::fs::File::open("README.md").expect("readme must be present"), + |f: &::std::fs::File| f.metadata().expect("metadata must be present").len() as usize +)); + +#[test] +fn read_stats_by_ref_returns_wrapped_reader() { + use paasio::ReadStats; + + let input = + "Why, sometimes I've believed as many as six impossible things before breakfast".as_bytes(); + let reader = ReadStats::new(input); + assert_eq!(reader.get_ref(), &input); +} diff --git a/rust/pascals-triangle/.exercism/metadata.json b/rust/pascals-triangle/.exercism/metadata.json new file mode 100644 index 0000000..7352c3c --- /dev/null +++ b/rust/pascals-triangle/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"pascals-triangle","id":"1186776428ea49b494e3cd0bd68308bc","url":"https://exercism.io/my/solutions/1186776428ea49b494e3cd0bd68308bc","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/pascals-triangle/.gitignore b/rust/pascals-triangle/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/pascals-triangle/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/pascals-triangle/Cargo.toml b/rust/pascals-triangle/Cargo.toml new file mode 100644 index 0000000..d308b66 --- /dev/null +++ b/rust/pascals-triangle/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "pascals-triangle" +version = "1.5.0" diff --git a/rust/pascals-triangle/README.md b/rust/pascals-triangle/README.md new file mode 100644 index 0000000..504b0b3 --- /dev/null +++ b/rust/pascals-triangle/README.md @@ -0,0 +1,95 @@ +# Pascal's Triangle + +Compute Pascal's triangle up to a given number of rows. + +In Pascal's Triangle each number is computed by adding the numbers to +the right and left of the current position in the previous row. + +```text + 1 + 1 1 + 1 2 1 + 1 3 3 1 +1 4 6 4 1 +# ... etc +``` + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Pascal's Triangle at Wolfram Math World [http://mathworld.wolfram.com/PascalsTriangle.html](http://mathworld.wolfram.com/PascalsTriangle.html) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/pascals-triangle/src/lib.rs b/rust/pascals-triangle/src/lib.rs new file mode 100644 index 0000000..7b2145b --- /dev/null +++ b/rust/pascals-triangle/src/lib.rs @@ -0,0 +1,34 @@ +#[derive(Debug)] +pub struct PascalsTriangle { + rows: Vec>, +} + +impl PascalsTriangle { + fn next_row(row: &[u32]) -> Vec { + let mut next = Vec::new(); + let last = row.iter().fold(0, |p, n| { + next.push(p + n); + *n + }); + next.push(last); + next + } +} + +impl PascalsTriangle { + pub fn new(row_count: u32) -> Self { + let mut rows = Vec::new(); + if row_count > 0 { + rows.push(vec![1]); + (1..row_count).for_each(|i| { + let irow = Self::next_row(&rows[(i as usize) - 1]); + rows.push(irow); + }) + } + PascalsTriangle { rows } + } + + pub fn rows(&self) -> Vec> { + self.rows.clone() + } +} diff --git a/rust/pascals-triangle/tests/pascals-triangle.rs b/rust/pascals-triangle/tests/pascals-triangle.rs new file mode 100644 index 0000000..64d2c2e --- /dev/null +++ b/rust/pascals-triangle/tests/pascals-triangle.rs @@ -0,0 +1,96 @@ +use pascals_triangle::*; + +#[test] +fn no_rows() { + let pt = PascalsTriangle::new(0); + let expected: Vec> = Vec::new(); + assert_eq!(expected, pt.rows()); +} + +#[test] +fn one_row() { + let pt = PascalsTriangle::new(1); + let expected: Vec> = vec![vec![1]]; + assert_eq!(expected, pt.rows()); +} + +#[test] +fn two_rows() { + let pt = PascalsTriangle::new(2); + let expected: Vec> = vec![vec![1], vec![1, 1]]; + assert_eq!(expected, pt.rows()); +} + +#[test] +fn three_rows() { + let pt = PascalsTriangle::new(3); + let expected: Vec> = vec![vec![1], vec![1, 1], vec![1, 2, 1]]; + assert_eq!(expected, pt.rows()); +} + +#[test] +fn last_of_four_rows() { + let pt = PascalsTriangle::new(4); + let expected: Vec = vec![1, 3, 3, 1]; + assert_eq!(Some(expected), pt.rows().pop()); +} + +#[test] +fn five_rows() { + let pt = PascalsTriangle::new(5); + let expected: Vec> = vec![ + vec![1], + vec![1, 1], + vec![1, 2, 1], + vec![1, 3, 3, 1], + vec![1, 4, 6, 4, 1], + ]; + assert_eq!(expected, pt.rows()); +} + +#[test] +fn six_rows() { + let pt = PascalsTriangle::new(6); + let expected: Vec> = vec![ + vec![1], + vec![1, 1], + vec![1, 2, 1], + vec![1, 3, 3, 1], + vec![1, 4, 6, 4, 1], + vec![1, 5, 10, 10, 5, 1], + ]; + assert_eq!(expected, pt.rows()); +} + +#[test] +fn seven_rows() { + let pt = PascalsTriangle::new(7); + let expected: Vec> = vec![ + vec![1], + vec![1, 1], + vec![1, 2, 1], + vec![1, 3, 3, 1], + vec![1, 4, 6, 4, 1], + vec![1, 5, 10, 10, 5, 1], + vec![1, 6, 15, 20, 15, 6, 1], + ]; + assert_eq!(expected, pt.rows()); +} + +#[test] +fn ten_rows() { + let pt = PascalsTriangle::new(10); + let expected: Vec> = vec![ + vec![1], + vec![1, 1], + vec![1, 2, 1], + vec![1, 3, 3, 1], + vec![1, 4, 6, 4, 1], + vec![1, 5, 10, 10, 5, 1], + vec![1, 6, 15, 20, 15, 6, 1], + vec![1, 7, 21, 35, 35, 21, 7, 1], + vec![1, 8, 28, 56, 70, 56, 28, 8, 1], + vec![1, 9, 36, 84, 126, 126, 84, 36, 9, 1], + ]; + assert_eq!(expected, pt.rows()); +} diff --git a/rust/prime-factors/.exercism/metadata.json b/rust/prime-factors/.exercism/metadata.json new file mode 100644 index 0000000..293742a --- /dev/null +++ b/rust/prime-factors/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"prime-factors","id":"a0a637c86ddc4aa2b63cfe05a163292d","url":"https://exercism.io/my/solutions/a0a637c86ddc4aa2b63cfe05a163292d","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/prime-factors/.gitignore b/rust/prime-factors/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/prime-factors/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/prime-factors/Cargo.toml b/rust/prime-factors/Cargo.toml new file mode 100644 index 0000000..70727e6 --- /dev/null +++ b/rust/prime-factors/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2018" +name = "prime_factors" +version = "1.1.0" + +[dependencies] diff --git a/rust/prime-factors/README.md b/rust/prime-factors/README.md new file mode 100644 index 0000000..f106dde --- /dev/null +++ b/rust/prime-factors/README.md @@ -0,0 +1,110 @@ +# Prime Factors + +Compute the prime factors of a given natural number. + +A prime number is only evenly divisible by itself and 1. + +Note that 1 is not a prime number. + +## Example + +What are the prime factors of 60? + +- Our first divisor is 2. 2 goes into 60, leaving 30. +- 2 goes into 30, leaving 15. + - 2 doesn't go cleanly into 15. So let's move on to our next divisor, 3. +- 3 goes cleanly into 15, leaving 5. + - 3 does not go cleanly into 5. The next possible factor is 4. + - 4 does not go cleanly into 5. The next possible factor is 5. +- 5 does go cleanly into 5. +- We're left only with 1, so now, we're done. + +Our successful divisors in that computation represent the list of prime +factors of 60: 2, 2, 3, and 5. + +You can check this yourself: + +- 2 * 2 * 3 * 5 +- = 4 * 15 +- = 60 +- Success! + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +The Prime Factors Kata by Uncle Bob [http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata](http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/prime-factors/src/lib.rs b/rust/prime-factors/src/lib.rs new file mode 100644 index 0000000..3d7b41f --- /dev/null +++ b/rust/prime-factors/src/lib.rs @@ -0,0 +1,18 @@ + +fn factors_aux(mut vec: Vec, n: u64) -> Vec { + match n { + 1 => vec, + n if n % 2 == 0 => { + factors_aux({ vec.push(2); vec }, n / 2) + }, + _ => { + let mut i: u64 = 3; + while n % i != 0 { i += 2 } + factors_aux({ vec.push(i); vec }, n / i) + } + } +} + +pub fn factors(n: u64) -> Vec { + factors_aux(vec![],n) +} diff --git a/rust/prime-factors/tests/prime-factors.rs b/rust/prime-factors/tests/prime-factors.rs new file mode 100644 index 0000000..1042415 --- /dev/null +++ b/rust/prime-factors/tests/prime-factors.rs @@ -0,0 +1,36 @@ +use prime_factors::factors; + +#[test] +fn test_no_factors() { + assert_eq!(factors(1), vec![]); +} + +#[test] +fn test_prime_number() { + assert_eq!(factors(2), vec![2]); +} + +#[test] +fn test_square_of_a_prime() { + assert_eq!(factors(9), vec![3, 3]); +} + +#[test] +fn test_cube_of_a_prime() { + assert_eq!(factors(8), vec![2, 2, 2]); +} + +#[test] +fn test_product_of_primes_and_non_primes() { + assert_eq!(factors(12), vec![2, 2, 3]); +} + +#[test] +fn test_product_of_primes() { + assert_eq!(factors(901_255), vec![5, 17, 23, 461]); +} + +#[test] +fn test_factors_include_large_prime() { + assert_eq!(factors(93_819_012_551), vec![11, 9539, 894_119]); +} diff --git a/rust/proverb/.exercism/metadata.json b/rust/proverb/.exercism/metadata.json new file mode 100644 index 0000000..92c8e56 --- /dev/null +++ b/rust/proverb/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"proverb","id":"df96008ca5da43758fca9ac1ee80607e","url":"https://exercism.io/my/solutions/df96008ca5da43758fca9ac1ee80607e","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/proverb/.gitignore b/rust/proverb/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/proverb/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/proverb/Cargo.toml b/rust/proverb/Cargo.toml new file mode 100644 index 0000000..4e09ea1 --- /dev/null +++ b/rust/proverb/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2018" +name = "proverb" +version = "1.1.0" + +[dependencies] diff --git a/rust/proverb/README.md b/rust/proverb/README.md new file mode 100644 index 0000000..b9efe0b --- /dev/null +++ b/rust/proverb/README.md @@ -0,0 +1,97 @@ +# Proverb + +For want of a horseshoe nail, a kingdom was lost, or so the saying goes. + +Given a list of inputs, generate the relevant proverb. For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme: + +```text +For want of a nail the shoe was lost. +For want of a shoe the horse was lost. +For want of a horse the rider was lost. +For want of a rider the message was lost. +For want of a message the battle was lost. +For want of a battle the kingdom was lost. +And all for the want of a nail. +``` + +Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. No line of the output text should be a static, unchanging string; all should vary according to the input given. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Wikipedia [http://en.wikipedia.org/wiki/For_Want_of_a_Nail](http://en.wikipedia.org/wiki/For_Want_of_a_Nail) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/proverb/src/lib.rs b/rust/proverb/src/lib.rs new file mode 100644 index 0000000..1046553 --- /dev/null +++ b/rust/proverb/src/lib.rs @@ -0,0 +1,15 @@ +use std::iter; + +pub fn build_proverb(list: &[&str]) -> String { + if list.is_empty() { + String::new() + } else { + let reason = |(a, b)| format!("For want of a {} the {} was lost.\n", a, b); + let bitter_end = format!("And all for the want of a {}.", list[0]); + list.iter() + .zip(list.iter().skip(1)) // .window(2) also works here + .map(reason) + .chain(iter::once(bitter_end)) + .collect() + } +} diff --git a/rust/proverb/tests/proverb.rs b/rust/proverb/tests/proverb.rs new file mode 100644 index 0000000..220de45 --- /dev/null +++ b/rust/proverb/tests/proverb.rs @@ -0,0 +1,70 @@ +use proverb::build_proverb; + +#[test] +fn test_two_pieces() { + let input = vec!["nail", "shoe"]; + let expected = vec![ + "For want of a nail the shoe was lost.", + "And all for the want of a nail.", + ] + .join("\n"); + assert_eq!(build_proverb(&input), expected); +} + +// Notice the change in the last line at three pieces. +#[test] +fn test_three_pieces() { + let input = vec!["nail", "shoe", "horse"]; + let expected = vec![ + "For want of a nail the shoe was lost.", + "For want of a shoe the horse was lost.", + "And all for the want of a nail.", + ] + .join("\n"); + assert_eq!(build_proverb(&input), expected); +} + +#[test] +fn test_one_piece() { + let input = vec!["nail"]; + let expected = String::from("And all for the want of a nail."); + assert_eq!(build_proverb(&input), expected); +} + +#[test] +fn test_zero_pieces() { + let input: Vec<&str> = vec![]; + let expected = String::new(); + assert_eq!(build_proverb(&input), expected); +} + +#[test] +fn test_full() { + let input = vec![ + "nail", "shoe", "horse", "rider", "message", "battle", "kingdom", + ]; + let expected = vec![ + "For want of a nail the shoe was lost.", + "For want of a shoe the horse was lost.", + "For want of a horse the rider was lost.", + "For want of a rider the message was lost.", + "For want of a message the battle was lost.", + "For want of a battle the kingdom was lost.", + "And all for the want of a nail.", + ] + .join("\n"); + assert_eq!(build_proverb(&input), expected); +} + +#[test] +fn test_three_pieces_modernized() { + let input = vec!["pin", "gun", "soldier", "battle"]; + let expected = vec![ + "For want of a pin the gun was lost.", + "For want of a gun the soldier was lost.", + "For want of a soldier the battle was lost.", + "And all for the want of a pin.", + ] + .join("\n"); + assert_eq!(build_proverb(&input), expected); +} diff --git a/rust/raindrops/.exercism/metadata.json b/rust/raindrops/.exercism/metadata.json new file mode 100644 index 0000000..edfef77 --- /dev/null +++ b/rust/raindrops/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"raindrops","id":"b8fea8a14bc4457f8f0f4f3d152c54c1","url":"https://exercism.io/my/solutions/b8fea8a14bc4457f8f0f4f3d152c54c1","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/raindrops/.gitignore b/rust/raindrops/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/raindrops/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/raindrops/Cargo.toml b/rust/raindrops/Cargo.toml new file mode 100644 index 0000000..f37aa78 --- /dev/null +++ b/rust/raindrops/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "raindrops" +version = "1.1.0" diff --git a/rust/raindrops/README.md b/rust/raindrops/README.md new file mode 100644 index 0000000..3a30435 --- /dev/null +++ b/rust/raindrops/README.md @@ -0,0 +1,96 @@ +# Raindrops + +Your task is to convert a number into a string that contains raindrop sounds corresponding to certain potential factors. A factor is a number that evenly divides into another number, leaving no remainder. The simplest way to test if a one number is a factor of another is to use the [modulo operation](https://en.wikipedia.org/wiki/Modulo_operation). + +The rules of `raindrops` are that if a given number: + +- has 3 as a factor, add 'Pling' to the result. +- has 5 as a factor, add 'Plang' to the result. +- has 7 as a factor, add 'Plong' to the result. +- _does not_ have any of 3, 5, or 7 as a factor, the result should be the digits of the number. + +## Examples + +- 28 has 7 as a factor, but not 3 or 5, so the result would be "Plong". +- 30 has both 3 and 5 as factors, but not 7, so the result would be "PlingPlang". +- 34 is not factored by 3, 5, or 7, so the result would be "34". + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division. [https://en.wikipedia.org/wiki/Fizz_buzz](https://en.wikipedia.org/wiki/Fizz_buzz) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/raindrops/src/lib.rs b/rust/raindrops/src/lib.rs new file mode 100644 index 0000000..811c569 --- /dev/null +++ b/rust/raindrops/src/lib.rs @@ -0,0 +1,28 @@ +struct Drops { + num: u32, + drops: Option +} + +impl Drops { + pub fn new(num: u32) -> Drops { + Drops { num, drops: None } + } + + pub fn add_if_factor(&mut self, div: u32, suffix: &str) { + if self.num % div == 0 { + self.drops.get_or_insert(String::new()).push_str(suffix); + } + } + + pub fn get(self) -> String { + self.drops.unwrap_or(self.num.to_string()) + } +} + +pub fn raindrops(n: u32) -> String { + let mut drops = Drops::new(n); + drops.add_if_factor(3, "Pling"); + drops.add_if_factor(5, "Plang"); + drops.add_if_factor(7, "Plong"); + drops.get() +} diff --git a/rust/raindrops/tests/raindrops.rs b/rust/raindrops/tests/raindrops.rs new file mode 100644 index 0000000..000c639 --- /dev/null +++ b/rust/raindrops/tests/raindrops.rs @@ -0,0 +1,96 @@ +use raindrops; + +#[test] +fn test_1() { + assert_eq!("1", raindrops::raindrops(1)); +} + +#[test] +fn test_3() { + assert_eq!("Pling", raindrops::raindrops(3)); +} + +#[test] +fn test_5() { + assert_eq!("Plang", raindrops::raindrops(5)); +} + +#[test] +fn test_7() { + assert_eq!("Plong", raindrops::raindrops(7)); +} + +#[test] +fn test_6() { + assert_eq!("Pling", raindrops::raindrops(6)); +} + +#[test] +fn test_8() { + assert_eq!("8", raindrops::raindrops(8)); +} + +#[test] +fn test_9() { + assert_eq!("Pling", raindrops::raindrops(9)); +} + +#[test] +fn test_10() { + assert_eq!("Plang", raindrops::raindrops(10)); +} + +#[test] +fn test_14() { + assert_eq!("Plong", raindrops::raindrops(14)); +} + +#[test] +fn test_15() { + assert_eq!("PlingPlang", raindrops::raindrops(15)); +} + +#[test] +fn test_21() { + assert_eq!("PlingPlong", raindrops::raindrops(21)); +} + +#[test] +fn test_25() { + assert_eq!("Plang", raindrops::raindrops(25)); +} + +#[test] +fn test_27() { + assert_eq!("Pling", raindrops::raindrops(27)); +} + +#[test] +fn test_35() { + assert_eq!("PlangPlong", raindrops::raindrops(35)); +} + +#[test] +fn test_49() { + assert_eq!("Plong", raindrops::raindrops(49)); +} + +#[test] +fn test_52() { + assert_eq!("52", raindrops::raindrops(52)); +} + +#[test] +fn test_105() { + assert_eq!("PlingPlangPlong", raindrops::raindrops(105)); +} + +#[test] +fn test_3125() { + assert_eq!("Plang", raindrops::raindrops(3125)); +} + +#[test] +fn test_12121() { + assert_eq!("12121", raindrops::raindrops(12_121)); +} diff --git a/rust/reverse-string/.exercism/metadata.json b/rust/reverse-string/.exercism/metadata.json new file mode 100644 index 0000000..667d0ed --- /dev/null +++ b/rust/reverse-string/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"reverse-string","id":"f735abfd7ff5444fb0f6c68c5fbef1b9","url":"https://exercism.io/my/solutions/f735abfd7ff5444fb0f6c68c5fbef1b9","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/reverse-string/.gitignore b/rust/reverse-string/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/reverse-string/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/reverse-string/Cargo.toml b/rust/reverse-string/Cargo.toml new file mode 100644 index 0000000..bdf501c --- /dev/null +++ b/rust/reverse-string/Cargo.toml @@ -0,0 +1,10 @@ +[dependencies] +unicode-segmentation = "1.3.0" + +[features] +grapheme = [] + +[package] +edition = "2018" +name = "reverse_string" +version = "1.2.0" diff --git a/rust/reverse-string/README.md b/rust/reverse-string/README.md new file mode 100644 index 0000000..78e9753 --- /dev/null +++ b/rust/reverse-string/README.md @@ -0,0 +1,103 @@ +# Reverse String + +Reverse a string + +For example: +input: "cool" +output: "looc" + +## Bonus +Test your function on this string: `uüu` and see what happens. Try to write a function that properly +reverses this string. Hint: grapheme clusters + +To get the bonus test to run, remove the ignore flag (`#[ignore]`) from the +last test, and execute the tests with: + +```bash +$ cargo test --features grapheme +``` + +You will need to use external libraries (a `crate` in rust lingo) for the bonus task. A good place to look for those is [crates.io](https://crates.io/), the official repository of crates. + +[Check the documentation](https://doc.rust-lang.org/cargo/guide/dependencies.html) for instructions on how to use external crates in your projects. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Introductory challenge to reverse an input string [https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb](https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/reverse-string/src/lib.rs b/rust/reverse-string/src/lib.rs new file mode 100644 index 0000000..f488a6e --- /dev/null +++ b/rust/reverse-string/src/lib.rs @@ -0,0 +1,5 @@ +use unicode_segmentation::UnicodeSegmentation; + +pub fn reverse(input: &str) -> String { + UnicodeSegmentation::graphemes(input, true).rev().collect() +} diff --git a/rust/reverse-string/tests/reverse-string.rs b/rust/reverse-string/tests/reverse-string.rs new file mode 100644 index 0000000..9b17bb0 --- /dev/null +++ b/rust/reverse-string/tests/reverse-string.rs @@ -0,0 +1,62 @@ +//! Tests for reverse-string +//! +//! Generated by [script][script] using [canonical data][canonical-data] +//! +//! [script]: https://github.com/exercism/rust/blob/b829ce2/bin/init_exercise.py +//! [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/reverse-string/canonical_data.json + +use reverse_string::*; + +/// Process a single test case for the property `reverse` +fn process_reverse_case(input: &str, expected: &str) { + assert_eq!(&reverse(input), expected) +} + +#[test] +/// empty string +fn test_an_empty_string() { + process_reverse_case("", ""); +} + +#[test] +/// a word +fn test_a_word() { + process_reverse_case("robot", "tobor"); +} + +#[test] +/// a capitalized word +fn test_a_capitalized_word() { + process_reverse_case("Ramen", "nemaR"); +} + +#[test] +/// a sentence with punctuation +fn test_a_sentence_with_punctuation() { + process_reverse_case("I'm hungry!", "!yrgnuh m'I"); +} + +#[test] +/// a palindrome +fn test_a_palindrome() { + process_reverse_case("racecar", "racecar"); +} + +#[test] +/// an even-sized word +fn test_an_even_sized_word() { + process_reverse_case("drawer", "reward"); +} + +#[test] +/// wide characters +fn test_wide_characters() { + process_reverse_case("子猫", "猫子"); +} + +#[test] +#[cfg(feature = "grapheme")] +/// grapheme clusters +fn test_grapheme_clusters() { + process_reverse_case("uüu", "uüu"); +} diff --git a/rust/saddle-points/.exercism/metadata.json b/rust/saddle-points/.exercism/metadata.json new file mode 100644 index 0000000..cb44aa3 --- /dev/null +++ b/rust/saddle-points/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"saddle-points","id":"18964e9c5971482790e97a569346a40d","url":"https://exercism.io/my/solutions/18964e9c5971482790e97a569346a40d","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/saddle-points/.gitignore b/rust/saddle-points/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/saddle-points/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/saddle-points/Cargo.toml b/rust/saddle-points/Cargo.toml new file mode 100644 index 0000000..5f262e2 --- /dev/null +++ b/rust/saddle-points/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2018" +name = "saddle-points" +version = "1.3.0" + +[dependencies] diff --git a/rust/saddle-points/README.md b/rust/saddle-points/README.md new file mode 100644 index 0000000..84647d0 --- /dev/null +++ b/rust/saddle-points/README.md @@ -0,0 +1,132 @@ +# Saddle Points + +Detect saddle points in a matrix. + +So say you have a matrix like so: + +```text + 1 2 3 + |--------- +1 | 9 8 7 +2 | 5 3 2 <--- saddle point at column 1, row 2, with value 5 +3 | 6 6 7 +``` + +It has a saddle point at column 1, row 2. + +It's called a "saddle point" because it is greater than or equal to +every element in its row and less than or equal to every element in +its column. + +A matrix may have zero or more saddle points. + +Your code should be able to provide the (possibly empty) list of all the +saddle points for any given matrix. + +The matrix can have a different number of rows and columns (Non square). + +Note that you may find other definitions of matrix saddle points online, +but the tests for this exercise follow the above unambiguous definition. + +## Rust Indices Start At 0 + +By convention, ordered sequences of values in Rust have their contents numbered +("indexed") starting from 0. This applies regardless of what the rest of the +exercise description in this README says, such as references to indices that +start at 1, so you will have to subtract 1 to translate those index numbers +to Rust index numbers. + +## Efficiency Notice + +This exercise uses a _vector of vectors_ to store the content of matrices. While +this exercise is designed to help students understand basic concepts about +vectors, such as indexing, and that nested data types are legal, _vector of +vectors_ is a suboptimal choice for high-performance matrix algebra and any +similar efficient processing of larger amounts of data. + +The detailed explanation of this inefficiency is beyond the scope of this +exercise and this learning track in general. This aspect is known as +[cache locality](https://stackoverflow.com/questions/12065774/why-does-cache-locality-matter-for-array-performance) +and you can find a good introduction to it by clicking that link if you'd like +to learn more about details of a modern computer architecture. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +J Dalbey's Programming Practice problems [http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/saddle-points/src/lib.rs b/rust/saddle-points/src/lib.rs new file mode 100644 index 0000000..7123243 --- /dev/null +++ b/rust/saddle-points/src/lib.rs @@ -0,0 +1,16 @@ +fn is_min(mat: &[Vec], col: usize, row: usize) -> bool { + (0..mat.len()).all(|r| mat[r][col] >= mat[row][col]) +} + +pub fn find_saddle_points(input: &[Vec]) -> Vec<(usize, usize)> { + let mut res = vec![]; + for (row,relem) in input.iter().enumerate() { + let m = relem.iter().max(); + for (col,celem) in relem.iter().enumerate() { + if (m == Some(celem)) && is_min(input,col,row) { + res.push((row,col)); + } + } + } + res +} diff --git a/rust/saddle-points/tests/saddle-points.rs b/rust/saddle-points/tests/saddle-points.rs new file mode 100644 index 0000000..1fbc2de --- /dev/null +++ b/rust/saddle-points/tests/saddle-points.rs @@ -0,0 +1,98 @@ +use saddle_points; + +use saddle_points::find_saddle_points; + +// We don't care about order +fn find_sorted_saddle_points(input: &[Vec]) -> Vec<(usize, usize)> { + let mut result = saddle_points::find_saddle_points(input); + result.sort(); + result +} + +#[test] +fn identify_single_saddle_point() { + let input = vec![vec![9, 8, 7], vec![5, 3, 2], vec![6, 6, 7]]; + assert_eq!(vec![(1, 0)], find_saddle_points(&input)); +} + +#[test] +fn identify_empty_matrix() { + let input = vec![vec![], vec![], vec![]]; + let expected: Vec<(usize, usize)> = Vec::new(); + assert_eq!(expected, find_saddle_points(&input)); +} + +#[test] +fn identify_lack_of_saddle_point() { + let input = vec![vec![1, 2, 3], vec![3, 1, 2], vec![2, 3, 1]]; + let expected: Vec<(usize, usize)> = Vec::new(); + assert_eq!(expected, find_saddle_points(&input)); +} + +#[test] +fn multiple_saddle_points_in_col() { + let input = vec![vec![4, 5, 4], vec![3, 5, 5], vec![1, 5, 4]]; + assert_eq!( + vec![(0, 1), (1, 1), (2, 1)], + find_sorted_saddle_points(&input) + ); +} + +#[test] +fn multiple_saddle_points_in_row() { + let input = vec![vec![6, 7, 8], vec![5, 5, 5], vec![7, 5, 6]]; + assert_eq!( + vec![(1, 0), (1, 1), (1, 2)], + find_sorted_saddle_points(&input) + ); +} + +#[test] +fn identify_bottom_right_saddle_point() { + let input = vec![vec![8, 7, 9], vec![6, 7, 6], vec![3, 2, 5]]; + assert_eq!(vec![(2, 2)], find_saddle_points(&input)); +} + +// track specific as of v1.3 +#[test] +fn non_square_matrix_high() { + let input = vec![vec![1, 5], vec![3, 6], vec![2, 7], vec![3, 8]]; + assert_eq!(vec![(0, 1)], find_saddle_points(&input)); +} + +#[test] +fn non_square_matrix_wide() { + let input = vec![vec![3, 1, 3], vec![3, 2, 4]]; + assert_eq!(vec![(0, 0), (0, 2)], find_sorted_saddle_points(&input)); +} + +#[test] +fn single_column_matrix() { + let input = vec![vec![2], vec![1], vec![4], vec![1]]; + assert_eq!(vec![(1, 0), (3, 0)], find_sorted_saddle_points(&input)); +} + +#[test] +fn single_row_matrix() { + let input = vec![vec![2, 5, 3, 5]]; + assert_eq!(vec![(0, 1), (0, 3)], find_sorted_saddle_points(&input)); +} + +#[test] +fn identify_all_saddle_points() { + let input = vec![vec![5, 5, 5], vec![5, 5, 5], vec![5, 5, 5]]; + assert_eq!( + vec![ + (0, 0), + (0, 1), + (0, 2), + (1, 0), + (1, 1), + (1, 2), + (2, 0), + (2, 1), + (2, 2) + ], + find_sorted_saddle_points(&input) + ); +} diff --git a/rust/simple-linked-list/.exercism/metadata.json b/rust/simple-linked-list/.exercism/metadata.json new file mode 100644 index 0000000..4c7e1a6 --- /dev/null +++ b/rust/simple-linked-list/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"simple-linked-list","id":"a0e2dbad46184d6a8ee961fff5e6c497","url":"https://exercism.io/my/solutions/a0e2dbad46184d6a8ee961fff5e6c497","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/simple-linked-list/.gitignore b/rust/simple-linked-list/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/simple-linked-list/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/simple-linked-list/Cargo.toml b/rust/simple-linked-list/Cargo.toml new file mode 100644 index 0000000..25a62e7 --- /dev/null +++ b/rust/simple-linked-list/Cargo.toml @@ -0,0 +1,6 @@ +[package] +edition = "2018" +name = "simple_linked_list" +version = "0.1.0" + +[dependencies] diff --git a/rust/simple-linked-list/README.md b/rust/simple-linked-list/README.md new file mode 100644 index 0000000..47178e8 --- /dev/null +++ b/rust/simple-linked-list/README.md @@ -0,0 +1,137 @@ +# Simple Linked List + +Write a simple linked list implementation that uses Elements and a List. + +The linked list is a fundamental data structure in computer science, +often used in the implementation of other data structures. They're +pervasive in functional programming languages, such as Clojure, Erlang, +or Haskell, but far less common in imperative languages such as Ruby or +Python. + +The simplest kind of linked list is a singly linked list. Each element in the +list contains data and a "next" field pointing to the next element in the list +of elements. + +This variant of linked lists is often used to represent sequences or +push-down stacks (also called a LIFO stack; Last In, First Out). + +As a first take, lets create a singly linked list to contain the range (1..10), +and provide functions to reverse a linked list and convert to and from arrays. + +When implementing this in a language with built-in linked lists, +implement your own abstract data type. + +## Implementation Hints + +Do not implement the struct `SimpleLinkedList` as a wrapper around a `Vec`. Instead, allocate nodes on the heap. +This might be implemented as: +``` +pub struct SimpleLinkedList { + head: Option>>, +} +``` +The `head` field points to the first element (Node) of this linked list. +This implementation also requires a struct `Node` with the following fields: +``` +struct Node { + data: T, + next: Option>>, +} +``` +`data` contains the stored data, and `next` points to the following node (if available) or None. + +### Why `Option>>` and not just `Option>`? +Try it on your own. You will get the following error. + +``` +| struct Node +| ^^^^^^^^^^^^^^ recursive type has infinite size +... +| next: Option>, +| --------------------- recursive without indirection + ``` + + The problem is that at compile time the size of next must be known. + Since `next` is recursive ("a node has a node has a node..."), the compiler does not know how much memory is to be allocated. + In contrast, [Box](https://doc.rust-lang.org/std/boxed/) is a heap pointer with a defined size. + + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +Inspired by 'Data Structures and Algorithms with Object-Oriented Design Patterns in Ruby', singly linked-lists. [https://web.archive.org/web/20160731005714/http://brpreiss.com/books/opus8/html/page96.html](https://web.archive.org/web/20160731005714/http://brpreiss.com/books/opus8/html/page96.html) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/simple-linked-list/src/lib.rs b/rust/simple-linked-list/src/lib.rs new file mode 100644 index 0000000..75e82f5 --- /dev/null +++ b/rust/simple-linked-list/src/lib.rs @@ -0,0 +1,109 @@ +use std::iter::FromIterator; + +#[derive(Debug)] +struct Node { + data: T, + next: Option>>, +} + +impl Node { + pub fn new(data: T, next: Option>>) -> Self { + Node { data, next } + } + + pub fn len(&self) -> usize { + 1 + self.next.as_ref().map(|n| n.len()).unwrap_or(0) + } +} + +#[derive(Debug)] +pub struct SimpleLinkedList { + head: Option>>, +} + +impl SimpleLinkedList { + pub fn new() -> Self { + SimpleLinkedList { head: None } + } + + // You may be wondering why it's necessary to have is_empty() + // when it can easily be determined from len(). + // It's good custom to have both because len() can be expensive for some types, + // whereas is_empty() is almost always cheap. + // (Also ask yourself whether len() is expensive for SimpleLinkedList) + pub fn is_empty(&self) -> bool { + self.head.is_none() + } + + pub fn len(&self) -> usize { + self.head.as_ref().map(|n| n.len()).unwrap_or(0) + } + + pub fn push(&mut self, _element: T) { + // let node = Box::new(Node::new(_element, self.head.take())); + // self.head.replace(node); + self.head = Some(Box::new(Node::new(_element, self.head.take()))); + } + + pub fn pop(&mut self) -> Option { + self.head.take().map(|n| { + // n.next.map(|n1| self.head.replace(n1)); + self.head = n.next; + n.data + }) + } + + pub fn peek(&self) -> Option<&T> { + self.head.as_ref().map(|n| &n.data) + } + + pub fn rev(self) -> SimpleLinkedList { + self.rev_aux(SimpleLinkedList::new()) + } + + pub fn rev_aux(mut self, mut acc: SimpleLinkedList) -> SimpleLinkedList { + if let Some(e) = self.pop() { + acc.push(e); + self.rev_aux(acc) + } else { + acc + } + } + + fn into_aux(mut self, mut acc: Vec) -> Vec { + if let Some(e) = self.pop() { + acc.push(e); + self.into_aux(acc) + } else { + acc + } + } +} + +impl FromIterator for SimpleLinkedList { + fn from_iter>(_iter: I) -> Self { + _iter + .into_iter() + .fold(SimpleLinkedList::new(), |mut acc, n| { + acc.push(n); + acc + }) + } +} + +// In general, it would be preferable to implement IntoIterator for SimpleLinkedList +// instead of implementing an explicit conversion to a vector. This is because, together, +// FromIterator and IntoIterator enable conversion between arbitrary collections. +// Given that implementation, converting to a vector is trivial: +// +// let vec: Vec<_> = simple_linked_list.into_iter().collect(); +// +// The reason this exercise's API includes an explicit conversion to Vec instead +// of IntoIterator is that implementing that interface is fairly complicated, and +// demands more of the student than we expect at this point in the track. + +impl Into> for SimpleLinkedList { + fn into(self) -> Vec { + self.rev().into_aux(Vec::new()) + } +} diff --git a/rust/simple-linked-list/tests/simple-linked-list.rs b/rust/simple-linked-list/tests/simple-linked-list.rs new file mode 100644 index 0000000..c89f8b5 --- /dev/null +++ b/rust/simple-linked-list/tests/simple-linked-list.rs @@ -0,0 +1,118 @@ +use simple_linked_list::SimpleLinkedList; + +#[test] +fn test_new_list_is_empty() { + let list: SimpleLinkedList = SimpleLinkedList::new(); + assert_eq!(list.len(), 0, "list's length must be 0"); +} + +#[test] +fn test_push_increments_length() { + let mut list: SimpleLinkedList = SimpleLinkedList::new(); + list.push(1); + assert_eq!(list.len(), 1, "list's length must be 1"); + list.push(2); + assert_eq!(list.len(), 2, "list's length must be 2"); +} + +#[test] +fn test_pop_decrements_length() { + let mut list: SimpleLinkedList = SimpleLinkedList::new(); + list.push(1); + list.push(2); + list.pop(); + assert_eq!(list.len(), 1, "list's length must be 1"); + list.pop(); + assert_eq!(list.len(), 0, "list's length must be 0"); +} + +#[test] +fn test_is_empty() { + let mut list: SimpleLinkedList = SimpleLinkedList::new(); + assert!(list.is_empty(), "List wasn't empty on creation"); + for inserts in 0..100 { + for i in 0..inserts { + list.push(i); + assert!( + !list.is_empty(), + "List was empty after having inserted {}/{} elements", + i, + inserts + ); + } + for i in 0..inserts { + assert!( + !list.is_empty(), + "List was empty before removing {}/{} elements", + i, + inserts + ); + list.pop(); + } + assert!( + list.is_empty(), + "List wasn't empty after having removed {} elements", + inserts + ); + } +} + +#[test] +fn test_pop_returns_head_element_and_removes_it() { + let mut list: SimpleLinkedList = SimpleLinkedList::new(); + list.push(1); + list.push(2); + assert_eq!(list.pop(), Some(2), "Element must be 2"); + assert_eq!(list.pop(), Some(1), "Element must be 1"); + assert_eq!(list.pop(), None, "No element should be contained in list"); +} + +#[test] +fn test_peek_returns_reference_to_head_element_but_does_not_remove_it() { + let mut list: SimpleLinkedList = SimpleLinkedList::new(); + assert_eq!(list.peek(), None, "No element should be contained in list"); + list.push(2); + assert_eq!(list.peek(), Some(&2), "Element must be 2"); + assert_eq!(list.peek(), Some(&2), "Element must be still 2"); + list.push(3); + assert_eq!(list.peek(), Some(&3), "Head element is now 3"); + assert_eq!(list.pop(), Some(3), "Element must be 3"); + assert_eq!(list.peek(), Some(&2), "Head element is now 2"); + assert_eq!(list.pop(), Some(2), "Element must be 2"); + assert_eq!(list.peek(), None, "No element should be contained in list"); +} + +#[test] +fn test_from_slice() { + let mut array = vec!["1", "2", "3", "4"]; + let mut list: SimpleLinkedList<_> = array.drain(..).collect(); + assert_eq!(list.pop(), Some("4")); + assert_eq!(list.pop(), Some("3")); + assert_eq!(list.pop(), Some("2")); + assert_eq!(list.pop(), Some("1")); +} + +#[test] +fn test_reverse() { + let mut list: SimpleLinkedList = SimpleLinkedList::new(); + list.push(1); + list.push(2); + list.push(3); + let mut rev_list = list.rev(); + assert_eq!(rev_list.pop(), Some(1)); + assert_eq!(rev_list.pop(), Some(2)); + assert_eq!(rev_list.pop(), Some(3)); + assert_eq!(rev_list.pop(), None); +} + +#[test] +fn test_into_vector() { + let mut v = Vec::new(); + let mut s = SimpleLinkedList::new(); + for i in 1..4 { + v.push(i); + s.push(i); + } + let s_as_vec: Vec = s.into(); + assert_eq!(v, s_as_vec); +} diff --git a/rust/sum-of-multiples/.exercism/metadata.json b/rust/sum-of-multiples/.exercism/metadata.json new file mode 100644 index 0000000..98ef3f1 --- /dev/null +++ b/rust/sum-of-multiples/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"sum-of-multiples","id":"9f1716859ebb4e38b10e5dfbd3858ad3","url":"https://exercism.io/my/solutions/9f1716859ebb4e38b10e5dfbd3858ad3","handle":"dyamon","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/sum-of-multiples/.gitignore b/rust/sum-of-multiples/.gitignore new file mode 100644 index 0000000..db7f315 --- /dev/null +++ b/rust/sum-of-multiples/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/sum-of-multiples/Cargo.toml b/rust/sum-of-multiples/Cargo.toml new file mode 100644 index 0000000..a006459 --- /dev/null +++ b/rust/sum-of-multiples/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2018" +name = "sum-of-multiples" +version = "1.5.0" diff --git a/rust/sum-of-multiples/README.md b/rust/sum-of-multiples/README.md new file mode 100644 index 0000000..72bb481 --- /dev/null +++ b/rust/sum-of-multiples/README.md @@ -0,0 +1,89 @@ +# Sum Of Multiples + +Given a number, find the sum of all the unique multiples of particular numbers up to +but not including that number. + +If we list all the natural numbers below 20 that are multiples of 3 or 5, +we get 3, 5, 6, 9, 10, 12, 15, and 18. + +The sum of these multiples is 78. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run all ignored tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the [online test documentation][rust-tests] + +Make sure to read the [Modules][modules] chapter if you +haven't already, it will help you with organizing your files. + +## Further improvements + +After you have solved the exercise, please consider using the additional utilities, described in the [installation guide](https://exercism.io/tracks/rust/installation), to further refine your final solution. + +To format your solution, inside the solution directory use + +```bash +cargo fmt +``` + +To see, if your solution contains some common ineffective use cases, inside the solution directory use + +```bash +cargo clippy --all-targets +``` + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md). + +[help-page]: https://exercism.io/tracks/rust/learning +[modules]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html +[cargo]: https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Source + +A variation on Problem 1 at Project Euler [http://projecteuler.net/problem=1](http://projecteuler.net/problem=1) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/rust/sum-of-multiples/src/lib.rs b/rust/sum-of-multiples/src/lib.rs new file mode 100644 index 0000000..148419d --- /dev/null +++ b/rust/sum-of-multiples/src/lib.rs @@ -0,0 +1,3 @@ +pub fn sum_of_multiples(limit: u32, factors: &[u32]) -> u32 { + (1..limit).filter(|x| factors.iter().filter(|&&x| x != 0).any(|y| x % y == 0)).sum() +} diff --git a/rust/sum-of-multiples/tests/sum-of-multiples.rs b/rust/sum-of-multiples/tests/sum-of-multiples.rs new file mode 100644 index 0000000..369289c --- /dev/null +++ b/rust/sum-of-multiples/tests/sum-of-multiples.rs @@ -0,0 +1,81 @@ +use sum_of_multiples::*; + +#[test] +fn no_multiples_within_limit() { + assert_eq!(0, sum_of_multiples(1, &[3, 5])) +} + +#[test] +fn one_factor_has_multiples_within_limit() { + assert_eq!(3, sum_of_multiples(4, &[3, 5])) +} + +#[test] +fn more_than_one_multiple_within_limit() { + assert_eq!(9, sum_of_multiples(7, &[3])) +} + +#[test] +fn more_than_one_factor_with_multiples_within_limit() { + assert_eq!(23, sum_of_multiples(10, &[3, 5])) +} + +#[test] +fn each_multiple_is_only_counted_once() { + assert_eq!(2318, sum_of_multiples(100, &[3, 5])) +} + +#[test] +fn a_much_larger_limit() { + assert_eq!(233_168, sum_of_multiples(1000, &[3, 5])) +} + +#[test] +fn three_factors() { + assert_eq!(51, sum_of_multiples(20, &[7, 13, 17])) +} + +#[test] +fn factors_not_relatively_prime() { + assert_eq!(30, sum_of_multiples(15, &[4, 6])) +} + +#[test] +fn some_pairs_of_factors_relatively_prime_and_some_not() { + assert_eq!(4419, sum_of_multiples(150, &[5, 6, 8])) +} + +#[test] +fn one_factor_is_a_multiple_of_another() { + assert_eq!(275, sum_of_multiples(51, &[5, 25])) +} + +#[test] +fn much_larger_factors() { + assert_eq!(2_203_160, sum_of_multiples(10_000, &[43, 47])) +} + +#[test] +fn all_numbers_are_multiples_of_1() { + assert_eq!(4950, sum_of_multiples(100, &[1])) +} + +#[test] +fn no_factors_means_an_empty_sum() { + assert_eq!(0, sum_of_multiples(10_000, &[])) +} + +#[test] +fn the_only_multiple_of_0_is_0() { + assert_eq!(0, sum_of_multiples(1, &[0])) +} + +#[test] +fn the_factor_0_does_not_affect_the_sum_of_multiples_of_other_factors() { + assert_eq!(3, sum_of_multiples(4, &[3, 0])) +} + +#[test] +fn solutions_using_include_exclude_must_extend_to_cardinality_greater_than_3() { + assert_eq!(39_614_537, sum_of_multiples(10_000, &[2, 3, 5, 7, 11])) +} -- cgit v1.2.3