This commit is contained in:
Bruce Axtens
2022-11-23 22:14:41 +08:00
parent d60cb9c82c
commit 3007540e6c
9 changed files with 331 additions and 28 deletions

View File

@@ -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"
]
}

View 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.

View 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"
}

View 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 ;

View 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

View File

@@ -0,0 +1,3 @@
: luhn \ s -- T
;

View 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
;

View File

@@ -0,0 +1 @@
8th -f test-words.8th -f luhn.8th -f luhn-tests.8th

View File

@@ -0,0 +1 @@
8th -f test-words.8th -f luhn.8th -f luhn-tests.8th