(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)))))))