Description
The Verhoeff algorithm is a checksum formula for error detection developed by the Dutch mathematician Jacobus Verhoeff and first published in 1969. It was the first decimal check digit algorithm which detects all single-digit errors, and all transposition errors involving two adjacent digits, which was at the time thought impossible with such a code.

As the workings of the algorithm are clearly described in the linked Wikipedia article they will not be repeated here.

Task

Write routines, methods, procedures etc. in your language to generate a Verhoeff checksum digit for non-negative integers of any length and to validate the result. A combined routine is also acceptable.

The more mathematically minded may prefer to generate the 3 tables required from the description provided rather than to hard-code them.

Write your routines in such a way that they can optionally display digit by digit calculations as in the Wikipedia example.

Use your routines to calculate check digits for the integers: 236, 12345 and 123456789012 and then validate them. Also attempt to validate the same integers if the check digits in all cases were 9 rather than what they actually are.

Display digit by digit calculations for the first two integers but not for the third.

Related task

   Damm algorithm


with javascript_semantics
sequence d = {tagset(9,0)},
         inv = tagset(9,0),
         p = {tagset(9,0)}
for i=1 to 4 do d = append(d,extract(d[$],{2,3,4,5,1,7,8,9,10,6})) end for
for i=5 to 8 do d = append(d,reverse(d[-4])) end for
                d = append(d,reverse(d[1]))
inv[2..5] = reverse(inv[2..5])
for i=1 to 7 do p = append(p,extract(p[$],{2,6,8,7,3,9,4,1,10,5})) end for

-- alternatively, if you prefer:
--constant d = {{0,1,2,3,4,5,6,7,8,9},
--              {1,2,3,4,0,6,7,8,9,5},
--              {2,3,4,0,1,7,8,9,5,6},
--              {3,4,0,1,2,8,9,5,6,7},
--              {4,0,1,2,3,9,5,6,7,8},
--              {5,9,8,7,6,0,4,3,2,1},
--              {6,5,9,8,7,1,0,4,3,2},
--              {7,6,5,9,8,2,1,0,4,3},
--              {8,7,6,5,9,3,2,1,0,4},
--              {9,8,7,6,5,4,3,2,1,0}},
--        inv = {0,4,3,2,1,5,6,7,8,9},
--         p = {{0,1,2,3,4,5,6,7,8,9},
--              {1,5,7,6,2,8,3,0,9,4},
--              {5,8,0,3,7,9,6,1,4,2},
--              {8,9,1,6,0,4,3,5,2,7},
--              {9,4,5,3,1,2,6,8,7,0},
--              {4,2,8,6,5,7,3,9,0,1},
--              {2,7,9,3,8,0,6,4,1,5},
--              {7,0,4,6,9,1,3,2,5,8}}

function verhoeff(string n, bool validate=false, show_workings=false)
    string {s,t} = iff(validate?{n,"Validation"}:{n&'0',"Check digit"})
    if show_workings then
        printf(1,"%s calculations for `%s`:\n", {t, n})
        printf(1," i  ni  p(i,ni)  c\n")
        printf(1,"------------------\n")
    end if
    integer c = 0
    for i=1 to length(s) do
        integer ni = s[-i]-'0',
                pi = p[remainder(i-1,8)+1][ni+1]
        c = d[c+1][pi+1]
        if show_workings then
            printf(1,"%2d  %d      %d     %d\n", {i-1, ni, pi, c})
        end if
    end for
    integer ch = inv[c+1]+'0'
    string r = iff(validate?iff(c=0?"":"in")&"correct"
                           :"`"&ch&"`")
    printf(1,"The %s for `%s` is %s\n\n",{lower(t),n,r})
    return ch
end function

constant tests = {"236", "12345", "123456789012"}
for i=1 to length(tests) do
    bool show_workings = (i<=2)
    integer ch = verhoeff(tests[i],false,show_workings)
    assert(verhoeff(tests[i]&ch,true,show_workings)=='0')
    assert(verhoeff(tests[i]&'9',true,show_workings)!='0')
end for
