The weekly challenge 290 - Task 2: Luhn’s Algorithm
1 #!/usr/bin/env perl 2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-290/#TASK2 3 # 4 # Task 2: Luhn’s Algorithm 5 # ======================== 6 # 7 # You are given a string $str containing digits (and possibly other characters 8 # which can be ignored). The last digit is the payload; consider it separately. 9 # Counting from the right, double the value of the first, third, etc. of the 10 # remaining digits. 11 # 12 # For each value now greater than 9, sum its digits. 13 # 14 # The correct check digit is that which, added to the sum of all values, would 15 # bring the total mod 10 to zero. 16 # 17 # Return true if and only if the payload is equal to the correct check digit. 18 # 19 # It was originally posted on reddit. 20 # 21 ## Example 1 22 ## 23 ## Input: "17893729974" 24 ## Output: true 25 ## 26 ## Payload is 4. 27 ## 28 ## Digits from the right: 29 ## 30 ## 7 * 2 = 14, sum = 5 31 ## 9 = 9 32 ## 9 * 2 = 18, sum = 9 33 ## 2 = 2 34 ## 7 * 2 = 14, sum = 5 35 ## 3 = 3 36 ## 9 * 2 = 18, sum = 9 37 ## 8 = 8 38 ## 7 * 2 = 14, sum = 5 39 ## 1 = 1 40 ## 41 ## Sum of all values = 56, so 4 must be added to bring the total mod 10 to 42 ## zero. The payload is indeed 4. 43 # 44 ## Example 2 45 ## 46 ## Input: "4137 8947 1175 5904" 47 ## Output: true 48 # 49 ## Example 3 50 ## 51 ## Input: "4137 8974 1175 5904" 52 ## Output: false 53 # 54 ############################################################ 55 ## 56 ## discussion 57 ## 58 ############################################################ 59 # 60 # First, we split the string into its characters, keep only 61 # the digits and reverse their order. We now put the first 62 # element into a $payload variable, the rest goes into an 63 # array @digits. Next, for the odd elements of the array, we 64 # double the value and sum the digits of that if bigger than 9. 65 # In the end, we add that to the sum so far. We then calculate 66 # the sum mod 10, substract that from 10 to find the correct 67 # payload. If the payload matches that, we return True, otherwise 68 # False. 69 70 use strict; 71 use warnings; 72 73 luhns_algorithm("17893729974"); 74 luhns_algorithm("4137 8947 1175 5904"); 75 luhns_algorithm("4137 8974 1175 5904"); 76 77 sub luhns_algorithm { 78 my $str = shift; 79 print "Input: $str\n"; 80 my ($payload, @digits) = reverse grep { /[0-9]/ } split //, $str; 81 my $odd = 1; 82 my $sum = 0; 83 foreach my $digit (@digits) { 84 if($odd) { 85 $digit *= 2; 86 if($digit > 9) { 87 my ($first, $second) = split //, $digit; 88 $digit = $first + $second; 89 } 90 $odd = 0; 91 } else { 92 $odd = 1; 93 } 94 $sum += $digit; 95 } 96 my $mod = $sum % 10; 97 my $correct = 10 - $mod; 98 if($payload == $correct) { 99 print "Output: True\n"; 100 } else { 101 print "Output: False\n"; 102 } 103 }