I wanted to challenge myself in a new language that I am learning (C#) by doing a simple exercise: check if a "modulus 10" Luhn number is valid or not. In this case the common application if verifying credit card numbers. So I discovered that an exist implementation of this algorithm.
I have tested the code works with generated card numbers)
How might this be improved. I saw on other posts that all the procedure can be done in very few lines of code compared to mine.
Program.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CreditCardChecker
{
class Program
{
static void Main(string[] args)
{
string cardNumber = Operations.UInput();
LuhnValidator.Validator(cardNumber);
Operations.DoWork();
Console.ReadLine();
}
}
class Operations
{
static string userInput;
static string cardType = "";
public static string UInput()
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Insert credit card number");
userInput = Console.ReadLine();
return userInput;
}
public static void DoWork()
{
if (LuhnValidator.IsValid(userInput) == true)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Valid Card");
var input = userInput.Substring(0, 1);
switch (input)
{
case "3":
Console.ForegroundColor = ConsoleColor.Cyan;
break;
case "4":
Console.ForegroundColor = ConsoleColor.Blue;
break;
case "5":
Console.ForegroundColor = ConsoleColor.Yellow;
break;
case "6":
Console.ForegroundColor = ConsoleColor.DarkYellow;
break;
default:
Console.WriteLine("Card type unidentified");
break;
}
cardType = ConfigurationManager.AppSettings[input];
Console.WriteLine(cardType);
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Invalid Card");
}
}
}
}
LuhnValidator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CreditCardChecker
{
// TODO: refactoring
//CheckDigit included
class LuhnValidator
{
static string invertedCardNumber = "";
static string noCheckDigit = "";
static List<int> numbersArray = new List<int>();
static List<int> listEvenPosition = new List<int>();
static List<int> listOddPosition = new List<int>();
static List<int> evenNumbers = new List<int>();
static List<int> notSumEvenNumbers = new List<int>();
static int sumDoubleEvenNumbers;
static int sumOfAll;
static int magicNumber = 0;
static int checkDigit = 0;
public static void Validator(string cardNumber)
{
Inverser(cardNumber);
AddToList(invertedCardNumber);
EvenOddLists();
Multiply();
Sums();
IsValid(cardNumber);
}
public static void Inverser(string cardNumber)
{
try
{
cardNumber = cardNumber.Replace(" ", string.Empty);
switch (cardNumber.Length)
{
case 16:
noCheckDigit = cardNumber.Substring(0, 15);
break;
case 15:
noCheckDigit = cardNumber.Substring(0, 14);
break;
default:
Console.WriteLine("Insert a valid number");
break;
}
// Invert card number so I can operate from left to right
for (int i = noCheckDigit.Length - 1; i >= 0; i--)
{
invertedCardNumber = invertedCardNumber + cardNumber[i];
}
}
catch (Exception)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Number too short");
}
}
public static void AddToList(string noCheckDigit)
{
// Convert the numbers from char to int and add them to array
numbersArray = invertedCardNumber.Substring(0, invertedCardNumber.Length).Select(c => c - '0').ToList();
}
public static void EvenOddLists()
{
// Separate Even and Odd numbers into two lists
listEvenPosition = numbersArray.Where((item, index) => index % 2 == 0).ToList();
listOddPosition = numbersArray.Where((item, index) => index % 2 != 0).ToList();
}
public static void Multiply()
{
foreach (var digit in listEvenPosition)
{
int sum = digit * 2;
if (sum > 9)
{
var digits = sum.ToString().Select(x => int.Parse(x.ToString()));
evenNumbers.Add(digits.Sum());
}
if (sum < 9)
{
notSumEvenNumbers.Add(sum);
}
}
sumDoubleEvenNumbers = evenNumbers.Sum();
}
public static void Sums()
{
int a = listOddPosition.Sum();
int b = notSumEvenNumbers.Sum();
sumOfAll = a + b + sumDoubleEvenNumbers;
checkDigit = Convert.ToInt32((sumOfAll * 9).ToString().AsEnumerable().Last().ToString());
if (invertedCardNumber.Length < 16)
{
magicNumber = sumOfAll + checkDigit;
}
if (invertedCardNumber.Length >= 16)
{
magicNumber = sumOfAll;
}
}
public static bool IsValid(string cardNumber)
{
bool status = true;
if (magicNumber % 10 == 0 & cardNumber.EndsWith(checkDigit.ToString()))
{
status = true;
}
else
{
status = false;
}
return status;
}
}
}
Where the code can be improved ? It's a very basic version, did just to see if it works (in fact, I wrote this code two times before having a working version, this one). Can I get rid of all that lists at the beggining?