How to resolve the algorithm Luhn test of credit card numbers step by step in the AppleScript programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Luhn test of credit card numbers step by step in the AppleScript programming language

Table of Contents

Problem Statement

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:

For example, if the trial number is 49927398716:

Write a function/method/procedure/subroutine that will validate a number with the Luhn test, and use it to validate the following numbers:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Luhn test of credit card numbers step by step in the AppleScript programming language

Source code in the applescript programming language

-- luhn :: String -> Bool
on luhn(s)
    -- True if the digit string represents
    -- a valid Luhn credit card number.
    
    script divMod10Sum
        on |λ|(a, x)
            a + x div 10 + x mod 10
        end |λ|
    end script
    
    0 = foldl(divMod10Sum, 0, ¬
        zipWith(my mul, ¬
            map(my int, reverse of (characters of s)), ¬
            cycle({1, 2}))) mod 10
end luhn


--------------------------- TEST ---------------------------
on run
    map(luhn, ¬
        {"49927398716", "49927398717", ¬
            "1234567812345678", "1234567812345670"})
    
    --> {true, false, false, true}
end run


---------------- REUSABLE GENERIC FUNCTIONS ----------------

-- cycle :: [a] -> Generator [a]
on cycle(xs)
    script
        property lng : 1 + (length of xs)
        property i : missing value
        on |λ|()
            if missing value is i then
                set i to 1
            else
                set nxt to (1 + i) mod lng
                if 0 = ((1 + i) mod lng) then
                    set i to 1
                else
                    set i to nxt
                end if
            end if
            return item i of xs
        end |λ|
    end script
end cycle

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- int :: String -> Int
on int(s)
    s as integer
end int

-- length :: [a] -> Int
on |length|(xs)
    set c to class of xs
    if list is c or string is c then
        length of xs
    else
        (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
    end if
end |length|

-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    -- The list obtained by applying f
    -- to each element of xs.
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min

-- mul (*) :: Num a => a -> a -> a
on mul(a, b)
    a * b
end mul

-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
    set c to class of xs
    if list is c then
        if 0 < n then
            items 1 thru min(n, length of xs) of xs
        else
            {}
        end if
    else if string is c then
        if 0 < n then
            text 1 thru min(n, length of xs) of xs
        else
            ""
        end if
    else if script is c then
        set ys to {}
        repeat with i from 1 to n
            set v to |λ|() of xs
            if missing value is v then
                return ys
            else
                set end of ys to v
            end if
        end repeat
        return ys
    else
        missing value
    end if
end take

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
    set lng to min(|length|(xs), |length|(ys))
    if 1 > lng then return {}
    set xs_ to take(lng, xs) -- Allow for non-finite
    set ys_ to take(lng, ys) -- generators like cycle etc
    set lst to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs_, item i of ys_)
        end repeat
        return lst
    end tell
end zipWith


on luhnTest(n)
    -- Accept only text input.
    if (n's class is not text) then return false
    -- Edit out any spaces or dashes.
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to {space, "-"}
    set n to n's text items
    set AppleScript's text item delimiters to ""
    set n to n as text
    set AppleScript's text item delimiters to astid
    -- Check that what's left is numeric.
    try
        n as number
    on error
        return false
    end try
    
    -- Do the calculation two digits at a time, starting at the end of the text and working back.
    set sum to 0
    repeat with i from ((count n) - 1) to 1 by -2
        set n2 to (text i thru (i + 1) of n) as integer
        tell n2 div 10 mod 10 * 2 to set sum to sum + it div 10 + it mod 10 + n2 mod 10
    end repeat
    -- If there's an odd digit left over, add that in too.
    if (i is 2) then set sum to sum + (character 1 of n)
    
    return (sum mod 10 is 0)
end luhnTest

-- Test code:
set testResults to {}
repeat with testNumber in {"49927398716", "49927398717", "1234567812345678", "1234567812345670"}
    set end of testResults to {testNumber:testNumber's contents, valid:luhnTest(testNumber)}
end repeat
return testResults


{{testNumber:"49927398716", valid:true}, {testNumber:"49927398717", valid:false}, {testNumber:"1234567812345678", valid:false}, {testNumber:"1234567812345670", valid:true}}


  

You may also check:How to resolve the algorithm Sorting algorithms/Comb sort step by step in the Delphi programming language
You may also check:How to resolve the algorithm N-smooth numbers step by step in the J programming language
You may also check:How to resolve the algorithm Arithmetic-geometric mean/Calculate Pi step by step in the Julia programming language
You may also check:How to resolve the algorithm Repeat a string step by step in the Dyalect programming language
You may also check:How to resolve the algorithm Hello world/Text step by step in the SkookumScript programming language