From 8f70a722a1af713a4c5e2d7a1504c17019b91ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Fri, 24 May 2024 21:11:37 -0700 Subject: [PATCH] Add armstrong numbers (#171) --- config.json | 8 + .../armstrong-numbers/.docs/instructions.md | 14 ++ .../armstrong-numbers/.meta/config.json | 19 ++ .../armstrong-numbers/.meta/example.red | 16 ++ .../armstrong-numbers/.meta/tests.toml | 45 ++++ .../armstrong-numbers-test.red | 96 ++++++++ .../armstrong-numbers/armstrong-numbers.red | 11 + .../practice/armstrong-numbers/testlib.red | 217 ++++++++++++++++++ 8 files changed, 426 insertions(+) create mode 100644 exercises/practice/armstrong-numbers/.docs/instructions.md create mode 100644 exercises/practice/armstrong-numbers/.meta/config.json create mode 100644 exercises/practice/armstrong-numbers/.meta/example.red create mode 100644 exercises/practice/armstrong-numbers/.meta/tests.toml create mode 100644 exercises/practice/armstrong-numbers/armstrong-numbers-test.red create mode 100644 exercises/practice/armstrong-numbers/armstrong-numbers.red create mode 100644 exercises/practice/armstrong-numbers/testlib.red diff --git a/config.json b/config.json index 77855d0..fb9777f 100644 --- a/config.json +++ b/config.json @@ -50,6 +50,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "armstrong-numbers", + "name": "Armstrong Numbers", + "uuid": "7ee5d442-dbed-4831-aee1-3d58070dcc36", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "binary-search", "name": "Binary Search", diff --git a/exercises/practice/armstrong-numbers/.docs/instructions.md b/exercises/practice/armstrong-numbers/.docs/instructions.md new file mode 100644 index 0000000..5e56bbe --- /dev/null +++ b/exercises/practice/armstrong-numbers/.docs/instructions.md @@ -0,0 +1,14 @@ +# Instructions + +An [Armstrong number][armstrong-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. + +[armstrong-number]: https://en.wikipedia.org/wiki/Narcissistic_number diff --git a/exercises/practice/armstrong-numbers/.meta/config.json b/exercises/practice/armstrong-numbers/.meta/config.json new file mode 100644 index 0000000..93a2452 --- /dev/null +++ b/exercises/practice/armstrong-numbers/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "armstrong-numbers.red" + ], + "test": [ + "armstrong-numbers-test.red" + ], + "example": [ + ".meta/example.red" + ] + }, + "blurb": "Determine if a number is an Armstrong number.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Narcissistic_number" +} diff --git a/exercises/practice/armstrong-numbers/.meta/example.red b/exercises/practice/armstrong-numbers/.meta/example.red new file mode 100644 index 0000000..d2b6e8c --- /dev/null +++ b/exercises/practice/armstrong-numbers/.meta/example.red @@ -0,0 +1,16 @@ +Red [ + description: {"Armstrong Numbers" exercise solution for exercism platform} + author: "BNAndras" +] + +is-armstrong-number: function [ + number +] [ + working: 0 + digits: to-string number + foreach digit digits [ + working: working + power to-integer form digit length? digits + ] + working == number +] + diff --git a/exercises/practice/armstrong-numbers/.meta/tests.toml b/exercises/practice/armstrong-numbers/.meta/tests.toml new file mode 100644 index 0000000..b956bdf --- /dev/null +++ b/exercises/practice/armstrong-numbers/.meta/tests.toml @@ -0,0 +1,45 @@ +# 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. + +[c1ed103c-258d-45b2-be73-d8c6d9580c7b] +description = "Zero is an Armstrong number" + +[579e8f03-9659-4b85-a1a2-d64350f6b17a] +description = "Single-digit numbers are Armstrong numbers" + +[2d6db9dc-5bf8-4976-a90b-b2c2b9feba60] +description = "There are no two-digit Armstrong numbers" + +[509c087f-e327-4113-a7d2-26a4e9d18283] +description = "Three-digit number that is an Armstrong number" + +[7154547d-c2ce-468d-b214-4cb953b870cf] +description = "Three-digit number that is not an Armstrong number" + +[6bac5b7b-42e9-4ecb-a8b0-4832229aa103] +description = "Four-digit number that is an Armstrong number" + +[eed4b331-af80-45b5-a80b-19c9ea444b2e] +description = "Four-digit number that is not an Armstrong number" + +[f971ced7-8d68-4758-aea1-d4194900b864] +description = "Seven-digit number that is an Armstrong number" + +[7ee45d52-5d35-4fbd-b6f1-5c8cd8a67f18] +description = "Seven-digit number that is not an Armstrong number" + +[5ee2fdf8-334e-4a46-bb8d-e5c19c02c148] +description = "Armstrong number containing seven zeroes" +include = false + +[12ffbf10-307a-434e-b4ad-c925680e1dd4] +description = "The largest and last Armstrong number" +include = false diff --git a/exercises/practice/armstrong-numbers/armstrong-numbers-test.red b/exercises/practice/armstrong-numbers/armstrong-numbers-test.red new file mode 100644 index 0000000..cc711a0 --- /dev/null +++ b/exercises/practice/armstrong-numbers/armstrong-numbers-test.red @@ -0,0 +1,96 @@ +Red [ + description: {Tests for "Armstrong Numbers" Exercism exercise} + author: "loziniak" +] + +#include %testlib.red + +test-init/limit %armstrong-numbers.red 1 +; test-init/limit %.meta/example.red 1 ; test example solution + +canonical-cases: [#[ + description: "Zero is an Armstrong number" + input: #[ + number: 0 + ] + expected: true + function: "is-armstrong-number" + uuid: "c1ed103c-258d-45b2-be73-d8c6d9580c7b" +] #[ + description: "Single-digit numbers are Armstrong numbers" + input: #[ + number: 5 + ] + expected: true + function: "is-armstrong-number" + uuid: "579e8f03-9659-4b85-a1a2-d64350f6b17a" +] #[ + description: "There are no two-digit Armstrong numbers" + input: #[ + number: 10 + ] + expected: false + function: "is-armstrong-number" + uuid: "2d6db9dc-5bf8-4976-a90b-b2c2b9feba60" +] #[ + description: "Three-digit number that is an Armstrong number" + input: #[ + number: 153 + ] + expected: true + function: "is-armstrong-number" + uuid: "509c087f-e327-4113-a7d2-26a4e9d18283" +] #[ + description: {Three-digit number that is not an Armstrong number} + input: #[ + number: 100 + ] + expected: false + function: "is-armstrong-number" + uuid: "7154547d-c2ce-468d-b214-4cb953b870cf" +] #[ + description: "Four-digit number that is an Armstrong number" + input: #[ + number: 9474 + ] + expected: true + function: "is-armstrong-number" + uuid: "6bac5b7b-42e9-4ecb-a8b0-4832229aa103" +] #[ + description: "Four-digit number that is not an Armstrong number" + input: #[ + number: 9475 + ] + expected: false + function: "is-armstrong-number" + uuid: "eed4b331-af80-45b5-a80b-19c9ea444b2e" +] #[ + description: "Seven-digit number that is an Armstrong number" + input: #[ + number: 9926315 + ] + expected: true + function: "is-armstrong-number" + uuid: "f971ced7-8d68-4758-aea1-d4194900b864" +] #[ + description: {Seven-digit number that is not an Armstrong number} + input: #[ + number: 9926314 + ] + expected: false + function: "is-armstrong-number" + uuid: "7ee45d52-5d35-4fbd-b6f1-5c8cd8a67f18" +]] + + +foreach c-case canonical-cases [ + case-code: reduce [ + 'expect c-case/expected compose [ + (to word! c-case/function) (values-of c-case/input) + ] + ] + + test c-case/description case-code +] + +test-results/print diff --git a/exercises/practice/armstrong-numbers/armstrong-numbers.red b/exercises/practice/armstrong-numbers/armstrong-numbers.red new file mode 100644 index 0000000..4ac9b93 --- /dev/null +++ b/exercises/practice/armstrong-numbers/armstrong-numbers.red @@ -0,0 +1,11 @@ +Red [ + description: {"Armstrong Numbers" exercise solution for exercism platform} + author: "" ; you can write your name here, in quotes +] + +is-armstrong-number: function [ + number +] [ + cause-error 'user 'message "You need to implement is-armstrong-number function." +] + diff --git a/exercises/practice/armstrong-numbers/testlib.red b/exercises/practice/armstrong-numbers/testlib.red new file mode 100644 index 0000000..9b0b79e --- /dev/null +++ b/exercises/practice/armstrong-numbers/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 + ] + +]