From e9f62ae212d9c89350aae541f966a7f61b63ca2e Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Tue, 16 Sep 2025 22:17:10 +0200 Subject: [PATCH] Adds an integer to roman converter utility --- .../knarlib/util/IntegerToRomanUtil.java | 74 +++++++++++++++++++ .../knarlib/util/IntegerToRomanUtilTest.java | 44 +++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/main/java/net/knarcraft/knarlib/util/IntegerToRomanUtil.java create mode 100644 src/test/java/net/knarcraft/knarlib/util/IntegerToRomanUtilTest.java diff --git a/src/main/java/net/knarcraft/knarlib/util/IntegerToRomanUtil.java b/src/main/java/net/knarcraft/knarlib/util/IntegerToRomanUtil.java new file mode 100644 index 0000000..586cade --- /dev/null +++ b/src/main/java/net/knarcraft/knarlib/util/IntegerToRomanUtil.java @@ -0,0 +1,74 @@ +package net.knarcraft.knarlib.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * A utility for converting from an integer to a roman numeral + */ +public final class IntegerToRomanUtil { + + private final static List romanValues = List.of(1000, 500, 100, 50, 10, 5, 1); + private final static List romanCharacters = List.of('M', 'D', 'C', 'L', 'X', 'V', 'I'); + + private IntegerToRomanUtil() { + + } + + /** + * Gets the given number as a roman number string + * + * @param number

The number to convert

+ * @return

The roman representation of the number

+ */ + @NotNull + public static String getRomanNumber(int number) { + StringBuilder output = new StringBuilder(); + int remainder = number; + for (int i = 0; i < romanCharacters.size(); i++) { + int romanValue = romanValues.get(i); + char romanCharacter = romanCharacters.get(i); + + // Repeat the roman character, and calculate the new remainder + if (remainder >= romanValue) { + output.append(repeat(romanCharacter, remainder / romanValue)); + remainder = remainder % romanValue; + } + + // Exit early to prevent unexpected trailing characters + if (remainder == 0) { + return output.toString(); + } + + // Generate the special case IV and similar + for (int j = i; j < romanCharacters.size(); j++) { + int value = romanValues.get(j); + int difference = Math.max(romanValue - value, 0); + + /* If the remainder is "one" less than the current roman value, we hit the IV/IX/XL case. + Note that 5 triggers the special case when 10 is tested, as 5 = 10 - 5, which requires a test, so it + can be filtered out. */ + if (remainder == difference && value != romanValue / 2) { + output.append(romanCharacters.get(j)).append(romanCharacter); + remainder = 0; + } + } + } + + return output.toString(); + } + + /** + * Repeats the given character + * + * @param character

The character to repeat

+ * @param times

The number of times to repeat the character

+ * @return

The repeated string

+ */ + @NotNull + private static String repeat(char character, int times) { + return String.valueOf(character).repeat(Math.max(0, times)); + } + +} diff --git a/src/test/java/net/knarcraft/knarlib/util/IntegerToRomanUtilTest.java b/src/test/java/net/knarcraft/knarlib/util/IntegerToRomanUtilTest.java new file mode 100644 index 0000000..8bbfd64 --- /dev/null +++ b/src/test/java/net/knarcraft/knarlib/util/IntegerToRomanUtilTest.java @@ -0,0 +1,44 @@ +package net.knarcraft.knarlib.util; + +import org.junit.jupiter.api.Test; + +import static net.knarcraft.knarlib.util.IntegerToRomanUtil.getRomanNumber; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * A test class for IntegerToRomanConverter + */ +public class IntegerToRomanUtilTest { + + @Test + public void basicNumbersTest() { + assertEquals("I", getRomanNumber(1)); + assertEquals("II", getRomanNumber(2)); + assertEquals("III", getRomanNumber(3)); + assertEquals("IV", getRomanNumber(4)); + assertEquals("V", getRomanNumber(5)); + assertEquals("X", getRomanNumber(10)); + assertEquals("XI", getRomanNumber(11)); + assertEquals("XII", getRomanNumber(12)); + assertEquals("XIII", getRomanNumber(13)); + assertEquals("XIV", getRomanNumber(14)); + assertEquals("XV", getRomanNumber(15)); + assertEquals("XX", getRomanNumber(20)); + assertEquals("L", getRomanNumber(50)); + assertEquals("C", getRomanNumber(100)); + assertEquals("D", getRomanNumber(500)); + assertEquals("M", getRomanNumber(1000)); + } + + @Test + public void nineFourTest() { + assertEquals("IV", getRomanNumber(4)); + assertEquals("IX", getRomanNumber(9)); + assertEquals("XIV", getRomanNumber(14)); + assertEquals("XIX", getRomanNumber(19)); + assertEquals("XXIV", getRomanNumber(24)); + assertEquals("XL", getRomanNumber(40)); + assertEquals("IL", getRomanNumber(49)); + } + +}