diff --git a/src/roman_converter/zaccagnino_from_roman.py b/src/roman_converter/zaccagnino_from_roman.py new file mode 100644 index 0000000..3a4e223 --- /dev/null +++ b/src/roman_converter/zaccagnino_from_roman.py @@ -0,0 +1,28 @@ +def roman_to_int_comparison(s: str) -> int: + roman_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + num = 0 + for i in range(len(s)): + if i + 1 < len(s) and roman_map[s[i]] < roman_map[s[i+1]]: + num -= roman_map[s[i]] + else: + num += roman_map[s[i]] + return num + +def romanToInt_reverse(s: str) -> int: + roman_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + integer, previous_value = 0, 0 + for ch in reversed(s): + current_value = roman_map[ch] + if current_value < previous_value: + integer -= current_value + else: + integer += current_value + previous_value = current_value + return integer + +def romanToInt_replace(s: str) -> int: + roman_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + s = s.replace("IV", "IIII").replace("IX", "VIIII") + s = s.replace("XL", "XXXX").replace("XC", "LXXXX") + s = s.replace("CD", "CCCC").replace("CM", "DCCCC") + return sum(roman_map[x] for x in s) diff --git a/src/roman_converter/zaccagnino_to_roman.py b/src/roman_converter/zaccagnino_to_roman.py new file mode 100644 index 0000000..830fedd --- /dev/null +++ b/src/roman_converter/zaccagnino_to_roman.py @@ -0,0 +1,62 @@ +def to_roman1(arabic: int) -> str: + if not 0 < arabic < 4000: + return "Input must be between 1 and 3999" + + roman_mapping = [ + (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), + (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), + (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I") + ] + + result = "" + for value, numeral in roman_mapping: + count = arabic // value + result += numeral * count + arabic %= value + + return result + +def arabic_to_roman_greedy(n: int) -> str: + """Greedy mapping implementation. Supports 1..3999.""" + if not isinstance(n, int): + raise TypeError("n must be int") + if n <= 0 or n >= 4000: + raise ValueError("n must be between 1 and 3999") + vals = [ + (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), + (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), + (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I"), + ] + res = [] + for val, sym in vals: + count, n = divmod(n, val) + res.append(sym * count) + if n == 0: + break + return "".join(res) + + +def arabic_to_roman_table(n: int) -> str: + """Table-driven implementation using digit breakdown. Supports 1..3999.""" + if not isinstance(n, int): + raise TypeError("n must be int") + if n <= 0 or n >= 4000: + raise ValueError("n must be between 1 and 3999") + thousands = ["", "M", "MM", "MMM"] + hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"] + tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"] + ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"] + return ( + thousands[(n // 1000) % 10] + + hundreds[(n // 100) % 10] + + tens[(n // 10) % 10] + + ones[n % 10] + ) + + + + + + + + diff --git a/tests/roman_converter/zaccagnino/tests_zaccagnino_from_roman.py b/tests/roman_converter/zaccagnino/tests_zaccagnino_from_roman.py new file mode 100644 index 0000000..9fc9938 --- /dev/null +++ b/tests/roman_converter/zaccagnino/tests_zaccagnino_from_roman.py @@ -0,0 +1,22 @@ +from types import ModuleType + +def test_roman_to_int_comparison(impl: ModuleType): + assert impl.roman_to_int_comparison("I") == 1 + assert impl.roman_to_int_comparison("IV") == 4 + assert impl.roman_to_int_comparison("XXVI") == 26 + assert impl.roman_to_int_comparison("MDCLXVI") == 1666 + assert impl.roman_to_int_comparison("MMMCMXCIX") == 3999 + +def romanToInt_reverse(impl: ModuleType): + assert impl.romanToInt_reverse("I") == 1 + assert impl.romanToInt_reverse("IV") == 4 + assert impl.romanToInt_reverse("XXVI") == 26 + assert impl.romanToInt_reverse("MDCLXVI") == 1666 + assert impl.romanToInt_reverse("MMMCMXCIX") == 3999 + +def test_romanToInt_replace(impl: ModuleType): + assert impl.romanToInt_replace("I") == 1 + assert impl.romanToInt_replace("IV") == 4 + assert impl.romanToInt_replace("XXVI") == 26 + assert impl.romanToInt_replace("MDCLXVI") == 1666 + assert impl.romanToInt_replace("MMMCMXCIX") == 3999 \ No newline at end of file diff --git a/tests/roman_converter/zaccagnino/tests_zaccagnino_to_roman.py b/tests/roman_converter/zaccagnino/tests_zaccagnino_to_roman.py new file mode 100644 index 0000000..dbc700a --- /dev/null +++ b/tests/roman_converter/zaccagnino/tests_zaccagnino_to_roman.py @@ -0,0 +1,23 @@ +from types import ModuleType + + +def test_to_roman1(impl: ModuleType): + assert impl.to_roman1(1) == "I" + assert impl.to_roman1(52) == "LII" + assert impl.to_roman1(176) == "CLXXVI" + assert impl.to_roman1(1256) == "MCCLVI" + assert impl.to_roman1(3999) == "MMMCMXCIX" + +def test_arabic_to_roman_greedy(impl: ModuleType): + assert impl.arabic_to_roman_greedy(1) == "I" + assert impl.arabic_to_roman_greedy(52) == "LII" + assert impl.arabic_to_roman_greedy(176) == "CLXXVI" + assert impl.arabic_to_roman_greedy(1256) == "MCCLVI" + assert impl.arabic_to_roman_greedy(3999) == "MMMCMXCIX" + +def test_arabic_to_roman_table(impl: ModuleType): + assert impl.arabic_to_roman_table(1) == "I" + assert impl.arabic_to_roman_table(52) == "LII" + assert impl.arabic_to_roman_table(176) == "CLXXVI" + assert impl.arabic_to_roman_table(1256) == "MCCLVI" + assert impl.arabic_to_roman_table(3999) == "MMMCMXCIX" \ No newline at end of file