Credit Card Checker Challenge Project (JavaScript)

Here is my solution to the Credit Card Checker Challenge Project. The solution includes a function that accepts a string or numbers and converts either into an array of numbers like the initially provided arrays. The solution also includes a function that converts an invalid card number to a valid card number by changing the last digit (“check digit”) of the invalid card number. The function preserves the original invalid card number and creates and returns a new valid card number. Best Regards, Bear.

I have a question about the final answer of the credit card checker solution -

Can anyone explain what the repeated code of if
(companies.indexOf(‘Amex’) ===-1 {

companies.push('Amex); , does?

(full code of the switch statement is here)
switch (invalidBatch[i][0]) {
case 3:
if (companies.indexOf(‘Amex’) === -1) {
companies.push(‘Amex’);
}
break
case 4:
if (companies.indexOf(‘Visa’) === -1) {
companies.push(‘Visa’);
}
break
case 5:
if (companies.indexOf(‘Mastercard’) === -1) {
companies.push(‘Mastercard’);
}
break
case 6:
if (companies.indexOf(‘Discover’) === -1) {
companies.push(‘Discover’);
}

I tried it out and it worked to get each credit card to show up only once, but I don’t understand why it worked.

Here is the code I wrote, which listed all the credit card companies, but repeated the names for each card.

    switch(invalidCards[i][0]) {
        case 3:
            companies.push('Amex')        
            break;
        case 4:
            companies.push('Visa')        
            break;
        case 5:
            companies.push('Mastercard')           
            break;
        case 6:
            companies.push('Discover')          
            break;
        default:
            console.log('Company not found');
    }
}
return companies;

Can anyone explain?

Hey bud.

case 3:
if (companies.indexOf(‘Amex’) === -1) {
companies.push(‘Amex’);
}

I think when you use the above code, .indexOf() returns -1 if it doesn’t find an instance of what you are searching for.

So if it doesn’t find an instance of ‘Amex’ while searching through the companies array. It will return -1 and proceed to push ‘Amex’ into the companies array.

So once the companies array contains an instance of ‘Amex’, the same if statement would return the index number of ‘Amex’ instead of the ‘-1’ and it wouldn’t carry on with the code. (Would not push another copy of ‘Amex’.

Hope I worded that clearly and it helps.

Can someone be so kind as to give me a code review, please? Also, post to this thread any code you want me to review for you as well. Here is a link to my repo on GitHub:
https://github.com/sagordon-dev/credit-card-checker/blob/master/main

Hey guys,

Here’s a link to my attempt.

GitHub repo

I added the convert string to array and convert invalid numbers to valid.

Think it would have been good to change the first function (validateCred()) so it was reusable by the converter function at the end. And add a middle man function for the findInvalidCards() function to still use validateCred(). But I wanted to code them all out separately for now.

Any advice appreciated

Heya,

That link comes up with a 404 for me

Oh sorry about that, it should open fine now… Your code is much more well documented than mine, this is something I should work on especially for a code review. Thought your code looked great!

Here is the proper link:

Also creating a Codebyte for it as well:

// All valid credit card numbers const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]; const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]; const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]; const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]; const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]; // All invalid credit card numbers const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]; const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]; const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]; const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]; const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]; // Can be either valid or invalid const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]; const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]; const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]; const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]; const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]; // An array of all the arrays above const batch = [ valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5, ]; // Add your functions below: const validateCred = (array) => { let sum = 0; for (let index = array.length - 1; index >= 0; index--) { let element = array[index]; if (index % 2 === 0) { element *= 2; } if (element > 9) { element -= 9; } sum += element; } if (sum % 10 === 0) { return true; } else { return false; } }; const findInvalidCards = (array) => { const invalidCards = []; for (let index = 0; index < array.length; index++) { const element = array[index]; if (validateCred(element) === false) { invalidCards.push(element); } } return invalidCards; }; const idIvalidCardCompanies = (array) => { let companies = []; array.forEach((element) => { if (element[0] == 3 && !companies.includes("Amex")) { companies.push("Amex"); } else if (element[0] == 4 && !companies.includes("Visa")) { companies.push("Visa"); } else if (element[0] == 5 && !companies.includes("Mastercard")) { companies.push("Mastercard"); } else if (element[0] == 6 && !companies.includes("Discover")) { companies.push("Discover"); } else { console.log("Company not found"); } }); return companies; }; console.log(idIvalidCardCompanies(batch));
1 Like

What do you think?

Looking good bud!

Yeah, I’ve been putting a lot of comments in. Mainly for myself so I don’t get lost lol.

Your first func is way better to read then mine with ‘if (index % 2 === 0)’, instead of my ■■■■■■ counter.

Thanks for checking it out :+1:

My solution.

Hi all!

I´m share with you my code for this project you can use it as way to acomplish the tasks. :slight_smile:

Here is my code:

For some reason, i’m not able to run my code in the project. Can you see if the code is okay or if there should be any fixing?

Having some trouble. This works as a Luhn algorithm for 9/10 of the provided test arrays, but does not work on valid3. Where’s my mistake? Too tired late in the day to spot it.

validateCred = (arr) => { for (i = arr.length - 1; i >= 0; i--) { if ((i % 2) == 0) { arr[i] *= 2 } if (arr[i] > 9) { arr[i] -= 9 } } let sum = arr.reduce((a, b) => a + b, 0) return sum % 10 === 0; }

Finally the penny has dropped. This was a fantastic exercise to implement everything that I learnt in the Javascript modules. Feel free to checkout my code :smiley:

Hi Everyone, this is my solution. Enjoy and don’t hesitate to comment!

Thanks, Dirk.

Hi all,

Could anyone please give me feedback on my solution? I’m new to JavaScript and this took me a very long time to figure out. If there are things I could improve on I’d be very happy to hear them.

I think it works to get the correct answer, but it doesn’t have all the functionality of the codecademy solution.

Thanks,
Ben

I had the same problem and I spent hours trying but finally found the answer.

 if ((i % 2) == 0) {}

should be this

if ((arr.length - 1 - i) % 2 === 1) {}

The arr.length - 1 - i is making us iterate correctly and the % 2 === 1 is making us add every other starting from the second element instead of the first.
If you want to debug the code you should log to the console this in the first line of the for loop:

console.log((arr.length - 1 - i) % 2)

Try logging the values of the array and you’ll see what I mean.

Not sure if I’ve brought this up before; it is something to consider…

const print = console.log;
const iter = function (arr) {
  const y = arr.slice()
  const n = y.length
  for (let x = n % 2; x < n; x += 2) {
    y[x] *= 2
  }
  return y
}
const even = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
//     [ 10, 5, 6, 5, 14, 6, 12, 7, 12, 8, 14, 5, 2, 4, 6, 9 ]
print (iter(even))
const odd = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
//      [ 3, 14, 1, 12, 1, 4, 0, 2, 9, 18, 8, 10, 2, 6, 6 ]
print (iter(odd))

This saves computing inside the loop. We only need to know which element to start from, and then step by 2. We use a slice of the original array so it is not compromised by our mutations.

We see above that the correct elements are getting doubled in value, and the last element is unchanged.

All that is left to do now is sum the digits.

const digitSum = x => x.join('').split('').reduce((a, b) => +a + +b)

// prints 80
print (digitSum(iter(even)))
// prints 60
print (digitSum(iter(odd)))

When we put this all together, we get,

const isValid = function (arr) {
  # This combines all the numbers then separates them 
  # again as single digits and sums them up.
  # It is still a 'casting of the nines', in a sense.
  const digitSum = x => x.join('').split('').reduce((a, b) => +a + +b)
  const iter = function (y) {
    const n = y.length
    for (let x = n % 2; x < n; x += 2) {
      y[x] *= 2
    }
    return y
  }
  return ! (digitSum(iter(arr.slice())) % 10)
}
// prints true
print (isValid(even))
// prints true
print (isValid(odd))

Let’s put this into app form!

HTML
<!DOCTYPE html>
<html>
<head>
  <title>Credit Card Validator</title>
   <meta name="viewport" content="width=device-width,initial-scale=1" >
  <link href="style.css" rel="stylesheet">
</head>
<body>
  <h1>Credit Card Validator</h1>
  <form action="">
    <input id="nums" placeholder="Card digits only">
    <input type="submit" value="Validate">
    <input value="" disabled>
  </form>
  <script src="script.js"></script>
</body>
</html>
CSS
body {
  background: #000;
  color: #fff;
  padding: 25px;
  font-family: sans-serif;
  font-size: 100%;
}
h1 {
  font-size: smaller;
}
input[disabled] {
  font-variant: small-caps;
  color: white;
  background-color: black;
  border: none;
}
JavaScript
const isValid = function (arr) {
  if (! Array.isArray(arr)) throw Error(`Input (${arr}) is not an array.`)
  const digitSum = x => x.join('').split('').reduce((a, b) => +a + +b)
  const iter = function (y) {
    const n = y.length
    for (let x = n % 2; x < n; x += 2) {
      y[x] *= 2
    }
    return y
  }
  return ! (digitSum(iter(arr.slice())) % 10)
}
const form = document.querySelector("form")
const nums = document.querySelector("#nums")
const result = document.querySelector("input:nth-child(3)")
const handler = event => {
  event.preventDefault()
  result.value = isValid(nums.value.split('').map(x => +x)).toString()
}
form.onsubmit = handler

This is strictly plain Jane, but illustrates the implementation.