blob: ac06e17cacd8369a59b98c19bac6401b5d9afa1f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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)))))))
|