Adds an integer to roman converter utility
All checks were successful
KnarCraft/KnarLib/pipeline/head This commit looks good

This commit is contained in:
2025-09-16 22:17:10 +02:00
parent b0968e619d
commit e9f62ae212
2 changed files with 118 additions and 0 deletions

View File

@@ -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<Integer> romanValues = List.of(1000, 500, 100, 50, 10, 5, 1);
private final static List<Character> romanCharacters = List.of('M', 'D', 'C', 'L', 'X', 'V', 'I');
private IntegerToRomanUtil() {
}
/**
* Gets the given number as a roman number string
*
* @param number <p>The number to convert</p>
* @return <p>The roman representation of the number</p>
*/
@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 <p>The character to repeat</p>
* @param times <p>The number of times to repeat the character</p>
* @return <p>The repeated string</p>
*/
@NotNull
private static String repeat(char character, int times) {
return String.valueOf(character).repeat(Math.max(0, times));
}
}

View File

@@ -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));
}
}