diff --git a/config.json b/config.json index 59589d2..56e1b76 100644 --- a/config.json +++ b/config.json @@ -165,6 +165,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "nth-prime", + "name": "Nth Prime", + "uuid": "2ea97355-acb9-4043-b107-964b6b7a1752", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "pangram", "name": "Pangram", diff --git a/exercises/practice/nth-prime/.docs/instructions.md b/exercises/practice/nth-prime/.docs/instructions.md new file mode 100644 index 0000000..065e323 --- /dev/null +++ b/exercises/practice/nth-prime/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +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. diff --git a/exercises/practice/nth-prime/.meta/config.json b/exercises/practice/nth-prime/.meta/config.json new file mode 100644 index 0000000..09c4b3b --- /dev/null +++ b/exercises/practice/nth-prime/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "nth-prime.red" + ], + "test": [ + "nth-prime-test.red" + ], + "example": [ + ".meta/example.red" + ] + }, + "blurb": "Given a number n, determine what the nth prime is.", + "source": "A variation on Problem 7 at Project Euler", + "source_url": "https://projecteuler.net/problem=7" +} diff --git a/exercises/practice/nth-prime/.meta/example.red b/exercises/practice/nth-prime/.meta/example.red new file mode 100644 index 0000000..2f1d4ad --- /dev/null +++ b/exercises/practice/nth-prime/.meta/example.red @@ -0,0 +1,41 @@ +Red [ + description: {"Nth Prime" exercise solution for exercism platform} + author: "BNAndras" +] + +prime: function [ + number +] [ + if number == 0 [ + cause-error 'user 'message "there is no zeroth prime" + ] + + if number == 1 [return 2] + + + tally: 1 + candidate: 1 + while [tally < number] [ + candidate: candidate + 2 + + if prime? candidate [ + tally: tally + 1 + ] + ] + candidate +] + +prime?: function [ + number +] [ + if number <= 1 [return false] + if number == 2 [return true] + if number % 2 == 0 [return false] + + prime: 3 + while [prime * prime <= number] [ + if number % prime == 0 [return false] + prime: prime + 2 + ] + true +] diff --git a/exercises/practice/nth-prime/.meta/tests.toml b/exercises/practice/nth-prime/.meta/tests.toml new file mode 100644 index 0000000..daccec4 --- /dev/null +++ b/exercises/practice/nth-prime/.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. + +[75c65189-8aef-471a-81de-0a90c728160c] +description = "first prime" + +[2c38804c-295f-4701-b728-56dea34fd1a0] +description = "second prime" + +[56692534-781e-4e8c-b1f9-3e82c1640259] +description = "sixth prime" + +[fce1e979-0edb-412d-93aa-2c744e8f50ff] +description = "big prime" + +[bd0a9eae-6df7-485b-a144-80e13c7d55b2] +description = "there is no zeroth prime" diff --git a/exercises/practice/nth-prime/nth-prime-test.red b/exercises/practice/nth-prime/nth-prime-test.red new file mode 100644 index 0000000..0b965b6 --- /dev/null +++ b/exercises/practice/nth-prime/nth-prime-test.red @@ -0,0 +1,73 @@ +Red [ + description: {Tests for "Nth Prime" Exercism exercise} + author: "loziniak" +] + +#include %testlib.red + +test-init/limit %nth-prime.red 1 +; test-init/limit %.meta/example.red 1 ; test example solution + +canonical-cases: [#[ + description: "first prime" + input: #[ + number: 1 + ] + expected: 2 + function: "prime" + uuid: "75c65189-8aef-471a-81de-0a90c728160c" +] #[ + description: "second prime" + input: #[ + number: 2 + ] + expected: 3 + function: "prime" + uuid: "2c38804c-295f-4701-b728-56dea34fd1a0" +] #[ + description: "sixth prime" + input: #[ + number: 6 + ] + expected: 13 + function: "prime" + uuid: "56692534-781e-4e8c-b1f9-3e82c1640259" +] #[ + description: "big prime" + input: #[ + number: 10001 + ] + expected: 104743 + function: "prime" + uuid: "fce1e979-0edb-412d-93aa-2c744e8f50ff" +] #[ + description: "there is no zeroth prime" + input: #[ + number: 0 + ] + expected: #[ + error: "there is no zeroth prime" + ] + function: "prime" + uuid: "bd0a9eae-6df7-485b-a144-80e13c7d55b2" +]] + + +foreach c-case canonical-cases [ + expect-code: compose [ + (to word! c-case/function) (values-of c-case/input) + ] + case-code: reduce + either all [ + map? c-case/expected + string? c-case/expected/error + ] [ + ['expect-error/message quote 'user expect-code c-case/expected/error] + ] [ + ['expect c-case/expected expect-code] + ] + + test c-case/description case-code +] + +test-results/print diff --git a/exercises/practice/nth-prime/nth-prime.red b/exercises/practice/nth-prime/nth-prime.red new file mode 100644 index 0000000..c88c6b0 --- /dev/null +++ b/exercises/practice/nth-prime/nth-prime.red @@ -0,0 +1,11 @@ +Red [ + description: {"Nth Prime" exercise solution for exercism platform} + author: "" ; you can write your name here, in quotes +] + +prime: function [ + number +] [ + cause-error 'user 'message "You need to implement prime function." +] + diff --git a/exercises/practice/nth-prime/testlib.red b/exercises/practice/nth-prime/testlib.red new file mode 100644 index 0000000..9b0b79e --- /dev/null +++ b/exercises/practice/nth-prime/testlib.red @@ -0,0 +1,217 @@ +Red [ + description: {Unit testing library} + author: "loziniak" +] + + +context [ + tested: ignore-after: test-file: results: output: none + + set 'test-init function [ + file [file!] + /limit + ia [integer!] + ] [ + self/tested: 0 + self/ignore-after: either limit [ia] [none] + self/test-file: file + self/results: copy [] + self/output: copy "" + ] + + sandbox!: context [ + + assert: function [ + code [block!] + /local result + ] [ + res: last results + + set/any 'result do code + either :result = true [ + res/status: 'pass + ] [ + res/status: 'fail + throw/name none 'expect-fail + ] + + :result + ] + + expect: function [ + expectation [any-type!] + code [block!] + /local result + ] [ + res: last results + res/expected: :expectation + + set/any 'result do code + res/actual: :result + + either :result = :expectation [ + res/status: 'pass + ] [ + res/status: 'fail + throw/name none 'expect-fail + ] + + :result + ] + + expect-error: function [ + type [word!] + code [block!] + /message + msg [string!] + /local result result-or-error + ] [ + returned-error?: no + set/any 'result-or-error try [ + set/any 'result do code + returned-error?: yes + :result + ] + + res: last results + res/actual: :result-or-error + res/expected: compose [type: (type)] + if message [append res/expected compose [id: 'message arg1: (msg)]] + + either all [ + error? :result-or-error + not returned-error? + result-or-error/type = type + any [ + not message + all [ + result-or-error/id = 'message + result-or-error/arg1 = msg + ] + ] + ] [ + res/status: 'pass + ] [ + res/status: 'fail + throw/name none 'expect-fail + ] + + :result-or-error + ] + ] + + set 'test function [ + summary [string!] + code [block!] + /extern + tested + ] [ + append results result: make map! compose/only [ + summary: (summary) ;@@ [string!] + test-code: (copy code) ;@@ [block!] + status: none ;@@ [word!] : 'pass | 'fail | 'error | 'ignored + ;-- expected (optional field) + ;-- actual (optional field) + ;-- output (optional field) + ] + + either any [ + none? ignore-after + tested < ignore-after + ] [ + clear output + old-functions: override-console + + exercise: make sandbox! load test-file + code: bind code exercise + uncaught?: yes + outcome: catch [ + outcome: try [ + catch/name [ + do code + ] 'expect-fail + none + ] + uncaught?: no + outcome + ] + + case [ + error? outcome [ + result/status: 'error + result/actual: outcome + ] + uncaught? [ + result/status: 'error + result/actual: make error! [type: 'throw id: 'throw arg1: outcome] + ] + ] + + restore-console old-functions + result/output: copy output + ] [ + result/status: 'ignored + ] + + tested: tested + 1 + ] + + set 'test-results function [ + /print + ] [ + either print [ + foreach result self/results [ + system/words/print rejoin [ + pad/with result/summary 40 #"." + "... " + switch result/status [ + pass ["✓"] + fail [rejoin [ + {FAILED.} + either find result 'expected [rejoin [ + { Expected: } result/expected + either find result 'actual [rejoin [ + {, but got } result/actual + ]] [] + ]] [] + newline + result/output + ]] + error [rejoin [ + newline + result/output + form result/actual + ]] + ignored ["(ignored)"] + ] + ] + ] + ] [ + self/results + ] + ] + + + override-console: function [] [ + old-functions: reduce [:prin :print :probe] + + system/words/prin: function [value [any-type!]] [ + append self/output form :value + return () + ] + system/words/print: function [value [any-type!]] [ + append self/output reduce [form :value #"^/"] + return () + ] + system/words/probe: function [value [any-type!]] [ + append self/output reduce [mold :value #"^/"] + return :value + ] + return old-functions + ] + + restore-console: function [old-functions [block!]] [ + set [prin print probe] old-functions + ] + +]