trackler 2.2.1.62 → 2.2.1.63
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/all-your-base/canonical-data.json +20 -29
- data/problem-specifications/exercises/forth/canonical-data.json +52 -5
- data/problem-specifications/exercises/isbn-verifier/canonical-data.json +15 -15
- data/problem-specifications/exercises/protein-translation/canonical-data.json +153 -0
- data/problem-specifications/exercises/reverse-string/canonical-data.json +39 -0
- data/problem-specifications/exercises/reverse-string/description.md +5 -0
- data/problem-specifications/exercises/reverse-string/metadata.yml +5 -0
- data/tracks/c/config.json +42 -41
- data/tracks/csharp/config.json +13 -0
- data/tracks/csharp/exercises/Exercises.sln +6 -0
- data/tracks/csharp/exercises/isbn-verifier/Example.cs +27 -0
- data/tracks/csharp/exercises/isbn-verifier/IsbnVerifier.cs +9 -0
- data/tracks/csharp/exercises/isbn-verifier/IsbnVerifier.csproj +19 -0
- data/tracks/csharp/exercises/isbn-verifier/IsbnVerifierTest.cs +84 -0
- data/tracks/csharp/exercises/isbn-verifier/README.md +40 -0
- data/tracks/csharp/generators/Exercises/IsbnVerifier.cs +15 -0
- data/tracks/delphi/config.json +28 -28
- data/tracks/erlang/config.json +10 -0
- data/tracks/erlang/exercises/accumulate/rebar.config +1 -1
- data/tracks/erlang/exercises/accumulate/test/accumulate_tests.erl +9 -7
- data/tracks/erlang/exercises/all-your-base/rebar.config +1 -1
- data/tracks/erlang/exercises/all-your-base/test/all_your_base_tests.erl +26 -24
- data/tracks/erlang/exercises/allergies/rebar.config +1 -1
- data/tracks/erlang/exercises/allergies/test/allergies_tests.erl +19 -17
- data/tracks/erlang/exercises/anagram/rebar.config +1 -3
- data/tracks/erlang/exercises/anagram/test/anagram_tests.erl +14 -12
- data/tracks/erlang/exercises/atbash-cipher/rebar.config +1 -1
- data/tracks/erlang/exercises/atbash-cipher/test/atbash_cipher_tests.erl +7 -5
- data/tracks/erlang/exercises/bank-account/rebar.config +1 -1
- data/tracks/erlang/exercises/bank-account/test/bank_account_tests.erl +52 -51
- data/tracks/erlang/exercises/beer-song/rebar.config +30 -0
- data/tracks/erlang/exercises/beer-song/test/beer_song_tests.erl +11 -10
- data/tracks/erlang/exercises/bob/rebar.config +1 -1
- data/tracks/erlang/exercises/bob/test/bob_tests.erl +33 -35
- data/tracks/erlang/exercises/circular-buffer/rebar.config +1 -1
- data/tracks/erlang/exercises/circular-buffer/test/circular_buffer_tests.erl +33 -32
- data/tracks/erlang/exercises/clock/rebar.config +1 -1
- data/tracks/erlang/exercises/clock/test/clock_tests.erl +57 -50
- data/tracks/erlang/exercises/collatz-conjecture/rebar.config +1 -1
- data/tracks/erlang/exercises/collatz-conjecture/test/collatz_conjecture_tests.erl +11 -9
- data/tracks/erlang/exercises/complex-numbers/rebar.config +1 -1
- data/tracks/erlang/exercises/complex-numbers/test/complex_numbers_tests.erl +102 -76
- data/tracks/erlang/exercises/custom-set/rebar.config +1 -1
- data/tracks/erlang/exercises/custom-set/test/custom_set_tests.erl +100 -109
- data/tracks/erlang/exercises/difference-of-squares/rebar.config +1 -1
- data/tracks/erlang/exercises/difference-of-squares/test/difference_of_squares_tests.erl +8 -7
- data/tracks/erlang/exercises/etl/rebar.config +1 -1
- data/tracks/erlang/exercises/etl/test/etl_tests.erl +6 -5
- data/tracks/erlang/exercises/gigasecond/rebar.config +1 -1
- data/tracks/erlang/exercises/gigasecond/test/gigasecond_tests.erl +9 -8
- data/tracks/erlang/exercises/grade-school/rebar.config +1 -1
- data/tracks/erlang/exercises/grade-school/test/grade_school_tests.erl +27 -23
- data/tracks/erlang/exercises/grains/rebar.config +1 -1
- data/tracks/erlang/exercises/grains/test/grains_tests.erl +7 -6
- data/tracks/erlang/exercises/hamming/rebar.config +1 -1
- data/tracks/erlang/exercises/hamming/test/hamming_tests.erl +20 -23
- data/tracks/erlang/exercises/hello-world/rebar.config +1 -1
- data/tracks/erlang/exercises/hello-world/test/hello_world_tests.erl +6 -4
- data/tracks/erlang/exercises/isogram/rebar.config +1 -1
- data/tracks/erlang/exercises/isogram/test/isogram_tests.erl +14 -12
- data/tracks/erlang/exercises/largest-series-product/rebar.config +1 -1
- data/tracks/erlang/exercises/largest-series-product/test/largest_series_product_tests.erl +22 -21
- data/tracks/erlang/exercises/leap/rebar.config +1 -1
- data/tracks/erlang/exercises/leap/test/leap_tests.erl +8 -7
- data/tracks/erlang/exercises/luhn/rebar.config +1 -1
- data/tracks/erlang/exercises/luhn/test/luhn_tests.erl +18 -16
- data/tracks/erlang/exercises/meetup/rebar.config +1 -1
- data/tracks/erlang/exercises/meetup/test/meetup_tests.erl +96 -95
- data/tracks/erlang/exercises/nucleotide-count/rebar.config +1 -1
- data/tracks/erlang/exercises/nucleotide-count/test/nucleotide_count_tests.erl +12 -11
- data/tracks/erlang/exercises/pangram/README.md +60 -0
- data/tracks/erlang/exercises/{accumulate → pangram}/include/exercism.hrl +0 -0
- data/tracks/erlang/exercises/{beer-song/rebar.conf → pangram/rebar.config} +0 -0
- data/tracks/erlang/exercises/pangram/src/example.erl +11 -0
- data/tracks/erlang/exercises/pangram/src/pangram.app.src +9 -0
- data/tracks/erlang/exercises/pangram/src/pangram.erl +8 -0
- data/tracks/erlang/exercises/pangram/test/pangram_tests.erl +38 -0
- data/tracks/erlang/exercises/parallel-letter-frequency/rebar.config +1 -1
- data/tracks/erlang/exercises/parallel-letter-frequency/test/parallel_letter_frequency_tests.erl +7 -6
- data/tracks/erlang/exercises/phone-number/rebar.config +1 -1
- data/tracks/erlang/exercises/phone-number/test/phone_number_tests.erl +13 -12
- data/tracks/erlang/exercises/rna-transcription/rebar.config +1 -1
- data/tracks/erlang/exercises/rna-transcription/test/rna_transcription_tests.erl +13 -11
- data/tracks/erlang/exercises/robot-simulator/rebar.config +1 -1
- data/tracks/erlang/exercises/robot-simulator/test/robot_simulator_tests.erl +70 -69
- data/tracks/erlang/exercises/roman-numerals/rebar.config +1 -1
- data/tracks/erlang/exercises/roman-numerals/test/roman_numerals_tests.erl +6 -5
- data/tracks/erlang/exercises/rotational-cipher/rebar.config +1 -8
- data/tracks/erlang/exercises/rotational-cipher/test/rotational_cipher_tests.erl +29 -27
- data/tracks/erlang/exercises/scrabble-score/rebar.config +1 -1
- data/tracks/erlang/exercises/scrabble-score/test/scrabble_score_tests.erl +6 -5
- data/tracks/erlang/exercises/series/rebar.config +1 -1
- data/tracks/erlang/exercises/series/test/series_tests.erl +6 -5
- data/tracks/erlang/exercises/sieve/rebar.config +1 -1
- data/tracks/erlang/exercises/sieve/test/sieve_tests.erl +10 -8
- data/tracks/erlang/exercises/space-age/rebar.config +1 -1
- data/tracks/erlang/exercises/space-age/test/space_age_tests.erl +20 -19
- data/tracks/erlang/exercises/spiral-matrix/rebar.config +1 -1
- data/tracks/erlang/exercises/spiral-matrix/test/spiral_matrix_tests.erl +12 -10
- data/tracks/erlang/exercises/strain/rebar.config +1 -1
- data/tracks/erlang/exercises/strain/test/strain_tests.erl +17 -16
- data/tracks/erlang/exercises/sum-of-multiples/rebar.config +1 -1
- data/tracks/erlang/exercises/sum-of-multiples/test/sum_of_multiples_tests.erl +16 -15
- data/tracks/erlang/exercises/triangle/rebar.config +1 -1
- data/tracks/erlang/exercises/triangle/test/triangle_tests.erl +20 -19
- data/tracks/erlang/exercises/two-fer/rebar.config +1 -1
- data/tracks/erlang/exercises/two-fer/test/two_fer_tests.erl +8 -7
- data/tracks/erlang/exercises/word-count/rebar.config +1 -1
- data/tracks/erlang/exercises/word-count/test/word_count_tests.erl +6 -5
- data/tracks/erlang/exercises/zipper/rebar.config +1 -1
- data/tracks/erlang/exercises/zipper/test/zipper_tests.erl +47 -46
- data/tracks/erlang/testgen/src/tgen.erl +8 -6
- data/tracks/erlang/testgen/src/tgen_bob.erl +1 -1
- data/tracks/erlang/testgen/src/tgen_collatz-conjecture.erl +2 -2
- data/tracks/erlang/testgen/src/tgen_complex-numbers.erl +11 -11
- data/tracks/erlang/testgen/src/tgen_custom-set.erl +14 -14
- data/tracks/erlang/testgen/src/tgen_hamming.erl +2 -2
- data/tracks/erlang/testgen/src/tgen_hello-world.erl +1 -1
- data/tracks/erlang/testgen/src/tgen_leap.erl +1 -1
- data/tracks/erlang/testgen/src/tgen_rna-transcription.erl +2 -2
- data/tracks/erlang/testgen/src/tgs.erl +6 -0
- data/tracks/fsharp/exercises/beer-song/BeerSong.fs +1 -5
- data/tracks/fsharp/exercises/beer-song/BeerSongTest.fs +342 -20
- data/tracks/fsharp/exercises/beer-song/Example.fs +16 -10
- data/tracks/fsharp/exercises/food-chain/Example.fs +1 -1
- data/tracks/fsharp/exercises/food-chain/FoodChain.fs +1 -3
- data/tracks/fsharp/exercises/food-chain/FoodChainTest.fs +11 -11
- data/tracks/fsharp/exercises/house/Example.fs +1 -1
- data/tracks/fsharp/exercises/house/House.fs +1 -3
- data/tracks/fsharp/exercises/house/HouseTest.fs +202 -202
- data/tracks/fsharp/exercises/proverb/Example.fs +9 -9
- data/tracks/fsharp/exercises/proverb/Proverb.fs +1 -3
- data/tracks/fsharp/exercises/proverb/ProverbTest.fs +50 -21
- data/tracks/fsharp/exercises/twelve-days/Example.fs +4 -4
- data/tracks/fsharp/exercises/twelve-days/TwelveDays.fs +2 -6
- data/tracks/fsharp/exercises/twelve-days/TwelveDaysTest.fs +81 -57
- data/tracks/fsharp/generators/Generators.fs +39 -15
- data/tracks/go/bin/run-generators +5 -1
- data/tracks/go/config.json +14 -2
- data/tracks/go/exercises/accumulate/example.go +2 -1
- data/tracks/go/exercises/zebra-puzzle/.meta/hints.md +24 -0
- data/tracks/go/exercises/zebra-puzzle/README.md +76 -0
- data/tracks/go/exercises/zebra-puzzle/example.go +256 -0
- data/tracks/go/exercises/zebra-puzzle/zebra_puzzle_test.go +18 -0
- data/tracks/haskell/exercises/forth/package.yaml +1 -1
- data/tracks/haskell/exercises/forth/test/Tests.hs +1 -4
- data/tracks/haskell/exercises/pascals-triangle/package.yaml +1 -1
- data/tracks/haskell/exercises/pascals-triangle/test/Tests.hs +22 -1
- data/tracks/java/POLICIES.md +3 -3
- data/tracks/java/config.json +21 -2
- data/tracks/java/exercises/atbash-cipher/.meta/src/reference/java/Atbash.java +12 -12
- data/tracks/java/exercises/protein-translation/.meta/src/reference/java/ProteinTranslator.java +47 -0
- data/tracks/java/exercises/protein-translation/.meta/version +1 -0
- data/tracks/java/exercises/protein-translation/README.md +58 -0
- data/tracks/java/exercises/protein-translation/build.gradle +18 -0
- data/tracks/java/exercises/protein-translation/src/main/java/ProteinTranslator.java +8 -0
- data/tracks/java/exercises/protein-translation/src/test/java/ProteinTranslatorTest.java +179 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/javascript/.eslintignore +2 -2
- data/tracks/javascript/exercises/accumulate/example.js +1 -2
- data/tracks/javascript/exercises/grains/example.js +6 -3
- data/tracks/kotlin/exercises/beer-song/.meta/src/reference/kotlin/BeerSong.kt +3 -3
- data/tracks/kotlin/exercises/beer-song/.meta/version +1 -1
- data/tracks/kotlin/exercises/beer-song/README.md +1 -1
- data/tracks/kotlin/exercises/beer-song/src/test/kotlin/BeerSongTest.kt +6 -6
- data/tracks/kotlin/exercises/forth/.meta/version +1 -1
- data/tracks/kotlin/exercises/forth/src/test/kotlin/ForthEvaluatorTest.kt +0 -7
- data/tracks/kotlin/exercises/meetup/README.md +16 -12
- data/tracks/kotlin/exercises/nth-prime/.meta/src/reference/kotlin/Prime.kt +7 -2
- data/tracks/kotlin/exercises/nth-prime/.meta/version +1 -1
- data/tracks/kotlin/exercises/nth-prime/src/test/kotlin/PrimeTest.kt +10 -1
- data/tracks/kotlin/exercises/nucleotide-count/README.md +2 -2
- data/tracks/kotlin/exercises/pascals-triangle/.meta/src/reference/kotlin/PascalsTriangle.kt +1 -1
- data/tracks/kotlin/exercises/pascals-triangle/.meta/version +1 -1
- data/tracks/kotlin/exercises/pascals-triangle/src/test/kotlin/PascalsTriangleTest.kt +58 -1
- data/tracks/kotlin/exercises/sum-of-multiples/README.md +3 -3
- data/tracks/ocaml/exercises/forth/test.ml +1 -3
- data/tracks/ocaml/exercises/rectangles/example.ml +11 -11
- data/tracks/php/exercises/bob/example.php +2 -2
- data/tracks/purescript/config.json +3 -3
- data/tracks/python/config.json +34 -22
- data/tracks/python/exercises/alphametics/example.py +90 -34
- data/tracks/python/exercises/ocr-numbers/example.py +18 -21
- data/tracks/python/exercises/ocr-numbers/ocr_numbers.py +1 -5
- data/tracks/python/exercises/ocr-numbers/ocr_numbers_test.py +124 -106
- data/tracks/python/exercises/simple-linked-list/README.md +49 -0
- data/tracks/python/exercises/simple-linked-list/example.py +67 -0
- data/tracks/python/exercises/simple-linked-list/hints.md +10 -0
- data/tracks/python/exercises/simple-linked-list/simple_linked_list.py +33 -0
- data/tracks/python/exercises/simple-linked-list/simple_linked_list_test.py +112 -0
- data/tracks/rust/README.md +2 -0
- data/tracks/rust/bin/init_exercise.py +586 -0
- data/tracks/rust/config.json +20 -10
- data/tracks/rust/exercises/book-store/.gitignore +3 -0
- data/tracks/rust/exercises/book-store/Cargo-example.toml +7 -0
- data/tracks/rust/exercises/book-store/Cargo.toml +6 -0
- data/tracks/rust/exercises/book-store/README.md +107 -0
- data/tracks/rust/exercises/book-store/example.rs +187 -0
- data/tracks/rust/exercises/book-store/src/lib.rs +3 -0
- data/tracks/rust/exercises/book-store/tests/book-store.rs +130 -0
- data/tracks/sml/config.json +8 -8
- data/tracks/typescript/config.json +6 -6
- metadata +43 -46
- data/tracks/erlang/exercises/all-your-base/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/allergies/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/anagram/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/atbash-cipher/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/bank-account/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/beer-song/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/bob/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/circular-buffer/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/clock/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/collatz-conjecture/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/complex-numbers/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/custom-set/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/difference-of-squares/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/etl/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/gigasecond/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/grade-school/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/grains/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/hamming/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/hello-world/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/isogram/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/largest-series-product/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/leap/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/luhn/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/meetup/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/nucleotide-count/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/parallel-letter-frequency/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/phone-number/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/rna-transcription/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/robot-simulator/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/roman-numerals/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/rotational-cipher/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/scrabble-score/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/series/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/sieve/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/space-age/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/spiral-matrix/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/strain/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/sum-of-multiples/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/triangle/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/two-fer/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/word-count/include/exercism.hrl +0 -11
- data/tracks/erlang/exercises/zipper/include/exercism.hrl +0 -11
@@ -0,0 +1,107 @@
|
|
1
|
+
# Book Store
|
2
|
+
|
3
|
+
To try and encourage more sales of different books from a popular 5 book
|
4
|
+
series, a bookshop has decided to offer discounts on multiple book purchases.
|
5
|
+
|
6
|
+
One copy of any of the five books costs $8.
|
7
|
+
|
8
|
+
If, however, you buy two different books, you get a 5%
|
9
|
+
discount on those two books.
|
10
|
+
|
11
|
+
If you buy 3 different books, you get a 10% discount.
|
12
|
+
|
13
|
+
If you buy 4 different books, you get a 20% discount.
|
14
|
+
|
15
|
+
If you buy all 5, you get a 25% discount.
|
16
|
+
|
17
|
+
Note: that if you buy four books, of which 3 are
|
18
|
+
different titles, you get a 10% discount on the 3 that
|
19
|
+
form part of a set, but the fourth book still costs $8.
|
20
|
+
|
21
|
+
Your mission is to write a piece of code to calculate the
|
22
|
+
price of any conceivable shopping basket (containing only
|
23
|
+
books of the same series), giving as big a discount as
|
24
|
+
possible.
|
25
|
+
|
26
|
+
For example, how much does this basket of books cost?
|
27
|
+
|
28
|
+
- 2 copies of the first book
|
29
|
+
- 2 copies of the second book
|
30
|
+
- 2 copies of the third book
|
31
|
+
- 1 copy of the fourth book
|
32
|
+
- 1 copy of the fifth book
|
33
|
+
|
34
|
+
One way of grouping these 8 books is:
|
35
|
+
|
36
|
+
- 1 group of 5 --> 25% discount (1st,2nd,3rd,4th,5th)
|
37
|
+
- +1 group of 3 --> 10% discount (1st,2nd,3rd)
|
38
|
+
|
39
|
+
This would give a total of:
|
40
|
+
|
41
|
+
- 5 books at a 25% discount
|
42
|
+
- +3 books at a 10% discount
|
43
|
+
|
44
|
+
Resulting in:
|
45
|
+
|
46
|
+
- 5 x (8 - 2.00) == 5 x 6.00 == $30.00
|
47
|
+
- +3 x (8 - 0.80) == 3 x 7.20 == $21.60
|
48
|
+
|
49
|
+
For a total of $51.60
|
50
|
+
|
51
|
+
However, a different way to group these 8 books is:
|
52
|
+
|
53
|
+
- 1 group of 4 books --> 20% discount (1st,2nd,3rd,4th)
|
54
|
+
- +1 group of 4 books --> 20% discount (1st,2nd,3rd,5th)
|
55
|
+
|
56
|
+
This would give a total of:
|
57
|
+
|
58
|
+
- 4 books at a 20% discount
|
59
|
+
- +4 books at a 20% discount
|
60
|
+
|
61
|
+
Resulting in:
|
62
|
+
|
63
|
+
- 4 x (8 - 1.60) == 4 x 6.40 == $25.60
|
64
|
+
- +4 x (8 - 1.60) == 4 x 6.40 == $25.60
|
65
|
+
|
66
|
+
For a total of $51.20
|
67
|
+
|
68
|
+
And $51.20 is the price with the biggest discount.
|
69
|
+
|
70
|
+
## Rust Installation
|
71
|
+
|
72
|
+
Refer to the [exercism help page][help-page] for Rust installation and learning
|
73
|
+
resources.
|
74
|
+
|
75
|
+
## Writing the Code
|
76
|
+
|
77
|
+
Execute the tests with:
|
78
|
+
|
79
|
+
```bash
|
80
|
+
$ cargo test
|
81
|
+
```
|
82
|
+
|
83
|
+
All but the first test have been ignored. After you get the first test to
|
84
|
+
pass, remove the ignore flag (`#[ignore]`) from the next test and get the tests
|
85
|
+
to pass again. The test file is located in the `tests` directory. You can
|
86
|
+
also remove the ignore flag from all the tests to get them to run all at once
|
87
|
+
if you wish.
|
88
|
+
|
89
|
+
Make sure to read the [Modules](https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html) chapter if you
|
90
|
+
haven't already, it will help you with organizing your files.
|
91
|
+
|
92
|
+
## Feedback, Issues, Pull Requests
|
93
|
+
|
94
|
+
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](https://github.com/orgs/exercism/teams/rust) are happy to help!
|
95
|
+
|
96
|
+
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).
|
97
|
+
|
98
|
+
[help-page]: http://exercism.io/languages/rust
|
99
|
+
[modules]: https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html
|
100
|
+
[cargo]: https://doc.rust-lang.org/book/second-edition/ch14-00-more-about-cargo.html
|
101
|
+
|
102
|
+
## Source
|
103
|
+
|
104
|
+
Inspired by the harry potter kata from Cyber-Dojo. [http://cyber-dojo.org](http://cyber-dojo.org)
|
105
|
+
|
106
|
+
## Submitting Incomplete Solutions
|
107
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,187 @@
|
|
1
|
+
use std::cmp::Ordering;
|
2
|
+
use std::collections::{BTreeSet, HashSet};
|
3
|
+
use std::collections::hash_map::DefaultHasher;
|
4
|
+
use std::hash::{Hash, Hasher};
|
5
|
+
use std::mem;
|
6
|
+
use std::cell::RefCell;
|
7
|
+
|
8
|
+
extern crate noisy_float;
|
9
|
+
use noisy_float::prelude::*;
|
10
|
+
|
11
|
+
type Book = usize;
|
12
|
+
type GroupedBasket = Vec<Group>;
|
13
|
+
type Price = f64;
|
14
|
+
const BOOK_PRICE: Price = 8.0;
|
15
|
+
|
16
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
17
|
+
struct Group(RefCell<BTreeSet<Book>>);
|
18
|
+
|
19
|
+
impl Group {
|
20
|
+
fn new() -> Group {
|
21
|
+
Group(RefCell::new(BTreeSet::new()))
|
22
|
+
}
|
23
|
+
|
24
|
+
fn new_containing(book: Book) -> Group {
|
25
|
+
let g = Group::new();
|
26
|
+
g.0.borrow_mut().insert(book);
|
27
|
+
g
|
28
|
+
}
|
29
|
+
|
30
|
+
fn price(&self) -> Price {
|
31
|
+
(self.0.borrow().len() as Price) * BOOK_PRICE *
|
32
|
+
match self.0.borrow().len() {
|
33
|
+
2 => 0.95,
|
34
|
+
3 => 0.90,
|
35
|
+
4 => 0.80,
|
36
|
+
5 => 0.75,
|
37
|
+
_ => 1.0,
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
impl Ord for Group {
|
44
|
+
// we want to order groups first by qty contained DESC, then by lowest value ASC
|
45
|
+
fn cmp(&self, other: &Group) -> Ordering {
|
46
|
+
match other.0.borrow().len().cmp(&self.0.borrow().len()) {
|
47
|
+
Ordering::Equal => {
|
48
|
+
if self.0.borrow().len() == 0 {
|
49
|
+
Ordering::Equal
|
50
|
+
} else {
|
51
|
+
self.0.borrow().iter().next().unwrap().cmp(
|
52
|
+
other
|
53
|
+
.0
|
54
|
+
.borrow()
|
55
|
+
.iter()
|
56
|
+
.next()
|
57
|
+
.unwrap(),
|
58
|
+
)
|
59
|
+
}
|
60
|
+
}
|
61
|
+
otherwise => otherwise,
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
impl PartialOrd for Group {
|
67
|
+
fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
|
68
|
+
Some(self.cmp(other))
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
impl Hash for Group {
|
73
|
+
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
74
|
+
self.0.borrow().hash(hasher);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
fn basket_price(basket: &GroupedBasket) -> Price {
|
79
|
+
basket.iter().map(|g| g.price()).sum()
|
80
|
+
}
|
81
|
+
|
82
|
+
/// Compute the hash of a GroupedBasket
|
83
|
+
///
|
84
|
+
/// Note that we don't actually care at all about the _values_ within
|
85
|
+
/// the groups, only their lengths. Therefore, let's hash not the actual
|
86
|
+
/// GB but its lengths.
|
87
|
+
fn hash_of(basket: &GroupedBasket) -> u64 {
|
88
|
+
let lengths = basket
|
89
|
+
.iter()
|
90
|
+
.map(|g| g.0.borrow().len())
|
91
|
+
.collect::<Vec<_>>();
|
92
|
+
let mut hasher = DefaultHasher::new();
|
93
|
+
lengths.hash(&mut hasher);
|
94
|
+
hasher.finish()
|
95
|
+
}
|
96
|
+
|
97
|
+
pub fn lowest_price(books: &[Book]) -> Price {
|
98
|
+
DecomposeGroups::new(books)
|
99
|
+
.map(|gb| r64(basket_price(&gb)))
|
100
|
+
.min()
|
101
|
+
.map(|r| r.raw())
|
102
|
+
.unwrap_or(0.0)
|
103
|
+
}
|
104
|
+
|
105
|
+
struct DecomposeGroups {
|
106
|
+
prev_states: HashSet<u64>,
|
107
|
+
next: Option<GroupedBasket>,
|
108
|
+
}
|
109
|
+
|
110
|
+
impl Iterator for DecomposeGroups {
|
111
|
+
type Item = GroupedBasket;
|
112
|
+
fn next(&mut self) -> Option<Self::Item> {
|
113
|
+
// our goal here: produce a stream of valid groups, differentiated by their
|
114
|
+
// counts, from most compact to most dispersed.
|
115
|
+
//
|
116
|
+
// Algorithm:
|
117
|
+
// - Start with the most compact groups possible
|
118
|
+
// - If the number of groups == 0 or the max population of any group == 1, return None
|
119
|
+
// - For every item in the most populous group:
|
120
|
+
// - Try removing it and adding it to a smaller group.
|
121
|
+
// - Can any smaller group accept it? if yes, move it there and return
|
122
|
+
// - If it cannot be added to any smaller group, try the next item from this set
|
123
|
+
// - If no item from the most populous group can be added to any smaller group,
|
124
|
+
// then move the last item from the most populous group into a new group, alone,
|
125
|
+
// and return
|
126
|
+
let return_value = self.next.clone();
|
127
|
+
if let Some(groups) = mem::replace(&mut self.next, None) {
|
128
|
+
if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
|
129
|
+
let mut hypothetical;
|
130
|
+
for mpg_book in groups[0].0.borrow().iter() {
|
131
|
+
for (idx, other_group) in groups[1..].iter().enumerate() {
|
132
|
+
if !other_group.0.borrow().contains(mpg_book) {
|
133
|
+
hypothetical = groups.clone();
|
134
|
+
hypothetical[0].0.borrow_mut().remove(mpg_book);
|
135
|
+
hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
|
136
|
+
hypothetical.sort();
|
137
|
+
let hypothetical_hash = hash_of(&hypothetical);
|
138
|
+
if !self.prev_states.contains(&hypothetical_hash) {
|
139
|
+
self.prev_states.insert(hypothetical_hash);
|
140
|
+
mem::replace(&mut self.next, Some(hypothetical));
|
141
|
+
return return_value;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
// we've gone through all the items of the most populous group,
|
147
|
+
// and none of them can be added to any other existing group.
|
148
|
+
// We need to create a new group;
|
149
|
+
let book = {
|
150
|
+
let backing_bt = groups[0].0.borrow();
|
151
|
+
let mut book_iter = backing_bt.iter();
|
152
|
+
book_iter.next().unwrap().clone()
|
153
|
+
};
|
154
|
+
hypothetical = groups.clone();
|
155
|
+
hypothetical[0].0.borrow_mut().remove(&book);
|
156
|
+
hypothetical.push(Group::new_containing(book));
|
157
|
+
hypothetical.sort();
|
158
|
+
self.prev_states.insert(hash_of(&hypothetical));
|
159
|
+
mem::replace(&mut self.next, Some(hypothetical));
|
160
|
+
}
|
161
|
+
}
|
162
|
+
return_value
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
impl DecomposeGroups {
|
167
|
+
fn new(books: &[Book]) -> DecomposeGroups {
|
168
|
+
let mut book_groups = GroupedBasket::new();
|
169
|
+
'nextbook: for book in books {
|
170
|
+
for idx in 0..book_groups.len() {
|
171
|
+
if !book_groups[idx].0.borrow().contains(&book) {
|
172
|
+
book_groups[idx].0.borrow_mut().insert(*book);
|
173
|
+
continue 'nextbook;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
// if we're here, we still haven't found a place for the book.
|
177
|
+
// better add it to a new group
|
178
|
+
book_groups.push(Group::new_containing(*book));
|
179
|
+
}
|
180
|
+
book_groups.sort();
|
181
|
+
|
182
|
+
DecomposeGroups {
|
183
|
+
next: Some(book_groups),
|
184
|
+
prev_states: HashSet::new(),
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
@@ -0,0 +1,130 @@
|
|
1
|
+
//! Tests for book-store
|
2
|
+
//!
|
3
|
+
//! Generated by [script][script] using [canonical data][canonical-data]
|
4
|
+
//!
|
5
|
+
//! [script]: https://github.com/exercism/rust/blob/master/bin/init_exercise.py
|
6
|
+
//! [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/book-store/canonical_data.json
|
7
|
+
|
8
|
+
extern crate book_store;
|
9
|
+
use book_store::*;
|
10
|
+
|
11
|
+
/// Process a single test case for the property `total`
|
12
|
+
///
|
13
|
+
/// All cases for the `total` property are implemented
|
14
|
+
/// in terms of this function.
|
15
|
+
///
|
16
|
+
/// Expected input format: ('basket', 'targetgrouping')
|
17
|
+
fn process_total_case(input: (Vec<usize>, Vec<Vec<usize>>), expected: f64) {
|
18
|
+
assert_eq!(
|
19
|
+
lowest_price(&input.0),
|
20
|
+
expected
|
21
|
+
)
|
22
|
+
}
|
23
|
+
|
24
|
+
// Return the total basket price after applying the best discount.
|
25
|
+
// Calculate lowest price for a shopping basket containing books only from
|
26
|
+
// a single series. There is no discount advantage for having more than
|
27
|
+
// one copy of any single book in a grouping.
|
28
|
+
|
29
|
+
|
30
|
+
#[test]
|
31
|
+
/// Only a single book
|
32
|
+
fn test_only_a_single_book() {
|
33
|
+
process_total_case((vec![1], vec![vec![1]]), 8.0);
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
#[test]
|
38
|
+
#[ignore]
|
39
|
+
/// Two of the same book
|
40
|
+
fn test_two_of_the_same_book() {
|
41
|
+
process_total_case((vec![2, 2], vec![vec![2], vec![2]]), 16.0);
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
#[test]
|
46
|
+
#[ignore]
|
47
|
+
/// Empty basket
|
48
|
+
fn test_empty_basket() {
|
49
|
+
process_total_case((vec![], vec![]), 0.0);
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
#[test]
|
54
|
+
#[ignore]
|
55
|
+
/// Two different books
|
56
|
+
fn test_two_different_books() {
|
57
|
+
process_total_case((vec![1, 2], vec![vec![1, 2]]), 15.2);
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
#[test]
|
62
|
+
#[ignore]
|
63
|
+
/// Three different books
|
64
|
+
fn test_three_different_books() {
|
65
|
+
process_total_case((vec![1, 2, 3], vec![vec![1, 2, 3]]), 21.6);
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
#[test]
|
70
|
+
#[ignore]
|
71
|
+
/// Four different books
|
72
|
+
fn test_four_different_books() {
|
73
|
+
process_total_case((vec![1, 2, 3, 4], vec![vec![1, 2, 3, 4]]), 25.6);
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
#[test]
|
78
|
+
#[ignore]
|
79
|
+
/// Five different books
|
80
|
+
fn test_five_different_books() {
|
81
|
+
process_total_case((vec![1, 2, 3, 4, 5], vec![vec![1, 2, 3, 4, 5]]), 30.0);
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
#[test]
|
86
|
+
#[ignore]
|
87
|
+
/// Two groups of four is cheaper than group of five plus group of three
|
88
|
+
fn test_two_groups_of_four_is_cheaper_than_group_of_five_plus_group_of_three() {
|
89
|
+
process_total_case((vec![1, 1, 2, 2, 3, 3, 4, 5], vec![vec![1, 2, 3, 4], vec![1, 2, 3, 5]]), 51.2);
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
#[test]
|
94
|
+
#[ignore]
|
95
|
+
/// Group of four plus group of two is cheaper than two groups of three
|
96
|
+
fn test_group_of_four_plus_group_of_two_is_cheaper_than_two_groups_of_three() {
|
97
|
+
process_total_case((vec![1, 1, 2, 2, 3, 4], vec![vec![1, 2, 3, 4], vec![1, 2]]), 40.8);
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
#[test]
|
102
|
+
#[ignore]
|
103
|
+
/// Two each of first 4 books and 1 copy each of rest
|
104
|
+
fn test_two_each_of_first_4_books_and_1_copy_each_of_rest() {
|
105
|
+
process_total_case((vec![1, 1, 2, 2, 3, 3, 4, 4, 5], vec![vec![1, 2, 3, 4, 5], vec![1, 2, 3, 4]]), 55.6);
|
106
|
+
}
|
107
|
+
|
108
|
+
|
109
|
+
#[test]
|
110
|
+
#[ignore]
|
111
|
+
/// Two copies of each book
|
112
|
+
fn test_two_copies_of_each_book() {
|
113
|
+
process_total_case((vec![1, 1, 2, 2, 3, 3, 4, 4, 5, 5], vec![vec![1, 2, 3, 4, 5], vec![1, 2, 3, 4, 5]]), 60.0);
|
114
|
+
}
|
115
|
+
|
116
|
+
|
117
|
+
#[test]
|
118
|
+
#[ignore]
|
119
|
+
/// Three copies of first book and 2 each of remaining
|
120
|
+
fn test_three_copies_of_first_book_and_2_each_of_remaining() {
|
121
|
+
process_total_case((vec![1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 1], vec![vec![1, 2, 3, 4, 5], vec![1, 2, 3, 4, 5], vec![1]]), 68.0);
|
122
|
+
}
|
123
|
+
|
124
|
+
|
125
|
+
#[test]
|
126
|
+
#[ignore]
|
127
|
+
/// Three each of first 2 books and 2 each of remaining books
|
128
|
+
fn test_three_each_of_first_2_books_and_2_each_of_remaining_books() {
|
129
|
+
process_total_case((vec![1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 1, 2], vec![vec![1, 2, 3, 4, 5], vec![1, 2, 3, 4, 5], vec![1, 2]]), 75.2);
|
130
|
+
}
|
data/tracks/sml/config.json
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
"test_pattern": "test[.]sml$",
|
7
7
|
"exercises": [
|
8
8
|
{
|
9
|
-
"uuid": "
|
9
|
+
"uuid": "a00f98a6-98dd-4c8a-b3d1-adc1d56eef29",
|
10
10
|
"slug": "hello-world",
|
11
11
|
"core": true,
|
12
12
|
"unlocked_by": null,
|
@@ -46,7 +46,7 @@
|
|
46
46
|
]
|
47
47
|
},
|
48
48
|
{
|
49
|
-
"uuid": "
|
49
|
+
"uuid": "4fb40e77-727b-41bc-ac15-b909a26bb917",
|
50
50
|
"slug": "bob",
|
51
51
|
"core": false,
|
52
52
|
"unlocked_by": null,
|
@@ -126,7 +126,7 @@
|
|
126
126
|
]
|
127
127
|
},
|
128
128
|
{
|
129
|
-
"uuid": "
|
129
|
+
"uuid": "580496d5-bec7-401d-b0cf-dc16da795491",
|
130
130
|
"slug": "difference-of-squares",
|
131
131
|
"core": false,
|
132
132
|
"unlocked_by": null,
|
@@ -136,7 +136,7 @@
|
|
136
136
|
]
|
137
137
|
},
|
138
138
|
{
|
139
|
-
"uuid": "
|
139
|
+
"uuid": "0f488d4b-89da-4d1f-958b-a7b3171f43d5",
|
140
140
|
"slug": "atbash-cipher",
|
141
141
|
"core": false,
|
142
142
|
"unlocked_by": null,
|
@@ -146,7 +146,7 @@
|
|
146
146
|
]
|
147
147
|
},
|
148
148
|
{
|
149
|
-
"uuid": "
|
149
|
+
"uuid": "8ccc61c6-fac5-4af7-803e-d0f6d10f8a1f",
|
150
150
|
"slug": "perfect-numbers",
|
151
151
|
"core": false,
|
152
152
|
"unlocked_by": null,
|
@@ -156,7 +156,7 @@
|
|
156
156
|
]
|
157
157
|
},
|
158
158
|
{
|
159
|
-
"uuid": "
|
159
|
+
"uuid": "d17ab3c6-82a1-413e-9018-8775ec9ea498",
|
160
160
|
"slug": "pangram",
|
161
161
|
"core": false,
|
162
162
|
"unlocked_by": null,
|
@@ -166,7 +166,7 @@
|
|
166
166
|
]
|
167
167
|
},
|
168
168
|
{
|
169
|
-
"uuid": "
|
169
|
+
"uuid": "e8ed5a0f-796c-4a1b-af7a-2502254d79a8",
|
170
170
|
"slug": "prime-factors",
|
171
171
|
"core": false,
|
172
172
|
"unlocked_by": null,
|
@@ -206,7 +206,7 @@
|
|
206
206
|
]
|
207
207
|
},
|
208
208
|
{
|
209
|
-
"uuid": "
|
209
|
+
"uuid": "4bce27a8-2b91-4595-b6e6-d4be7e704113",
|
210
210
|
"slug": "sum-of-multiples",
|
211
211
|
"core": false,
|
212
212
|
"unlocked_by": null,
|
@@ -157,7 +157,7 @@
|
|
157
157
|
"recursion"
|
158
158
|
],
|
159
159
|
"unlocked_by": "sum-of-multiples",
|
160
|
-
"uuid": "
|
160
|
+
"uuid": "b912fe4f-c505-4bac-8029-76412644375b"
|
161
161
|
},
|
162
162
|
{
|
163
163
|
"core": true,
|
@@ -413,7 +413,7 @@
|
|
413
413
|
"mathematics"
|
414
414
|
],
|
415
415
|
"unlocked_by": "leap",
|
416
|
-
"uuid": "
|
416
|
+
"uuid": "0eb37e93-d191-4451-bd77-cd3681c91d94"
|
417
417
|
},
|
418
418
|
{
|
419
419
|
"core": true,
|
@@ -424,7 +424,7 @@
|
|
424
424
|
"control_flow_loops",
|
425
425
|
"mathematics"
|
426
426
|
],
|
427
|
-
"uuid": "
|
427
|
+
"uuid": "10edb37d-cf5d-443a-bb4c-8831a3986b61"
|
428
428
|
},
|
429
429
|
{
|
430
430
|
"core": false,
|
@@ -436,7 +436,7 @@
|
|
436
436
|
"control_flow_conditionals",
|
437
437
|
"control_flow_loops"
|
438
438
|
],
|
439
|
-
"uuid": "
|
439
|
+
"uuid": "53584e8d-9b8d-4c0e-8ad8-4c228fcf6bcf"
|
440
440
|
},
|
441
441
|
{
|
442
442
|
"core": false,
|
@@ -447,7 +447,7 @@
|
|
447
447
|
"iterators",
|
448
448
|
"mathematics"
|
449
449
|
],
|
450
|
-
"uuid": "
|
450
|
+
"uuid": "dbe39983-5635-4369-89a3-fd549144259b"
|
451
451
|
},
|
452
452
|
{
|
453
453
|
"core": false,
|
@@ -511,7 +511,7 @@
|
|
511
511
|
"uuid": "61f0964f-0779-446d-bd6b-6bb988414302"
|
512
512
|
},
|
513
513
|
{
|
514
|
-
"uuid": "
|
514
|
+
"uuid": "df7c1bff-2224-422b-9c34-64b28b09510e",
|
515
515
|
"slug": "diamond",
|
516
516
|
"core": false,
|
517
517
|
"unlocked_by": "pascals-triangle",
|