###
### CREDIT CARD SUBROUTINES
###
# Idle hands are the optimizer's workshop.
# Read this subroutine from right to left, $_[0] is the input string.
# split // means split it up into a list of individual digits, so 'X1234' becomes ('X', '1', '2', '3', '4')
# reverse it to ('4', '3', '2', '1', 'X')
# grep through only the digits to make ('4', '3', '2', '1')
# map the odd indexes to their luhn doubles (see below) to make ('4', '6', '2', '2')
# join them with plusses to form '4+6+2+2'
# eval that string to get 14
# A brief explanation of LUHN:
# A fuller explanation can be found at http://utopia.knoware.nl/users/eprebel/Numbers/Luhn.html
# Consider the numbers in the credit card number as a string of digits. Reverse the string, and index the
# string of digits starting with zero. Double the odd-numbered digits and sum the digits of the doubled
# digit (e.g. 5 * 2 = 10 => 1 + 0 => 1). Sum all these digits up to form the LUHN sum, which must be
# mod 10 to be a sane credit card number.
sub luhn_sum {
my $odd = 0;
return eval join '+', map {tr/1-8/24681357/ if $odd; $odd ^= 1; $_} grep /\d/, reverse split //, $_[0];
}