Last active
November 27, 2022 04:10
-
-
Save iboss-ptk/d1b4b6df006a9dac8521f02eaf4468c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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