diff --git a/rust/sum-of-multiples/.exercism/config.json b/rust/sum-of-multiples/.exercism/config.json new file mode 100644 index 0000000..c5c6c9a --- /dev/null +++ b/rust/sum-of-multiples/.exercism/config.json @@ -0,0 +1,39 @@ +{ + "authors": [ + "IanWhitney" + ], + "contributors": [ + "coriolinus", + "cwhakes", + "eddyp", + "efx", + "ErikSchierboom", + "GoneUp", + "hekrause", + "leoyvens", + "lutostag", + "mkantor", + "nfiles", + "petertseng", + "rofrol", + "sshine", + "stringparser", + "xakon", + "ZapAnton" + ], + "files": { + "solution": [ + "src/lib.rs", + "Cargo.toml" + ], + "test": [ + "tests/sum_of_multiples.rs" + ], + "example": [ + ".meta/example.rs" + ] + }, + "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", + "source": "A variation on Problem 1 at Project Euler", + "source_url": "https://projecteuler.net/problem=1" +} diff --git a/rust/sum-of-multiples/.gitignore b/rust/sum-of-multiples/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/rust/sum-of-multiples/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/rust/sum-of-multiples/Cargo.toml b/rust/sum-of-multiples/Cargo.toml new file mode 100644 index 0000000..be310bd --- /dev/null +++ b/rust/sum-of-multiples/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "sum_of_multiples" +version = "0.1.0" +edition = "2024" + +# Not all libraries from crates.io are available in Exercism's test runner. +# The full list of available libraries is here: +# https://github.com/exercism/rust-test-runner/blob/main/local-registry/Cargo.toml +[dependencies] diff --git a/rust/sum-of-multiples/HELP.md b/rust/sum-of-multiples/HELP.md new file mode 100644 index 0000000..22a6c00 --- /dev/null +++ b/rust/sum-of-multiples/HELP.md @@ -0,0 +1,89 @@ +# Help + +## Running the tests + +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 _only ignored_ tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +If you are using Rust 1.51 or later, you can run _all_ tests with + +```bash +$ cargo test -- --include-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]. + +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Submitting your solution + +You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Rust track's documentation](https://exercism.org/docs/tracks/rust) +- The [Rust track's programming category on the forum](https://forum.exercism.org/c/programming/rust) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## 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 + +Head to [the forum](https://forum.exercism.org/c/programming/rust/) and create a post to provide feedback about an exercise or if you want to help implement new exercises. +Members of the rust track team are happy to help! + +The GitHub [track repository][github] is the home for all of the Rust exercises. + +If you want to know more about Exercism, take a look at the [contribution guide]. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + +[help-page]: https://exercism.org/tracks/rust/learning +[github]: https://github.com/exercism/rust +[contribution guide]: https://exercism.org/docs/community/contributors \ No newline at end of file diff --git a/rust/sum-of-multiples/README.md b/rust/sum-of-multiples/README.md new file mode 100644 index 0000000..5e2651c --- /dev/null +++ b/rust/sum-of-multiples/README.md @@ -0,0 +1,69 @@ +# Sum of Multiples + +Welcome to Sum of Multiples on Exercism's Rust Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You work for a company that makes an online, fantasy-survival game. + +When a player finishes a level, they are awarded energy points. +The amount of energy awarded depends on which magical items the player found while exploring that level. + +## Instructions + +Your task is to write the code that calculates the energy points that get awarded to players when they complete a level. + +The points awarded depend on two things: + +- The level (a number) that the player completed. +- The base value of each magical item collected by the player during that level. + +The energy points are awarded according to the following rules: + +1. For each magical item, take the base value and find all the multiples of that value that are less than the level number. +2. Combine the sets of numbers. +3. Remove any duplicates. +4. Calculate the sum of all the numbers that are left. + +Let's look at an example: + +**The player completed level 20 and found two magical items with base values of 3 and 5.** + +To calculate the energy points earned by the player, we need to find all the unique multiples of these base values that are less than level 20. + +- Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}` +- Multiples of 5 less than 20: `{5, 10, 15}` +- Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}` +- Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78` +- Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5. + +## Source + +### Created by + +- @IanWhitney + +### Contributed to by + +- @coriolinus +- @cwhakes +- @eddyp +- @efx +- @ErikSchierboom +- @GoneUp +- @hekrause +- @leoyvens +- @lutostag +- @mkantor +- @nfiles +- @petertseng +- @rofrol +- @sshine +- @stringparser +- @xakon +- @ZapAnton + +### Based on + +A variation on Problem 1 at Project Euler - https://projecteuler.net/problem=1 \ No newline at end of file diff --git a/rust/sum-of-multiples/src/lib.rs b/rust/sum-of-multiples/src/lib.rs new file mode 100644 index 0000000..61fdcb7 --- /dev/null +++ b/rust/sum-of-multiples/src/lib.rs @@ -0,0 +1,12 @@ +use std::collections::HashSet; + +pub fn sum_of_multiples(limit: u32, factors: &[u32]) -> u32 { + factors + .iter() + .copied() + .filter(|&x| 0 < x) + .flat_map(|num| (num..limit).step_by(num as usize)) + .collect::>() + .iter() + .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..8f6ef45 --- /dev/null +++ b/rust/sum-of-multiples/tests/sum_of_multiples.rs @@ -0,0 +1,145 @@ +use sum_of_multiples::*; + +#[test] +fn no_multiples_within_limit() { + let factors = &[3, 5]; + let limit = 1; + let output = sum_of_multiples(limit, factors); + let expected = 0; + assert_eq!(output, expected); +} + +#[test] +fn one_factor_has_multiples_within_limit() { + let factors = &[3, 5]; + let limit = 4; + let output = sum_of_multiples(limit, factors); + let expected = 3; + assert_eq!(output, expected); +} + +#[test] +fn more_than_one_multiple_within_limit() { + let factors = &[3]; + let limit = 7; + let output = sum_of_multiples(limit, factors); + let expected = 9; + assert_eq!(output, expected); +} + +#[test] +fn more_than_one_factor_with_multiples_within_limit() { + let factors = &[3, 5]; + let limit = 10; + let output = sum_of_multiples(limit, factors); + let expected = 23; + assert_eq!(output, expected); +} + +#[test] +fn each_multiple_is_only_counted_once() { + let factors = &[3, 5]; + let limit = 100; + let output = sum_of_multiples(limit, factors); + let expected = 2_318; + assert_eq!(output, expected); +} + +#[test] +fn a_much_larger_limit() { + let factors = &[3, 5]; + let limit = 1_000; + let output = sum_of_multiples(limit, factors); + let expected = 233_168; + assert_eq!(output, expected); +} + +#[test] +fn three_factors() { + let factors = &[7, 13, 17]; + let limit = 20; + let output = sum_of_multiples(limit, factors); + let expected = 51; + assert_eq!(output, expected); +} + +#[test] +fn factors_not_relatively_prime() { + let factors = &[4, 6]; + let limit = 15; + let output = sum_of_multiples(limit, factors); + let expected = 30; + assert_eq!(output, expected); +} + +#[test] +fn some_pairs_of_factors_relatively_prime_and_some_not() { + let factors = &[5, 6, 8]; + let limit = 150; + let output = sum_of_multiples(limit, factors); + let expected = 4_419; + assert_eq!(output, expected); +} + +#[test] +fn one_factor_is_a_multiple_of_another() { + let factors = &[5, 25]; + let limit = 51; + let output = sum_of_multiples(limit, factors); + let expected = 275; + assert_eq!(output, expected); +} + +#[test] +fn much_larger_factors() { + let factors = &[43, 47]; + let limit = 10_000; + let output = sum_of_multiples(limit, factors); + let expected = 2_203_160; + assert_eq!(output, expected); +} + +#[test] +fn all_numbers_are_multiples_of_1() { + let factors = &[1]; + let limit = 100; + let output = sum_of_multiples(limit, factors); + let expected = 4_950; + assert_eq!(output, expected); +} + +#[test] +fn no_factors_means_an_empty_sum() { + let factors = &[]; + let limit = 10_000; + let output = sum_of_multiples(limit, factors); + let expected = 0; + assert_eq!(output, expected); +} + +#[test] +fn the_only_multiple_of_0_is_0() { + let factors = &[0]; + let limit = 1; + let output = sum_of_multiples(limit, factors); + let expected = 0; + assert_eq!(output, expected); +} + +#[test] +fn the_factor_0_does_not_affect_the_sum_of_multiples_of_other_factors() { + let factors = &[3, 0]; + let limit = 4; + let output = sum_of_multiples(limit, factors); + let expected = 3; + assert_eq!(output, expected); +} + +#[test] +fn solutions_using_include_exclude_must_extend_to_cardinality_greater_than_3() { + let factors = &[2, 3, 5, 7, 11]; + let limit = 10_000; + let output = sum_of_multiples(limit, factors); + let expected = 39_614_537; + assert_eq!(output, expected); +}