Проверка типа и срока действия кредитной карты с помощью алгоритма Луна на языке C (CS50)

Я беру CS50 Intro в CS. В этом задании нас просят создать программу, которая может определить, какой тип кредитной карты (AMEX, Visa, MasterCard) указан во входных данных (и действителен ли он). Действительность проверяется с помощью алгоритма Луна. Вот как работает алгоритм:

  1. Умножьте все остальные цифры на 2, начиная с предпоследней цифры номера, а затем сложите цифры этих продуктов вместе. (Мы не добавляем продукты вместе, а точнее цифры продуктов!)
  2. Добавьте сумму к сумме цифр, которые не были умножены на 2.
  3. Если последняя цифра суммы равна 0, число действительное!

Затем тип кредитной карты проверяется путем проверки первых нескольких цифр кредитной карты. Т.е. номера American Express начинаются с 34 или 37, VISA – с 4 и т. Д. Вот моя реализация:

#include <stdio.h>
#include <cs50.h>
#include <math.h>
#include <stdlib.h>

bool check_is_card_valid(long card);
int checksum(long card);
bool array_consists(const unsigned int arr[], int val, int arrlen);
string get_card_type(long card);
int get_nth_digit(long card, int digit);
int get_card_length(long card);

const unsigned int accepted_card_length[] = 
{
    15, // AMEX uses 15 digit numbers
    16, // MasterCard and VISA uses 16 digit numbers
    13  // VISA uses 13 digit numbers
};
const size_t acc_card_len = sizeof(accepted_card_length) / sizeof(*accepted_card_length);
const unsigned int AMEX_first_digits[] = {34, 37};
const size_t amex_digits_len = sizeof(AMEX_first_digits) / sizeof(*AMEX_first_digits);
const unsigned int MASTERCARD_first_digits[] = {51, 52, 53, 54, 55};
const size_t mc_digits_len = sizeof(MASTERCARD_first_digits) / sizeof(*MASTERCARD_first_digits);
const unsigned int VISA_first_digit = 4;


int main(void)
{
    long card_number = get_long("Card number: ");
    if (check_is_card_valid(card_number) == true)
    {
        printf("%sn", get_card_type(card_number));
    } 
    else
    {
        printf("INVALIDn");
    }
}

/*
    Luhn's algorithm. Starting from the right, multiply every other digit by 2 and add up the digits
    add this sum to the sum of the digits that were not multiplied by 2. 
*/

int checksum(long card)
{
    int checksum = 0;
    for (int i = 0; i < get_card_length(card); i++)
    {
        if (i % 2 == 0)
        {
            checksum += get_nth_digit(card, i);
        }
        else if (i % 2 == 1)
        {
            int num = get_nth_digit(card, i) * 2;
            if (num > 9)
            {
                num = get_nth_digit(num, 0) + get_nth_digit(num, 1);
            }
            checksum += num;
        }
    }
    return checksum;
}

bool array_consists(const unsigned int arr[], int val, int arrlen)
{
    for (int i = 0; i < arrlen; i++)
    {
        if (val == arr[i])
        {
            return true;
        }
    }
    return false;
}

// Luhn's algorithm states that if the last digit of the checksum is 0, it is valid
bool check_is_card_valid(long card)
{
    if (array_consists(accepted_card_length, get_card_length(card), acc_card_len) == true)
    {
        return checksum(card) % 10 == 0;
    }
    else
    {
        return false;
    }
}

string get_card_type(long card)
{
    int card_length = get_card_length(card);
    int first_digit = get_nth_digit(card, card_length - 1);
    int second_digit = get_nth_digit(card, card_length - 2);
    int first_two_digits = (first_digit * 10) + second_digit;
    if (first_digit == VISA_first_digit)
    {
        return "VISA";
    }
    else if (array_consists(AMEX_first_digits, first_two_digits, amex_digits_len) == true)
    {
        return "AMEX";
    }
    else if (array_consists(MASTERCARD_first_digits, first_two_digits, mc_digits_len) == true)
    {
        return "MASTERCARD";
    }
    else 
    {
        return "INVALID";
    }

}

// gets nth digit from the right, starting with 0, using modulo
int get_nth_digit(long card, int digit)
{
    return fmod(floor(card / pow(10, digit)), 10);
}

int get_card_length(long card)
{
    return floor(log10(card)) + 1;
}

Я хотел бы получить отзывы о моем коде и о том, как я могу его улучшить; такие вещи, как стиль, читабельность, чистота, эффективность и т. д. Легко ли понятен мой код? Что с комментариями – их мало? Я стараюсь не комментировать свой код, когда функция чего-то кажется очевидной. Как мне улучшить стиль и есть ли какие-либо соглашения о коде, которых я не придерживаюсь? Могу ли я оптимизировать это, чтобы ускорить процесс? Или, может быть, есть лучший способ сделать то же самое? В принципе, как мне улучшить свой код?

1 ответ
1

Упрощение было бы следующим.

int checksum(long card)
{
    int checksum = 0;
    for (int i = 0; i < get_card_length(card); i++)
    {
        int digit = get_nth_digit(card, i);
        if (i % 2 == 0)
        {
            checksum += digit;
        }
        else
        {
            int num = digit * 2;
            if (num > 9) // 10, 12, 14, 16, 18
            {
                //num = get_nth_digit(num, 0) + get_nth_digit(num, 1);
                //num = 1 + num - 10;
                num -= 9;
            }
            checksum += num;
        }
    }
    return checksum;
}
  • Более читаемый, если ввести digit.
  • else if может стать else. Поскольку значения операндов% неотрицательны, результат не может быть -1.
  • get_nth_digit является кладжем, и на самом деле конечный результат, кажется, представляет гораздо более простую семантику.

API для проверки номера кредитной карты использует промежуточный checksum. Это «последняя цифра», значение% 10, должно быть 0 для действительной контрольной суммы. Итак, функция checksum может быть локальной “частной” функцией. Не совсем понятно, что вы вставляете в .h, а что в .c.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *