diff options
| author | mryouse | 2022-08-02 02:16:38 +0000 |
|---|---|---|
| committer | mryouse | 2022-08-02 02:16:38 +0000 |
| commit | ee509e05746731b12afe64bfe34284b119f6b4ae (patch) | |
| tree | 3a7e2e2ea668a99ab979e5852eedb661d9723085 /rosetta/luhn.neb | |
| parent | 7300580eb3aacfe1b67918fb20259e3ec26559c2 (diff) | |
exercises
Diffstat (limited to 'rosetta/luhn.neb')
| -rw-r--r-- | rosetta/luhn.neb | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/rosetta/luhn.neb b/rosetta/luhn.neb new file mode 100644 index 0000000..ac06e17 --- /dev/null +++ b/rosetta/luhn.neb @@ -0,0 +1,73 @@ +(func odd-elems (lst) + (odd-elems lst (list))) + +(func odd-elems (lst acc) + (if (eq? 0 (length lst)) + acc + (odd-elems (rest (rest lst)) (append acc (first lst))))) + +(func even-elems (lst) + (even-elems lst (list))) + +(func even-elems (lst acc) + (if (>= 1 (length lst)) + acc + (even-elems (rest (rest lst)) (append acc (first (rest lst)))))) + +(func luhn? (num) + ;; algo: + ;; with digits reversed, sum odd digits + ;; for all even digits: + ;; - double them + ;; - sum the digits (i.e. 16 -> 1 + 6 -> 7) + ;; - sum everything + ;; sum both values, and if the result ends in 0, it's valid + (def reverse-digits (reverse (->string num))) + ; sum the odd digits + (def s1 + (reduce + (lambda (x y) (+ x (string->int y))) + (odd-elems reverse-digits) 0)) + (def s2 + ; sum everything + (reduce (lambda (x y) (+ x y)) + ; sum each of the digits + (map (lambda (x) (apply + x)) + ; split the resulting numbers into digits + (map (lambda (x) (map string->int (split (->string x)))) + ; double the even digits + (map (lambda (x) (* 2 (string->int x))) + (even-elems reverse-digits)))) 0)) + (int? (/ (+ s1 s2) 10))) + +(func base36-to-base10 (value :string) + (base36-to-base10 (ord value))) + +(func base36-to-base10 (value :int) + (if (< value 32) + (+ 9 value) + (base36-to-base10 (- value 32)))) + +(func isin? (value) + ;; algo: + ;; - must be 12 digits + ;; - first 2 must be letters + ;; - last must be a number + ;; - interpret all values as base 32 + ;; - replace them as if replacing characters in a string + ;; - run luhn + (def digits (split "0123456789")) + (and + (eq? 12 (length value)) + (not (in? (first value) digits)) + (not (in? (first (rest value)) digits)) + (in? (last value) digits) + (luhn? (string->int + (apply concat + (reduce + (lambda (acc val) + (append acc + (->string (try + (string->int val) + (base36-to-base10 val))))) + (split value) (list))))))) |
