/*
Luhn tests of credit card numbers in Picat.
From http://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers
"""
The Luhn test is used by some credit card companies to distinguish
valid credit card numbers from what could be a random selection of digits.
Those companies using credit card numbers that can be validated by the
Luhn test have numbers that pass the following test:
1. Reverse the order of the digits in the number.
2. Take the first, third, ... and every other odd digit in the
reversed digits and sum them to form the partial sum s1
3. Taking the second, fourth ... and every other even digit in the
reversed digits:
1. Multiply each digit by two and sum the digits if the answer
is greater than nine to form partial sums for the even digits
2. Sum the partial sums of the even digits to form s2
1. If s1 + s2 ends in zero then the original number is in the form
of a valid credit card number as verified by the Luhn test.
For example, if the trail number is 49927398716:
Reverse the digits:
61789372994
Sum the odd digits:
6 + 7 + 9 + 7 + 9 + 4 = 42 = s1
The even digits:
1, 8, 3, 2, 9
Two times each even digit:
2, 16, 6, 4, 18
Sum the digits of each multiplication:
2, 7, 6, 4, 9
Sum the last:
2 + 7 + 6 + 4 + 9 = 28 = s2
s1 + s2 = 70 which ends in zero which means that 49927398716
passes the Luhn test
The task is to write a function/method/procedure/subroutine that will
validate a number with the Luhn test, and use it to validate the
following numbers:
49927398716
49927398717
1234567812345678
1234567812345670
"""
Model created by Hakan Kjellerstrand, hakank@gmail.com
See also my Picat page: http://www.hakank.org/picat/
*/
import util.
main => go.
go =>
Nums = ["49927398716","49927398717","1234567812345678","1234567812345670"],
foreach (N in Nums)
println([N, isluhn10(N)])
end,
nl.
%
% isluhn10(num) returns 1 is valid, else 0
%
% Assumption: input num is a string.
%
isluhn10(Num) = V =>
X = [I : I in Num.reverse()] ++ [""],
Digits = "0246813579",
M = new_map([(I.to_string()=Digits[I+1]) : I in 0..9]),
V1 = sum([X[I].to_integer() + M.get2(X[I+1].to_string(),0) : I in 1..2..Num.length]),
V := cond(V1 mod 10 == 0, 1, 0).
get2(M, Key, Default)=V =>
if M.has_key(Key) then V= M.get(Key).to_integer() else V=Default end.