 # rootulp's solution

## to Luhn in the Go Track

Published at Feb 28 2021 · 0 comments
Instructions
Test suite
Solution

Given a number determine whether or not it is valid per the Luhn formula.

The Luhn algorithm is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers and Canadian Social Insurance Numbers.

The task is to check if a given string is valid.

## Validating a Number

Strings of length 1 or less are not valid. Spaces are allowed in the input, but they should be stripped before checking. All other non-digit characters are disallowed.

## Example 1: valid credit card number

``````4539 1488 0343 6467
``````

The first step of the Luhn algorithm is to double every second digit, starting from the right. We will be doubling

``````4_3_ 1_8_ 0_4_ 6_6_
``````

If doubling the number results in a number greater than 9 then subtract 9 from the product. The results of our doubling:

``````8569 2478 0383 3437
``````

Then sum all of the digits:

``````8+5+6+9+2+4+7+8+0+3+8+3+3+4+3+7 = 80
``````

If the sum is evenly divisible by 10, then the number is valid. This number is valid!

## Example 2: invalid credit card number

``````8273 1232 7352 0569
``````

Double the second digits, starting from the right

``````7253 2262 5312 0539
``````

Sum the digits

``````7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57
``````

57 is not evenly divisible by 10, so this number is not valid.

## Coding the solution

Look for a stub file having the name luhn.go and place your solution code in that file.

## Running the tests

To run the tests run the command `go test` from within the exercise directory.

If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem` flags:

``````go test -v --bench . --benchmem
``````

Keep in mind that each reviewer will run benchmarks on a different machine, with different specs, so the results from these benchmark tests may vary.

## Further information

For more detailed information about the Go track, including how to get help if you're having trouble, please visit the exercism.io Go language page.

## Source

The Luhn Algorithm on Wikipedia http://en.wikipedia.org/wiki/Luhn_algorithm

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### cases_test.go

``````package luhn

// Source: exercism/problem-specifications
// Commit: f375a46 luhn: Update non-ASCII test case
// Problem Specifications Version: 1.6.1

var testCases = []struct {
description string
input       string
ok          bool
}{
{
"single digit strings can not be valid",
"1",
false,
},
{
"a single zero is invalid",
"0",
false,
},
{
"a simple valid SIN that remains valid if reversed",
"059",
true,
},
{
"a simple valid SIN that becomes invalid if reversed",
"59",
true,
},
{
"055 444 285",
true,
},
{
"055 444 286",
false,
},
{
"invalid credit card",
"8273 1232 7352 0569",
false,
},
{
"valid number with an even number of digits",
"095 245 88",
true,
},
{
"valid number with an odd number of spaces",
"234 567 891 234",
true,
},
{
"valid strings with a non-digit added at the end become invalid",
"059a",
false,
},
{
"valid strings with punctuation included become invalid",
"055-444-285",
false,
},
{
"valid strings with symbols included become invalid",
"055# 444\$ 285",
false,
},
{
"single zero with space is invalid",
" 0",
false,
},
{
"more than a single zero is valid",
"0000 0",
true,
},
{
"input digit 9 is correctly converted to output digit 9",
"091",
true,
},
{
"using ascii value for non-doubled non-digit isn't allowed",
"055b 444 285",
false,
},
{
"using ascii value for doubled non-digit isn't allowed",
":9",
false,
},
}``````

### luhn_test.go

``````package luhn

import "testing"

func TestValid(t *testing.T) {
for _, test := range testCases {
if ok := Valid(test.input); ok != test.ok {
t.Fatalf("Valid(%s): %s\n\t Expected: %t\n\t Got: %t", test.input, test.description, test.ok, ok)
}
}
}

func BenchmarkValid(b *testing.B) {
for i := 0; i < b.N; i++ {
Valid("2323 2005 7766 3554")
}
}``````
``````package luhn

import (
"errors"
"strconv"
"strings"
)

// Valid returns whether the provided string represents a number that satisfies the Luhn algorithm.
func Valid(s string) bool {
s = strings.ReplaceAll(s, " ", "")
if len(s) <= 1 {
return false
}
checkDigit, err := checkSum(s)

if err != nil {
return false
}

return checkDigit%10 == 0
}

// checkSum returns the Luhn check sum of the provided string.
func checkSum(s string) (int, error) {
sum := 0
for i, v := range reverse(s) {
digit, err := strconv.Atoi(string(v))

if err != nil {
// stop if we failed to convert this digit
return 0, errors.New("Invalid digit")
}

if (i % 2) == 0 {
// if this is an even indexed digit, add it to the sum directly
sum += digit
} else {
// double the digit and subtract 9 if it surpasses 9
product := digit * 2
if product > 9 {
product -= 9
}
sum += product
}
}
return sum, nil
}

// reverse returns a string with characters in reversed order.
func reverse(s string) string {
chars := strings.Split(s, "")
result := make([]string, len(s))

for i := len(chars) - 1; i >= 0; i-- {
result = append(result, chars[i])
}
return strings.Join(result, "")
}``````