caveat
This programming challenge is found at
or
and it will be presented as is:
the challenge
Cellulant has implemented a custom, card number verification system to ensure detection and blocking of fake cards. A scratch card consists of 4 sets of 5 digits (20 digits in total) e.g. [10006-12342-00081-99993] which are printed separated by a space or a dash.
Each set of 5 digits consists of two parts, the first 4 digits (the number) and a 5th digit (the checksum) The formula dictates that each of the sets must be validated as follows: The first 4 digits, e.g 1234, as decimal numbers be converted into an octal number (base 8) i.e. 23228. This octal number is then processed to generate the checksum, as follows:
- Add all digits to each other to get a new number “X”
- If “X” is more than 1 digit, repeat step (1) until you have a single digit. “Y”
- Append “Y” to the end of the original decimal number e.g. 1234 2
For Example:
Given the set “10006”
Convert 1000 to octal =>1750>
1+7+5+0=15
1+5=68
Valid number is 10006 so;
return (TRUE)Given the set “99998”
Convert 9999 to octal => 23417
2+3+4+1+7=21
2+1=3
Valid number is 99993 so;
return (FALSE)Create a Java, Java-Script or PHP script with the function that will receive a string value (scratch card number) and return boolean TRUE or FALSE, on whether the card number is valid, as shown below
You should use as many other functions as you deem necessary within your code.
really neat solution
This solution was contributed by Filipe Ramalho
- We get the modulo operation of first-four with 7
- Then we subtract the result from the checksum
- Next we get the modulo operation of the result above with 7
- Then we check if it is equal to 0
Better explained by Filipe Ramalho:
For 9999|8
- 9999 % 7 = 3 //First you modulo through 7
- 8 - 3 = 5 //Then you subtract the result from the checksum.
- 5 % 7 = 5 //Then you modulo that through 7.
The end result isn't 0, so the digit isn't valid
(defn is-valid?
[number]
(let [first-four (quot number 10)
check-sum (rem number 10)]
(-> first-four
(mod 7)
(- check-sum)
(mod 7)
(= 0))))
user> (is-valid-modified? 10006)
true
user> (is-valid-modified? 99993)
true
user> (is-valid-modified? 99998)
false
user> (is-valid-modified? 12342)
true
user> (is-valid-modified? 11697)
true
(defn validate-scratch-card [card-number]
(let [f (comp is-valid? #(Integer/parseInt %))]
(->> (string/split card-number #"(-|\s)")
(map f)
(every? true?))))
user> (validate-scratch-card "10006 12342 00081 99998")
false
user> (validate-scratch-card "10006 12342 00081 99993")
true
It is an elegant solution.
the old solution
Instead of using any of the proposed languages above, I shall use Clojure.
validate-scratch-card
is a function which takes a string which may look like:
- "
10006-12342-00081-99993
" - "
10006 12342 00081 99993
"
It would be nice to split the argument based on the presence of a space or a hyphen so that I could work on each substring:
;; has hyphen
user> (clojure.string/split "10006-12342-00081-99993" #("-|\s)")
;; ["10006" "12342" "00081" "99993"]
;; has spaces
user> (clojure.string/split "10006 12342 00081 99993" #"(-|\s)")
;; ["10006" "12342" "00081" "99993"]
Next item on the agenda is to parse each individual substring to Integer
via the Java method Integer/parseInt
.
user> (Integer/parseInt "10006")
;; 10006
map
can be used to parse each individual substring
user> (map #(Integer/parseInt %) "10006 12342 00081 99993")
;; 10006
Each Integer can be checked for validity based on the rules above.
Each Integer has 2 parts:
- first four digits (the number)
- the fifth digit (the checksum)
user> (quot 10006 10)
;; 1000 first four digits (the number)
user> (rem 10006 10)
;; 6 fifth digit (checksum)
Next is to convert the first four digits to octal.
This will be achieved by creating a base converter
(defn- to-digits [number base]
(loop [n number
digits '()]
(if (pos? n)
(recur (quot n base)
(conj digits (mod n base)))
digits)))
(defn to-octal [number]
"returns a list of octal numbers"
(to-digits number 8))
user> (to-octal 1000)
;; (1 7 5 0)
Subsequent step is to sum up each of the generated numbers.
But before that, a function that takes two octal numbers and sums them up is needed.
(defn add-two-octal [x y]
"add two octal numbers"
(let [a (Integer/parseInt (str x) 8)
b (Integer/parseInt (str y) 8)]
(-> (+ a b)
Integer/toOctalString
Integer/parseInt)))
user> (add-two-octal 3 6)
;; 11
This add-two-octal
function can then be used to sum up a list of octal numbers together as follows:
user> (reduce #(add-two-octal %1 %2)
(to-octal 1000))
;; 15
user> (reduce #(add-two-octal %1 %2)
'(1 7 5 0))
;; 15
Although the addition works fine it doesn't satisfy the requirement that the result of the sum should be a single digit.
If a single digit is the result of the sum then the single digit should be returned else the summation should be done again.
Also there is need for a function to separate the new summation if it happens to be two digits.
(defn separate [number]
"a utility function to separate digits"
(loop [n number
digits '()]
(if (zero? n)
digits
(recur (quot n 10)
(conj digits (rem n 10))))))
(defn sum-octal [number]
(let [sum (reduce #(add-two-octal %1 %2)
(to-octal number))]
(if (zero? (quot sum 10))
sum
(apply add-two-octal (separate sum)))))
user> (sum-octal 1000)
;; 6
Next a function that takes a number and checks for validity can be written as follows:
(defn is-valid? [number]
(let [first-four (quot number 10)
check-sum (rem number 10)
verify (sum-octal first-four)]
(= verify check-sum)))
user> (is-valid? 10006)
;; true
user> (is-valid? 99998)
;; false
The is-valid?
function and the #(Integer/parseInt %)
can be composed together
(comp is-valid? #(Integer/parseInt %))
user> ((comp is-valid? #(Integer/parseInt %)) "10006")
;; true
Finally, the validate-scratch-card
function will shape up as follows
(defn validate-scratch-card [card-number]
(let [f (comp is-valid? #(Integer/parseInt %))]
(->> (string/split card-number #"(-|\s)")
(map f)
(every? true?))))
user> (validate-scratch-card "10006 12342 00081 99993")
;; true
user> (validate-scratch-card "10006 12342 00081 99998")
;; false
Top comments (4)
You can also use modulo. You calculate the iterative digit sum with number % 9. If 0 comes out the sum is 9.
sjsu.edu/faculty/watkins/Digitsum0...
I'm not familiar with Clojure so I can't give you a code example of Clojure. But here in pseudocode
You can also consider 0 and 9 equal and spare the conversion from 0 to 9:
Or you could modulo the difference through 9. If it's 0 the result is 0, if it's 9 the result is also 0.
So in one line it would look like this
Thank you for contribution.
I have really tried my best to understand, but have failed.
Could you use examples?
Actually I had an error. You shouldn't convert the digit. And instead modulo through 7.
For 9999|8
The end result isn't 0, so the digit isn't valid
For 1234|2
The end result is 0, so the digit is valid
For 1169|7
1.1169 % 7 = 0 //If you modulo through 7, when the digit sum is 7 instead 0 comes out, so you can consider 0=7.
The end result is 0, so the digit is valid
Updated code
You can also consider 0 and 7 equal and spare the conversion from 0 to 7:
Or you could modulo the difference through 7. The difference must be either 7 or 0 and both have the same result for modulo 7.
So in one line it would look like this
Thank you for clarifying. I have now understood.
It is actually a really neat solution it basically reduces the code to just two functions.
I have learnt something, thank you.