diff --git a/README.md b/README.md index 892695c..a62d112 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,122 @@ public class LinearSearchSnippet { } } ``` +### Luhn Mod N + + +```java +public class LuhnModnSnippet { + + private static final String CODE_POINTS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + /** + * Throws an exception based on the specified mode, character, or code point. + * + * @param mode the mode of operation; determines which exception to throw + * @param character the character to include in the exception message (used if mode is 1) + * @param codePoint the code point to include in the exception message (used if mode is 2) + * @throws IllegalArgumentException if mode is 1, message including the invalid character, + * or if mode is 2, message including the invalid code point + */ + public static void throwException(int mode, char character, int codePoint) { + switch (mode) { + case 1: + throw new IllegalArgumentException("Invalid character: " + character); + case 2: + throw new IllegalArgumentException("Invalid code point: " + codePoint); + default: + return; + } + } + + /** + * Converts a character to its corresponding code point index. + * + * @param character the input character + * @return the code point index + * @throws IllegalArgumentException if the character is invalid + */ + public static int codePointFromCharacter(char character) { + if (CODE_POINTS.indexOf(character) == -1) { + throwException(1, character, 0); + } + return CODE_POINTS.indexOf(character); + } + + /** + * Converts a code point index to its corresponding character. + * + * @param codePoint the code point index + * @return the corresponding character + * @throws IllegalArgumentException if the code point is out of range + */ + public static char characterFromCodePoint(int codePoint) { + if (codePoint < 0 || codePoint >= CODE_POINTS.length()) { + throwException(2, '\0', codePoint); + } + return CODE_POINTS.charAt(codePoint); + } + + /** + * Returns the number of valid input characters. + * + * @return the total count of valid input characters in {@code CODE_POINTS} + */ + public static int numberOfValidInputCharacters() { + return CODE_POINTS.length(); + } + + /** + * Helper method to calculate the sum for both check character generation and validation. + * + * @param input the input string + * @param factorStart the initial factor to start with (1 or 2) + * @return the calculated sum, reminder, and the numberOfValidInputCharacters + */ + private static int[] calculateSum(String input, int factorStart) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException("Input cannot be empty"); + } + + int factor = factorStart; + int sum = 0; + int n = numberOfValidInputCharacters(); + + for (int i = input.length() - 1; i >= 0; i--) { + int codePoint = codePointFromCharacter(input.charAt(i)); + int addend = factor * codePoint; + factor = (factor == 2) ? 1 : 2; + addend = (addend / n) + (addend % n); + sum += addend; + } + return new int[]{sum, sum % n, n}; + } + + /** + * Generates a check character for the given input string using the Luhn mod N algorithm. + * + * @param input the input string (non-empty) + * @return the generated check character + * @throws IllegalArgumentException if the input is null or empty + */ + public static char generateCheckCharacter(String input) { + int[] result = calculateSum(input, 2); + return characterFromCodePoint((result[2] - result[1]) % result[2]); + } + + /** + * Validates a check character by applying the Luhn mod N algorithm. + * + * @param input the input string (including the check character) + * @return true if the input passes validation, false otherwise + * @throws IllegalArgumentException if the input is null or empty + */ + public static boolean validateCheckCharacter(String input) { + int[] result = calculateSum(input, 1); + return (result[1] == 0); + } +} +``` ### Merge Sort @@ -435,134 +551,6 @@ public class SieveOfEratosthenesSnippet { } } ``` -### Luhn Mod N - - -```java -public class LuhnModnSnippet { - - - private LuhnModnSnippet() { - throw new IllegalStateException("LuhnModnSnippet class"); - } - - - private static final String CODE_POINTS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - - /** - * Generates a check character using the Luhn mod N algorithm. - * - * @param character the input string consisting of valid alphanumeric characters - * @return the generated check character - * @throws IllegalArgumentException if the input contains invalid characters - */ - public static int codePointFromCharacter(char character) { - int index = CODE_POINTS.indexOf(character); - if (index == -1) { - throw new IllegalArgumentException("Invalid character: " + character); - } - return index; - } - - - /** - * Converts a code point to its corresponding character. - * - * @param codePoint the code point to be converted - * @return the character representation of the code point - * @throws IllegalArgumentException if the code point is out of range. - */ - public static char characterFromCodePoint(int codePoint) { - if (codePoint < 0 || codePoint >= CODE_POINTS.length()) { - throw new IllegalArgumentException("Invalid code point: " + codePoint); - } - return CODE_POINTS.charAt(codePoint); - } - - - public static int numberOfValidInputCharacters() { - return CODE_POINTS.length(); - } - - - /** - * Generates a check character for the given input string using the Luhn mod N algorithm. - * - * @param input the input string (non-empty) - * @return the generated check character - * @throws IllegalArgumentException if the input is null or empty - */ - public static char generateCheckCharacter(String input) { - if (input == null || input.isEmpty()) { - throw new IllegalArgumentException("Input cannot be empty"); - } - - - int factor = 2; - int sum = 0; - int n = numberOfValidInputCharacters(); - - - for (int i = input.length() - 1; i >= 0; i--) { - int codePoint = codePointFromCharacter(input.charAt(i)); - int addend = factor * codePoint; - - - factor = (factor == 2) ? 1 : 2; - - - addend = (addend / n) + (addend % n); - sum += addend; - } - - - int remainder = sum % n; - int checkCodePoint = (n - remainder) % n; - - - return characterFromCodePoint(checkCodePoint); - } - - - /** - * Validates a check character by applying the Luhn mod N algorithm. - * - * @param input the input string (including the check character) - * @return true if the input passes validation, false otherwise - * @throws IllegalArgumentException if the input is null or empty - */ - public static boolean validateCheckCharacter(String input) { - if (input == null || input.isEmpty()) { - throw new IllegalArgumentException("Input cannot be empty"); - } - - - int factor = 1; - int sum = 0; - int n = numberOfValidInputCharacters(); - - - for (int i = input.length() - 1; i >= 0; i--) { - int codePoint = codePointFromCharacter(input.charAt(i)); - int addend = factor * codePoint; - - - factor = (factor == 2) ? 1 : 2; - - - addend = (addend / n) + (addend % n); - sum += addend; - } - - - int remainder = sum % n; - - - return (remainder == 0); - } -} -``` ## Array diff --git a/src/main/java/algorithm/LuhnModnSnippet.java b/src/main/java/algorithm/LuhnModnSnippet.java index d751544..53f2e76 100644 --- a/src/main/java/algorithm/LuhnModnSnippet.java +++ b/src/main/java/algorithm/LuhnModnSnippet.java @@ -22,98 +22,109 @@ * SOFTWARE. */ - package algorithm; - /** * LuhnModnSnippet. */ public class LuhnModnSnippet { - - private LuhnModnSnippet() { - throw new IllegalStateException("LuhnModnSnippet class"); - } - - private static final String CODE_POINTS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * Throws an exception based on the specified mode, character, or code point. + * + * @param mode the mode of operation; determines which exception to throw + * @param character the character to include in the exception message (used if mode is 1) + * @param codePoint the code point to include in the exception message (used if mode is 2) + * @throws IllegalArgumentException if mode is 1, message including the invalid character, + * or if mode is 2, message including the invalid code point + */ + public static void throwException(int mode, char character, int codePoint) { + switch (mode) { + case 1: + throw new IllegalArgumentException("Invalid character: " + character); + case 2: + throw new IllegalArgumentException("Invalid code point: " + codePoint); + default: + return; + } + } /** - * Generates a check character using the Luhn mod N algorithm. + * Converts a character to its corresponding code point index. * - * @param character the input string consisting of valid alphanumeric characters - * @return the generated check character - * @throws IllegalArgumentException if the input contains invalid characters + * @param character the input character + * @return the code point index + * @throws IllegalArgumentException if the character is invalid */ public static int codePointFromCharacter(char character) { - int index = CODE_POINTS.indexOf(character); - if (index == -1) { - throw new IllegalArgumentException("Invalid character: " + character); + if (CODE_POINTS.indexOf(character) == -1) { + throwException(1, character, 0); } - return index; + return CODE_POINTS.indexOf(character); } - /** - * Converts a code point to its corresponding character. + * Converts a code point index to its corresponding character. * - * @param codePoint the code point to be converted - * @return the character representation of the code point - * @throws IllegalArgumentException if the code point is out of range. + * @param codePoint the code point index + * @return the corresponding character + * @throws IllegalArgumentException if the code point is out of range */ public static char characterFromCodePoint(int codePoint) { if (codePoint < 0 || codePoint >= CODE_POINTS.length()) { - throw new IllegalArgumentException("Invalid code point: " + codePoint); + throwException(2, '\0', codePoint); } return CODE_POINTS.charAt(codePoint); } - + /** + * Returns the number of valid input characters. + * + * @return the total count of valid input characters in {@code CODE_POINTS} + */ public static int numberOfValidInputCharacters() { return CODE_POINTS.length(); } - /** - * Generates a check character for the given input string using the Luhn mod N algorithm. + * Helper method to calculate the sum for both check character generation and validation. * - * @param input the input string (non-empty) - * @return the generated check character - * @throws IllegalArgumentException if the input is null or empty + * @param input the input string + * @param factorStart the initial factor to start with (1 or 2) + * @return the calculated sum, reminder, and the numberOfValidInputCharacters */ - public static char generateCheckCharacter(String input) { + private static int[] calculateSum(String input, int factorStart) { if (input == null || input.isEmpty()) { throw new IllegalArgumentException("Input cannot be empty"); } - - int factor = 2; + int factor = factorStart; int sum = 0; int n = numberOfValidInputCharacters(); - for (int i = input.length() - 1; i >= 0; i--) { int codePoint = codePointFromCharacter(input.charAt(i)); int addend = factor * codePoint; - - factor = (factor == 2) ? 1 : 2; - - addend = (addend / n) + (addend % n); sum += addend; } - - - int remainder = sum % n; - int checkCodePoint = (n - remainder) % n; - - - return characterFromCodePoint(checkCodePoint); + return new int[]{sum, sum % n, n}; } + /** + * Generates a check character for the given input string using the Luhn mod N algorithm. + * + * @param input the input string (non-empty) + * @return the generated check character + * @throws IllegalArgumentException if the input is null or empty + */ + public static char generateCheckCharacter(String input) { + int[] result = calculateSum(input, 2); + return characterFromCodePoint((result[2] - result[1]) % result[2]); + } /** * Validates a check character by applying the Luhn mod N algorithm. @@ -123,32 +134,7 @@ public static char generateCheckCharacter(String input) { * @throws IllegalArgumentException if the input is null or empty */ public static boolean validateCheckCharacter(String input) { - if (input == null || input.isEmpty()) { - throw new IllegalArgumentException("Input cannot be empty"); - } - - - int factor = 1; - int sum = 0; - int n = numberOfValidInputCharacters(); - - - for (int i = input.length() - 1; i >= 0; i--) { - int codePoint = codePointFromCharacter(input.charAt(i)); - int addend = factor * codePoint; - - - factor = (factor == 2) ? 1 : 2; - - - addend = (addend / n) + (addend % n); - sum += addend; - } - - - int remainder = sum % n; - - - return (remainder == 0); + int[] result = calculateSum(input, 1); + return (result[1] == 0); } -} +} \ No newline at end of file diff --git a/src/test/java/algorithm/LuhnModnSnippetTest.java b/src/test/java/algorithm/LuhnModnSnippetTest.java index 6c02df2..63b1f51 100644 --- a/src/test/java/algorithm/LuhnModnSnippetTest.java +++ b/src/test/java/algorithm/LuhnModnSnippetTest.java @@ -22,10 +22,8 @@ * SOFTWARE. */ - package algorithm; - import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -35,23 +33,15 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; - - - - - /** * Tests for {@link LuhnModnSnippet#generateCheckCharacter(String)} and * {@link LuhnModnSnippet#validateCheckCharacter(String)}. */ class LuhnModnSnippetTest { - /** * Tests the full process of generating and validating a check character. */ - - @ParameterizedTest @MethodSource("validInputProvider") public void testGenerateCheckCharacter(String input) { @@ -61,7 +51,6 @@ public void testGenerateCheckCharacter(String input) { "Validation should pass for the generated check character."); } - @ParameterizedTest @MethodSource("invalidInputProvider") public void testInvalidInputs(String input, Character checkCharacter, boolean throwException) { @@ -79,7 +68,6 @@ public void testInvalidInputs(String input, Character checkCharacter, boolean th } } - private static Stream validInputProvider() { return Stream.of( "HELLO", @@ -88,11 +76,10 @@ private static Stream validInputProvider() { ); } - private static Stream invalidInputProvider() { return Stream.of( Arguments.of("", null, true), Arguments.of("WORLD", 'A', false) ); } -} +} \ No newline at end of file