luhn
This commit is contained in:
115
config.json
115
config.json
@@ -16,119 +16,151 @@
|
||||
"highlightjs_language": "TODO: specify highlightjs language"
|
||||
},
|
||||
"files": {
|
||||
"solution": ["%{pascal_slug}.8th"],
|
||||
"test": ["%{pascal_slug}-tests.8th"],
|
||||
"example": [".meta/example.8th"],
|
||||
"exemplar": [".meta/exemplar.8th"]
|
||||
"solution": [
|
||||
"%{pascal_slug}.8th"
|
||||
],
|
||||
"test": [
|
||||
"%{pascal_slug}-tests.8th"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.8th"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.8th"
|
||||
]
|
||||
},
|
||||
"exercises": {
|
||||
"concept": [],
|
||||
"practice": [{
|
||||
"practice": [
|
||||
{
|
||||
"slug": "hello-world",
|
||||
"name": "Hello World",
|
||||
"uuid": "0c6d16eb-3a07-42ee-ba14-fa910e67a91f",
|
||||
"prerequisites": [],
|
||||
"difficulty": 1,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "two-fer",
|
||||
"name": "Two Fer",
|
||||
"uuid": "8e69c859-d131-4c2c-b0b7-e5cfadd5d679",
|
||||
"prerequisites": [],
|
||||
"difficulty": 1,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "leap",
|
||||
"name": "Leap",
|
||||
"uuid": "b46ecfb1-59ee-4776-a8fa-f8bd23cf15db",
|
||||
"prerequisites": [],
|
||||
"difficulty": 1,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "triangle",
|
||||
"name": "Triangle",
|
||||
"uuid": "12389895-0775-41f2-90bb-db65bc2ecfaf",
|
||||
"prerequisites": [],
|
||||
"difficulty": 2,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "trinary",
|
||||
"name": "Trinary (Base-3) Numbers",
|
||||
"uuid": "6cf0dbc3-e90e-4a7f-a95b-507ef389d316",
|
||||
"prerequisites": [],
|
||||
"difficulty": 2,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "bob",
|
||||
"name": "Bob",
|
||||
"uuid": "b34b3dd7-9df2-4b3d-970d-f4b3a3a15358",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "hamming",
|
||||
"name": "Hamming",
|
||||
"uuid": "ead8a049-708c-4413-b58c-9526e6f66bfb",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "raindrops",
|
||||
"name": "Raindrops",
|
||||
"uuid": "6247ab47-f00e-4ab0-8bb9-1ca4110eaf0b",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "armstrong-numbers",
|
||||
"name": "Armstrong Numbers",
|
||||
"uuid": "fdc96f81-bba3-4a79-bd7d-3eab7bcdb446",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "isogram",
|
||||
"name": "Isogram",
|
||||
"uuid": "6d34e782-2002-4073-a935-9e50b9ac9d2e",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "acronym",
|
||||
"name": "Acronym",
|
||||
"uuid": "2b310b6a-cccc-4890-ae83-e0729cac412a",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "luhn",
|
||||
"name": "Luhn Credit Card Number Checker",
|
||||
"uuid": "b36a18cc-4385-40ba-9113-af5bf2ea349e",
|
||||
"prerequisites": [],
|
||||
"difficulty": 3,
|
||||
"practices": []
|
||||
},
|
||||
{
|
||||
"slug": "collatz-conjecture",
|
||||
"name": "Collatz Conjecture",
|
||||
"uuid": "7968006c-efdc-410c-a2fa-305a37528705",
|
||||
"prerequisites": [],
|
||||
"difficulty": 4,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "pangram",
|
||||
"name": "Pangram",
|
||||
"uuid": "077b874d-4094-46c2-9433-af64dd19ddfa",
|
||||
"prerequisites": [],
|
||||
"difficulty": 5,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "yacht",
|
||||
"name": "Yacht",
|
||||
"uuid": "b1d34538-6c5c-476b-a79f-4cd55ac96e0b",
|
||||
"prerequisites": [],
|
||||
"difficulty": 6,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "roman-numerals",
|
||||
"name": "Roman Numerals",
|
||||
"uuid": "2b4c2a11-2639-4c9b-9ec1-5c20ee14da52",
|
||||
"prerequisites": [],
|
||||
"difficulty": 7,
|
||||
"practices": []
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"slug": "reverse-string",
|
||||
"name": "Reverse string",
|
||||
"uuid": "a76d512f-2b44-46eb-87e5-b6f9b90a5309",
|
||||
@@ -139,31 +171,58 @@
|
||||
]
|
||||
},
|
||||
"concepts": [],
|
||||
"key_features": [{
|
||||
"key_features": [
|
||||
{
|
||||
"icon": "safe",
|
||||
"title": "Safe",
|
||||
"content": "8th was designed from the beginning to avoid the most common software security problems."
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"icon": "cross-platform",
|
||||
"title": "Cross-platform",
|
||||
"content": "With one click generate the executable for any platform 8th supports, from any platform it supports!"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"icon": "expressive",
|
||||
"title": "Expressive",
|
||||
"content": "No reserved words at all and almost no syntax."
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"icon": "general-purpose",
|
||||
"title": "General purpose",
|
||||
"content": "8th is primarily a strongly-typed FORTH-like stack-based procedural language with RPN syntax."
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"icon": "interactive",
|
||||
"title": "Interactive",
|
||||
"content": "8th has an interactive REPL."
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"icon": "documentation",
|
||||
"title": "Documentation",
|
||||
"content": "Documentation is extensive, making it easy to get started with 8th."
|
||||
}
|
||||
],
|
||||
"tags": ["paradigm/functional", "paradigm/imperative", "paradigm/procedural", "typing/static", "typing/strong", "typing/dynamic", "execution_mode/compiled", "execution_mode/interpreted", "platform/windows", "platform/mac", "platform/linux", "platform/ios", "platform/android", "used_for/backends", "used_for/cross_platform_development", "used_for/frontends", "used_for/games", "used_for/guis", "used_for/mobile", "used_for/web_development"]
|
||||
}
|
||||
"tags": [
|
||||
"paradigm/functional",
|
||||
"paradigm/imperative",
|
||||
"paradigm/procedural",
|
||||
"typing/static",
|
||||
"typing/strong",
|
||||
"typing/dynamic",
|
||||
"execution_mode/compiled",
|
||||
"execution_mode/interpreted",
|
||||
"platform/windows",
|
||||
"platform/mac",
|
||||
"platform/linux",
|
||||
"platform/ios",
|
||||
"platform/android",
|
||||
"used_for/backends",
|
||||
"used_for/cross_platform_development",
|
||||
"used_for/frontends",
|
||||
"used_for/games",
|
||||
"used_for/guis",
|
||||
"used_for/mobile",
|
||||
"used_for/web_development"
|
||||
]
|
||||
}
|
||||
64
exercises/practice/luhn/.docs/instructions.md
Normal file
64
exercises/practice/luhn/.docs/instructions.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Instructions
|
||||
|
||||
Given a number determine whether or not it is valid per the Luhn formula.
|
||||
|
||||
The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is
|
||||
a simple checksum formula used to validate a variety of identification
|
||||
numbers, such as credit card numbers and Canadian Social Insurance
|
||||
Numbers.
|
||||
|
||||
The task is to check if a given string is valid.
|
||||
|
||||
## Validating a Number
|
||||
|
||||
Strings of length 1 or less are not valid. Spaces are allowed in the input,
|
||||
but they should be stripped before checking. All other non-digit characters
|
||||
are disallowed.
|
||||
|
||||
## Example 1: valid credit card number
|
||||
|
||||
```text
|
||||
4539 3195 0343 6467
|
||||
```
|
||||
|
||||
The first step of the Luhn algorithm is to double every second digit,
|
||||
starting from the right. We will be doubling
|
||||
|
||||
```text
|
||||
4_3_ 3_9_ 0_4_ 6_6_
|
||||
```
|
||||
|
||||
If doubling the number results in a number greater than 9 then subtract 9
|
||||
from the product. The results of our doubling:
|
||||
|
||||
```text
|
||||
8569 6195 0383 3437
|
||||
```
|
||||
|
||||
Then sum all of the digits:
|
||||
|
||||
```text
|
||||
8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80
|
||||
```
|
||||
|
||||
If the sum is evenly divisible by 10, then the number is valid. This number is valid!
|
||||
|
||||
## Example 2: invalid credit card number
|
||||
|
||||
```text
|
||||
8273 1232 7352 0569
|
||||
```
|
||||
|
||||
Double the second digits, starting from the right
|
||||
|
||||
```text
|
||||
7253 2262 5312 0539
|
||||
```
|
||||
|
||||
Sum the digits
|
||||
|
||||
```text
|
||||
7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57
|
||||
```
|
||||
|
||||
57 is not evenly divisible by 10, so this number is not valid.
|
||||
20
exercises/practice/luhn/.meta/config.json
Normal file
20
exercises/practice/luhn/.meta/config.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"blurb": "Given a number determine whether or not it is valid per the Luhn formula.",
|
||||
"authors": [
|
||||
"rosettacode"
|
||||
],
|
||||
"contributors": [],
|
||||
"files": {
|
||||
"solution": [
|
||||
"luhn.8th"
|
||||
],
|
||||
"test": [
|
||||
"luhn.tests.8th"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.8th"
|
||||
]
|
||||
},
|
||||
"source": "The Luhn Algorithm on Wikipedia",
|
||||
"source_url": "http://en.wikipedia.org/wiki/Luhn_algorithm"
|
||||
}
|
||||
35
exercises/practice/luhn/.meta/example.8th
Normal file
35
exercises/practice/luhn/.meta/example.8th
Normal file
@@ -0,0 +1,35 @@
|
||||
\ Adapted from the C version:
|
||||
: remap \ n1 -- n2
|
||||
[0,2,4,6,8,1,3,5,7,9]
|
||||
swap caseof ;
|
||||
|
||||
: length-gt-1 \ s -- T
|
||||
s:len 1 n:>
|
||||
;
|
||||
|
||||
: contains-only-numeric \ s -- T
|
||||
dup /[^0-9]/ r:match 0 n:=
|
||||
;
|
||||
|
||||
: valid? \ s -- T
|
||||
length-gt-1 !if false ;then
|
||||
contains-only-numeric !if drop false ;then
|
||||
drop
|
||||
true
|
||||
;
|
||||
|
||||
: strip-spaces \ s -- s
|
||||
" " "" s:replace!
|
||||
;
|
||||
|
||||
: luhn \ s -- f
|
||||
strip-spaces
|
||||
valid? !if drop false ;then
|
||||
0 swap
|
||||
s:rev
|
||||
(
|
||||
'0 n:-
|
||||
swap 2 n:mod if remap then
|
||||
n:+
|
||||
) s:each
|
||||
10 n:mod not ;
|
||||
67
exercises/practice/luhn/luhn-tests.8th
Normal file
67
exercises/practice/luhn/luhn-tests.8th
Normal file
@@ -0,0 +1,67 @@
|
||||
"single digit strings can not be valid"
|
||||
( "1" luhn ) test_false
|
||||
|
||||
"a single zero is invalid"
|
||||
( "0" luhn ) test_false
|
||||
|
||||
"a simple valid SIN that remains valid if reversed"
|
||||
( "059" luhn ) test_true
|
||||
|
||||
\ "a simple valid SIN that becomes invalid if reversed"
|
||||
\ ( "59" luhn ) test_true
|
||||
\
|
||||
\ "a valid Canadian SIN"
|
||||
\ ( "055 444 285" luhn ) test_true
|
||||
\
|
||||
\ "invalid Canadian SIN"
|
||||
\ ( "055 444 286" luhn ) test_false
|
||||
\
|
||||
\ "invalid credit card"
|
||||
\ ( "8273 1232 7352 0569" luhn ) test_false
|
||||
\
|
||||
\ "invalid long number with an even remainder"
|
||||
\ ( "1 2345 6789 1234 5678 9012" luhn ) test_false
|
||||
\
|
||||
\ "invalid long number with a remainder divisible by 5"
|
||||
\ ( "1 2345 6789 1234 5678 9013" luhn ) test_false
|
||||
\
|
||||
\ "valid number with an even number of digits"
|
||||
\ ( "095 245 88" luhn ) test_true
|
||||
\
|
||||
\ "valid number with an odd number of spaces"
|
||||
\ ( "234 567 891 234" luhn ) test_true
|
||||
\
|
||||
\ "valid strings with a non-digit added at the end become invalid"
|
||||
\ ( "059a" luhn ) test_false
|
||||
\
|
||||
\ "valid strings with punctuation included become invalid"
|
||||
\ ( "055-444-285" luhn ) test_false
|
||||
\
|
||||
\ "valid strings with symbols included become invalid"
|
||||
\ ( "055# 444$ 285" luhn ) test_false
|
||||
\
|
||||
\ "single zero with space is invalid"
|
||||
\ ( " 0" luhn ) test_false
|
||||
\
|
||||
\ "more than a single zero is valid"
|
||||
\ ( "0000 0" luhn ) test_true
|
||||
\
|
||||
\ "input digit 9 is correctly converted to output digit 9"
|
||||
\ ( "091" luhn ) test_true
|
||||
\
|
||||
\ "very long input is valid"
|
||||
\ ( "9999999999 9999999999 9999999999 9999999999" luhn ) test_true
|
||||
\
|
||||
\ "valid luhn with an odd number of digits and non zero first digit"
|
||||
\ ( "109" luhn ) test_true
|
||||
\
|
||||
\ "using ascii value for non-doubled non-digit isn't allowed"
|
||||
\ ( "055b 444 285" luhn ) test_false
|
||||
\
|
||||
\ "using ascii value for doubled non-digit isn't allowed"
|
||||
\ ( "9" luhn ) test_false
|
||||
\
|
||||
\ "non-numeric, non-space char in the middle with a sum that's divisible by 10 isn't allowed"
|
||||
\ ( "59%59" luhn ) test_false
|
||||
|
||||
bye
|
||||
3
exercises/practice/luhn/luhn.8th
Normal file
3
exercises/practice/luhn/luhn.8th
Normal file
@@ -0,0 +1,3 @@
|
||||
: luhn \ s -- T
|
||||
|
||||
;
|
||||
53
exercises/practice/luhn/test-words.8th
Normal file
53
exercises/practice/luhn/test-words.8th
Normal file
@@ -0,0 +1,53 @@
|
||||
needs console/loaded
|
||||
|
||||
: isword? \ x -- x f
|
||||
dup >kind ns:w n:=
|
||||
;
|
||||
|
||||
: test_eq \ s x w -- | s w x --
|
||||
isword? !if swap then
|
||||
a:new swap 0 swap a:! 0 a:@ nip w:exec
|
||||
n:= if
|
||||
con:green con:onBlack . space " ... OK" . con:white con:onBlack cr
|
||||
else
|
||||
con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr
|
||||
then
|
||||
;
|
||||
|
||||
: test_eqs \ s x w -- | s w x --
|
||||
isword? !if swap then
|
||||
a:new swap 0 swap a:! 0 a:@ nip w:exec
|
||||
s:= if
|
||||
con:green con:onBlack . space " ... OK" . con:white con:onBlack cr
|
||||
else
|
||||
con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr
|
||||
then
|
||||
;
|
||||
|
||||
: test_true \ s w --
|
||||
a:new swap 0 swap a:! 0 a:@ nip w:exec
|
||||
if
|
||||
con:green con:onBlack . space " ... OK" . con:white con:onBlack cr
|
||||
else
|
||||
con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr
|
||||
then
|
||||
;
|
||||
|
||||
: test_false \ s w --
|
||||
a:new swap 0 swap a:! 0 a:@ nip w:exec
|
||||
!if
|
||||
con:green con:onBlack . space " ... OK" . con:white con:onBlack cr
|
||||
else
|
||||
con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr
|
||||
then
|
||||
;
|
||||
|
||||
: test_null \ s w --
|
||||
a:new swap 0 swap a:! 0 a:@ nip w:exec
|
||||
null? if
|
||||
drop con:green con:onBlack . space " ... OK" . con:white con:onBlack cr
|
||||
else
|
||||
drop con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr
|
||||
then
|
||||
;
|
||||
|
||||
1
exercises/practice/luhn/tester.bat
Normal file
1
exercises/practice/luhn/tester.bat
Normal file
@@ -0,0 +1 @@
|
||||
8th -f test-words.8th -f luhn.8th -f luhn-tests.8th
|
||||
1
exercises/practice/luhn/tester.sh
Normal file
1
exercises/practice/luhn/tester.sh
Normal file
@@ -0,0 +1 @@
|
||||
8th -f test-words.8th -f luhn.8th -f luhn-tests.8th
|
||||
Reference in New Issue
Block a user