Code Kata: Roman Numeral – Part 1

Christmas is over, so we get rid of the Christmas Tree.
Today I want to show You another Code Kata: Roman Numerals. The task seems to be quite easy. Write a program which converts a decimal number into a string which contains the equivalent as a roman literal. E.g. convert 1984 into MCMLXXXIV.

The requirements

We just use the characters from I to M.

Symbol I V X L C D M
Value 1 5 10 50 100 500 1,000

We first write a simple conversion function which ignores the abbreviation syntax, so instead of IX for 9 we write VIIII. To do so we use integer division and modulo operation.  We start with the highest number and work our way down. Have a look:

def convert_number_simple(number):
    roman_literal = ""
    thousands = number / 1000
    roman_literal += "M" * thousands
    five_hundreds = number % 1000 / 500
    roman_literal += "D" * five_hundreds
    hundreds = number % 1000 % 500 / 100
    roman_literal += "C" * hundreds
    fifties = number % 1000 % 500 % 100 / 50
    roman_literal += "L" * fifties
    tens = number % 1000 % 500 % 100 % 50 / 10
    roman_literal += "X" * tens
    fives = number % 1000 % 500 % 100 % 50 % 10 / 5
    roman_literal += "V" * fives
    ones = number % 1000 % 500 % 100 % 50 % 10 % 5
    roman_literal += "I" * ones
return roman_literal

This is by far not the most efficient way to convert a number. You could introduce a variable which holds the last calculation for the modulo operation, but I chose this representation for the sake of readability.

After we have written the simple conversion we can introduce the complex format by replacing string sequences which represent
900, 90, 9 and 4. It is important that we do it again in an descendant order because if we got “VIIII” and would replace”IIII” we would end up with VIV which is a non-valid numeral.

def convert_number(number):
    easy = convert_number_simple(number)
    easy = easy.replace("DCCCC", "CM") # 900
    easy = easy.replace("LXXXX", "XC") # 90
    easy = easy.replace("VIIII", "IX") # 9
    easy = easy.replace("IIII", "IV")  # 4
return easy

To test drive our code, Python has an assert function build in so we can write our main function as follows:

def main():
    assert("M" == convert_number_simple(1000))
    assert("MM" == convert_number_simple(2000))
    assert("D" == convert_number_simple(500))
    assert("MD" == convert_number_simple(1500))
    assert("C" == convert_number_simple(100))
    assert("L" == convert_number_simple(50))
    assert("X" == convert_number_simple(10))
    assert("V" == convert_number_simple(5))
    assert("I" == convert_number_simple(1))

    assert("MDCCCCLXXXIIII" == convert_number_simple(1984))
    assert("MCMLXXXIV" == convert_number(1984))
    assert("IV" == convert_number(4))
    assert("IX" == convert_number(9))


if __name__ == '__main__':
    main()

So far the solution in Python – stay tuned for Part 2 in which we do it in Rust 🙂