aboutsummaryrefslogtreecommitdiff
path: root/rosetta/luhn.neb
diff options
context:
space:
mode:
authormryouse2022-08-02 02:16:38 +0000
committermryouse2022-08-02 02:16:38 +0000
commitee509e05746731b12afe64bfe34284b119f6b4ae (patch)
tree3a7e2e2ea668a99ab979e5852eedb661d9723085 /rosetta/luhn.neb
parent7300580eb3aacfe1b67918fb20259e3ec26559c2 (diff)
exercises
Diffstat (limited to 'rosetta/luhn.neb')
-rw-r--r--rosetta/luhn.neb73
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)))))))