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 🙂