diff --git a/README.md b/README.md index f2bb4f6..7388601 100644 --- a/README.md +++ b/README.md @@ -2245,3 +2245,73 @@ public class ThreadPool { } } ``` +### Damm Algorithm + +```java +public class DammSnippet { + + /** + * Private constructor to prevent instantiation of utility class. + */ + private DammSnippet() { + throw new UnsupportedOperationException("Utility class - instantiation is not allowed."); + } + private static final int[][] matrix = new int[][] { + { 0, 3, 1, 7, 5, 9, 8, 6, 4, 2 }, + { 7, 0, 9, 2, 1, 5, 4, 8, 6, 3 }, + { 4, 2, 0, 6, 8, 7, 1, 3, 5, 9 }, + { 1, 7, 5, 0, 9, 8, 3, 4, 2, 6 }, + { 6, 1, 2, 3, 0, 4, 5, 9, 7, 8 }, + { 3, 6, 7, 4, 2, 0, 9, 5, 8, 1 }, + { 5, 8, 6, 9, 7, 2, 0, 1, 3, 4 }, + { 8, 9, 4, 5, 3, 6, 2, 0, 1, 7 }, + { 9, 4, 3, 8, 6, 1, 7, 2, 0, 5 }, + { 2, 5, 8, 1, 4, 3, 6, 7, 9, 0 } + }; + public static int calculateCheckSumDigit(String number) { + if (number == null || number.isEmpty()) { + throw new IllegalArgumentException("Input number cannot be null or empty."); + } + + int interim = 0; + for (int index = 0; index < number.length(); index++) { + char currCh = number.charAt(index); + if (!Character.isDigit(currCh)) { + throw new IllegalArgumentException("Input number contains invalid characters: " + number); + } + + int currentIndex = currCh - '0'; + interim = matrix[interim][currentIndex]; + } + + return interim; + } + public static int calculateCheckSumDigit(int number) { + return calculateCheckSumDigit(String.valueOf(number)); + } + public static int calculateCheckSumDigit(long number) { + return calculateCheckSumDigit(String.valueOf(number)); + } + public static String generateCheckSum(String number) { + int checkSumDigit = calculateCheckSumDigit(number); + return number + checkSumDigit; + } + public static int generateCheckSum(int number) { + int checkSumDigit = calculateCheckSumDigit(number); + return (number * 10) + checkSumDigit; + } + public static long generateCheckSum(long number) { + int checkSumNumber = calculateCheckSumDigit(number); + return (number * 10) + checkSumNumber; + } + public static boolean validate(String number) { + return calculateCheckSumDigit(number) == 0; + } + public static boolean validate(int number) { + return calculateCheckSumDigit(number) == 0; + } + public static boolean validate(long number) { + return calculateCheckSumDigit(number) == 0; + } +} +``` \ No newline at end of file diff --git a/src/main/java/algorithm/DammSnippet.java b/src/main/java/algorithm/DammSnippet.java new file mode 100644 index 0000000..849fa57 --- /dev/null +++ b/src/main/java/algorithm/DammSnippet.java @@ -0,0 +1,170 @@ +/* + * MIT License + * + * Copyright (c) 2017-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package algorithm; + +/** + * The implementation of the Damm algorithm based on the details on + * Wikipedia. + * + *
The Damm algorithm is used for error detection and generates a checksum + * that can detect single-digit errors and adjacent transposition errors.
+ * + */ +public class DammSnippet { + + /** + * Private constructor to prevent instantiation of utility class. + */ + private DammSnippet() { + throw new UnsupportedOperationException("Utility class - instantiation is not allowed."); + } + + /** + * The quasigroup table used by the Damm algorithm. + */ + private static final int[][] matrix = new int[][] { + { 0, 3, 1, 7, 5, 9, 8, 6, 4, 2 }, + { 7, 0, 9, 2, 1, 5, 4, 8, 6, 3 }, + { 4, 2, 0, 6, 8, 7, 1, 3, 5, 9 }, + { 1, 7, 5, 0, 9, 8, 3, 4, 2, 6 }, + { 6, 1, 2, 3, 0, 4, 5, 9, 7, 8 }, + { 3, 6, 7, 4, 2, 0, 9, 5, 8, 1 }, + { 5, 8, 6, 9, 7, 2, 0, 1, 3, 4 }, + { 8, 9, 4, 5, 3, 6, 2, 0, 1, 7 }, + { 9, 4, 3, 8, 6, 1, 7, 2, 0, 5 }, + { 2, 5, 8, 1, 4, 3, 6, 7, 9, 0 } + }; + + /** + * Calculates the Damm checksum digit for the given number. + * + * @param number the input number as a string + * @return the calculated checksum digit + * @throws IllegalArgumentException if the input is null, empty, or contains non-digit characters + */ + public static int calculateCheckSumDigit(String number) { + if (number == null || number.isEmpty()) { + throw new IllegalArgumentException("Input number cannot be null or empty."); + } + + int interim = 0; + for (int index = 0; index < number.length(); index++) { + char currCh = number.charAt(index); + if (!Character.isDigit(currCh)) { + throw new IllegalArgumentException("Input number contains invalid characters: " + number); + } + + int currentIndex = currCh - '0'; + interim = matrix[interim][currentIndex]; + } + + return interim; + } + + /** + * Calculates the Damm checksum digit for the given number. + * + * @param number the input number as an integer + * @return the calculated checksum digit + */ + public static int calculateCheckSumDigit(int number) { + return calculateCheckSumDigit(String.valueOf(number)); + } + + /** + * Calculates the Damm checksum digit for the given number. + * + * @param number the input number as a long + * @return the calculated checksum digit + */ + public static int calculateCheckSumDigit(long number) { + return calculateCheckSumDigit(String.valueOf(number)); + } + + /** + * Appends the calculated checksum digit to the given number as a string. + * + * @param number the input number as a string + * @return the original number with the checksum digit appended + * @throws IllegalArgumentException if the input is null, empty, or contains non-digit characters + */ + public static String generateCheckSum(String number) { + int checkSumDigit = calculateCheckSumDigit(number); + return number + checkSumDigit; + } + + /** + * Appends the calculated checksum digit to the given number as an integer. + * + * @param number the input number as an integer + * @return the original number with the checksum digit appended + */ + public static int generateCheckSum(int number) { + int checkSumDigit = calculateCheckSumDigit(number); + return (number * 10) + checkSumDigit; + } + + /** + * Appends the calculated checksum digit to the given number as a long. + * + * @param number the input number as a long + * @return the original number with the checksum digit appended + */ + public static long generateCheckSum(long number) { + int checkSumNumber = calculateCheckSumDigit(number); + return (number * 10) + checkSumNumber; + } + + /** + * Validates the given number by checking if the checksum digit is correct. + * + * @param number the input number as a string + * @return {@code true} if the number is valid, {@code false} otherwise + * @throws IllegalArgumentException if the input is null, empty, or contains non-digit characters + */ + public static boolean validate(String number) { + return calculateCheckSumDigit(number) == 0; + } + + /** + * Validates the given number by checking if the checksum digit is correct. + * + * @param number the input number as an integer + * @return {@code true} if the number is valid, {@code false} otherwise + */ + public static boolean validate(int number) { + return calculateCheckSumDigit(number) == 0; + } + + /** + * Validates the given number by checking if the checksum digit is correct. + * + * @param number the input number as a long + * @return {@code true} if the number is valid, {@code false} otherwise + */ + public static boolean validate(long number) { + return calculateCheckSumDigit(number) == 0; + } +} \ No newline at end of file diff --git a/src/test/java/algorithm/DammSnippetTest.java b/src/test/java/algorithm/DammSnippetTest.java new file mode 100644 index 0000000..58a2a6d --- /dev/null +++ b/src/test/java/algorithm/DammSnippetTest.java @@ -0,0 +1,126 @@ +/* + * MIT License + * + * Copyright (c) 2017-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package algorithm; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + + +/** + * Tests for the {@link DammSnippet} class. + */ +class DammSnippetTest { + + /** + * Test for calculating the checksum digit with valid input. + */ + @Test + void testCalculateCheckSumDigit() { + String number = "572"; + int checkSumDigit = DammSnippet.calculateCheckSumDigit(number); + assertEquals(4, checkSumDigit); + } + + /** + * Test for generating the full number with checksum. + */ + @Test + void testGenerateCheckSum() { + String number = "572"; + String fullNumber = DammSnippet.generateCheckSum(number); + assertEquals("5724", fullNumber); + } + + /** + * Test for validating a number with a valid checksum. + */ + @Test + void testValidateWithValidNumber() { + String fullNumber = "5724"; + boolean isValid = DammSnippet.validate(fullNumber); + assertTrue(isValid); + } + + /** + * Test for validating an invalid number. + */ + @Test + void testValidateWithInvalidNumber() { + String invalidNumber = "5723"; + boolean isValid = DammSnippet.validate(invalidNumber); + assertFalse(isValid); + } + + /** + * Test for handling invalid input in checksum calculation. + */ + @Test + void testCalculateCheckSumDigitWithInvalidInput() { + assertThrows(IllegalArgumentException.class, () -> DammSnippet.calculateCheckSumDigit("")); + assertThrows(IllegalArgumentException.class, () -> DammSnippet.calculateCheckSumDigit("12a4")); + } + + /** + * Test for generating checksum with an integer input. + */ + @Test + void testGenerateCheckSumWithInt() { + int number = 572; + int fullNumberWithChecksum = DammSnippet.generateCheckSum(number); + assertEquals(5724, fullNumberWithChecksum); + } + + /** + * Test for validation using integer input. + */ + @Test + void testValidateWithInt() { + int fullNumber = 5724; + boolean isValid = DammSnippet.validate(fullNumber); + assertTrue(isValid); + + int invalidNumber = 5723; + boolean isValidInvalid = DammSnippet.validate(invalidNumber); + assertFalse(isValidInvalid); + } + + /** + * Test for validating a long number with checksum. + */ + @Test + void testValidateWithLong() { + long fullNumber = 5724L; + boolean isValid = DammSnippet.validate(fullNumber); + assertTrue(isValid); + + long invalidNumber = 5723L; + boolean isValidInvalid = DammSnippet.validate(invalidNumber); + assertFalse(isValidInvalid); + } +} \ No newline at end of file