Skip to content

Instantly share code, notes, and snippets.

@iboss-ptk
Last active November 27, 2022 04:10
Show Gist options
  • Save iboss-ptk/d1b4b6df006a9dac8521f02eaf4468c7 to your computer and use it in GitHub Desktop.
Save iboss-ptk/d1b4b6df006a9dac8521f02eaf4468c7 to your computer and use it in GitHub Desktop.
#include <cs50.h>
#include <stdio.h>
#include <math.h>
long exp10(int exponent);
long get_digit(long cc_num, int pos);
bool has_exact_digit(long cc_num, int digit);
string check_credit_card_number(long cc_num);
int main(void)
{
long cc_num = get_long("Number: ");
printf("%s\n", check_credit_card_number(cc_num));
}
string check_credit_card_number(long cc_num)
{
// validate checksum with Luhn’s Algorithm
long checksum = 0;
int digit_count;
// pos starts at 0, which corresponded to right-most digit
// loop while 10^pos < cc_num
for (int pos = 0; exp10(pos) < cc_num; pos++)
{
long digit = get_digit(cc_num, pos);
// every other digit, starting with the number’s second-to-last digit
// we need to x2 and sum all digit.
// when pos starts with 0 from last. that means said condition are odd pos
bool odd_pos = pos % 2 == 1;
if (odd_pos)
{
long doubled_digit = digit * 2;
if (doubled_digit >= 10)
{
long fst_digit = doubled_digit / 10;
long snd_digit = doubled_digit % 10;
checksum += fst_digit + snd_digit;
}
else
{
checksum += doubled_digit;
}
}
else
{
checksum += digit;
}
// at last round of the loop, pos + 1 will determine digit count
// since pos starts at 0 = 1st digit
digit_count = pos + 1;
}
// valid only last checksum digit is 0
if (checksum % 10 != 0)
{
return "INVALID";
}
long first_digit = cc_num / exp10(digit_count - 1);
long first_two_digits = cc_num / exp10(digit_count - 2);
// AMEX starts with 34, 37, 15-digit numbers
if ((first_two_digits == 34 || first_two_digits == 37) && has_exact_digit(cc_num, 15))
{
return "AMEX";
}
// MASTERCARD starts with 51, 52, 53, 54, or 55, 16-digit numbers
if (first_two_digits >= 51 && first_two_digits <= 55 && has_exact_digit(cc_num, 16))
{
return "MASTERCARD";
}
// VISA starts with 4, 13- and 16-digit numbers.
if (first_digit == 4 && (has_exact_digit(cc_num, 13) || has_exact_digit(cc_num, 16)))
{
return "VISA";
}
// The rest are invalid
return "INVALID";
}
long exp10(int exponent)
{
return pow(10, (double)exponent);
}
// getting digit of a certain position
// for example: `1234`, digit at pos=1 -> 3
// 1234 % 10^(1+1) / 10^1
// => 1234 % 100 / 10
// => 34 / 10
// => 3 (dividing long yields long)
long get_digit(long cc_num, int pos)
{
return (cc_num % exp10(pos + 1)) / exp10(pos);
}
bool has_exact_digit(long cc_num, int digit)
{
return cc_num >= exp10(digit - 1) && cc_num < exp10(digit);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment