diff --git a/config.json b/config.json index 6cf193ab..a4a73ad1 100644 --- a/config.json +++ b/config.json @@ -1217,6 +1217,22 @@ "result" ], "difficulty": 5 + }, + { + "slug": "sieve", + "name": "sieve", + "uuid": "60804d7f-8eb3-46e0-8337-45b7426456b0", + "practices": [ + "array" + ], + "prerequisites": [ + "booleans", + "maybe", + "pattern-matching", + "array", + "lists" + ], + "difficulty": 6 } ] }, diff --git a/exercises/practice/sieve/.docs/instructions.md b/exercises/practice/sieve/.docs/instructions.md new file mode 100644 index 00000000..3adf1d55 --- /dev/null +++ b/exercises/practice/sieve/.docs/instructions.md @@ -0,0 +1,28 @@ +# Instructions + +Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find prime numbers. + +A prime number is a number that is only divisible by 1 and itself. +For example, 2, 3, 5, 7, 11, and 13 are prime numbers. + +The Sieve of Eratosthenes is an ancient algorithm that works by taking a list of numbers and crossing out all the numbers that aren't prime. + +A number that is **not** prime is called a "composite number". + +To use the Sieve of Eratosthenes, you first create a list of all the numbers between 2 and your given number. +Then you repeat the following steps: + +1. Find the next unmarked number in your list. This is a prime number. +2. Mark all the multiples of that prime number as composite (not prime). + +You keep repeating these steps until you've gone through every number in your list. +At the end, all the unmarked numbers are prime. + +~~~~exercism/note +[Wikipedia's Sieve of Eratosthenes article][eratosthenes] has a useful graphic that explains the algorithm. + +The tests don't check that you've implemented the algorithm, only that you've come up with the correct list of primes. +A good first test is to check that you do not use division or remainder operations. + +[eratosthenes]: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes +~~~~ diff --git a/exercises/practice/sieve/.docs/introduction.md b/exercises/practice/sieve/.docs/introduction.md new file mode 100644 index 00000000..f6c1cf79 --- /dev/null +++ b/exercises/practice/sieve/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +You bought a big box of random computer parts at a garage sale. +You've started putting the parts together to build custom computers. + +You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare. +You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits. diff --git a/exercises/practice/sieve/.meta/config.json b/exercises/practice/sieve/.meta/config.json new file mode 100644 index 00000000..21368f96 --- /dev/null +++ b/exercises/practice/sieve/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jiegillet" + ], + "files": { + "solution": [ + "src/Sieve.elm" + ], + "test": [ + "tests/Tests.elm" + ], + "example": [ + ".meta/src/Sieve.example.elm" + ] + }, + "blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.", + "source": "Sieve of Eratosthenes at Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" +} diff --git a/exercises/practice/sieve/.meta/src/Sieve.example.elm b/exercises/practice/sieve/.meta/src/Sieve.example.elm new file mode 100644 index 00000000..39a6af42 --- /dev/null +++ b/exercises/practice/sieve/.meta/src/Sieve.example.elm @@ -0,0 +1,68 @@ +module Sieve exposing (primes) + +import Array exposing (Array) + + +primes : Int -> List Int +primes limit = + let + -- an array, with indices from 0 until limit, each with a Bool value representing primeness + initialSieve = + Array.initialize (limit + 1) + (\n -> + if n < 2 then + False + + else + True + ) + + initialPrime = + Just 2 + in + runSieve initialPrime initialSieve + |> Array.toIndexedList + |> List.filterMap + (\( index, isPrime ) -> + if isPrime then + Just index + + else + Nothing + ) + + +runSieve : Maybe Int -> Array Bool -> Array Bool +runSieve maybePrime sieve = + case maybePrime of + Nothing -> + sieve + + Just prime -> + let + removeMultiples : Int -> Array Bool -> Array Bool + removeMultiples multiple = + if multiple > Array.length sieve then + identity + + else + Array.set multiple False + >> removeMultiples (multiple + prime) + + sieveWithPrimeMultipleRemoved : Array Bool + sieveWithPrimeMultipleRemoved = + removeMultiples (2 * prime) sieve + + findNextPrime : Int -> Maybe Int + findNextPrime index = + case Array.get index sieveWithPrimeMultipleRemoved of + Nothing -> + Nothing + + Just True -> + Just index + + Just False -> + findNextPrime (index + 1) + in + runSieve (findNextPrime (prime + 1)) sieveWithPrimeMultipleRemoved diff --git a/exercises/practice/sieve/.meta/tests.toml b/exercises/practice/sieve/.meta/tests.toml new file mode 100644 index 00000000..fec5e1a1 --- /dev/null +++ b/exercises/practice/sieve/.meta/tests.toml @@ -0,0 +1,25 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[88529125-c4ce-43cc-bb36-1eb4ddd7b44f] +description = "no primes under two" + +[4afe9474-c705-4477-9923-840e1024cc2b] +description = "find first prime" + +[974945d8-8cd9-4f00-9463-7d813c7f17b7] +description = "find primes up to 10" + +[2e2417b7-3f3a-452a-8594-b9af08af6d82] +description = "limit is prime" + +[92102a05-4c7c-47de-9ed0-b7d5fcd00f21] +description = "find primes up to 1000" diff --git a/exercises/practice/sieve/elm.json b/exercises/practice/sieve/elm.json new file mode 100644 index 00000000..22c9e137 --- /dev/null +++ b/exercises/practice/sieve/elm.json @@ -0,0 +1,29 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/core": "1.0.5", + "elm/json": "1.1.3", + "elm/parser": "1.1.0", + "elm/random": "1.0.0", + "elm/regex": "1.0.0", + "elm/time": "1.0.0" + }, + "indirect": {} + }, + "test-dependencies": { + "direct": { + "elm-explorations/test": "2.1.0", + "rtfeldman/elm-iso8601-date-strings": "1.1.4" + }, + "indirect": { + "elm/bytes": "1.0.8", + "elm/html": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + } +} diff --git a/exercises/practice/sieve/src/Sieve.elm b/exercises/practice/sieve/src/Sieve.elm new file mode 100644 index 00000000..8bd231fd --- /dev/null +++ b/exercises/practice/sieve/src/Sieve.elm @@ -0,0 +1,6 @@ +module Sieve exposing (primes) + + +primes : Int -> List Int +primes limit = + Debug.todo "Please implement primes" diff --git a/exercises/practice/sieve/tests/Tests.elm b/exercises/practice/sieve/tests/Tests.elm new file mode 100644 index 00000000..3e2ee614 --- /dev/null +++ b/exercises/practice/sieve/tests/Tests.elm @@ -0,0 +1,36 @@ +module Tests exposing (tests) + +import Expect +import Sieve +import Test exposing (Test, describe, skip, test) + + +tests : Test +tests = + describe "Sieve" + [ -- skip <| + test "no primes under two" <| + \() -> + Sieve.primes 1 + |> Expect.equal [] + , skip <| + test "find first prime" <| + \() -> + Sieve.primes 2 + |> Expect.equal [ 2 ] + , skip <| + test "find primes up to 10" <| + \() -> + Sieve.primes 10 + |> Expect.equal [ 2, 3, 5, 7 ] + , skip <| + test "limit is prime" <| + \() -> + Sieve.primes 13 + |> Expect.equal [ 2, 3, 5, 7, 11, 13 ] + , skip <| + test "find primes up to 1000" <| + \() -> + Sieve.primes 1000 + |> Expect.equal [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 ] + ]