*This follows on from Roman Numerals: part I.*

Last time I had managed to convert these numbers into Roman numerals:

```
1 => I
2 => II
10 => X
20 => XX
100 => C
200 => CC
1000 => M
2000 => MM
11 => XI
3012 => MMMXII
```

My full implementation at this point:

```
private val powersOfTen = listOf(1000, 100, 10, 1)
fun Int.toRoman(): String {
val placeValues = toDecimalPlaceValues(this)
return placeValues.map {
it.magnitude.toRomanDigit().repeat(it.multiplier)
}.joinToString(separator = "")
}
fun toDecimalPlaceValues(number: Int): List<PlaceValue> {
if (number == 0) {
return emptyList()
}
val largestPowerNeeded = powersOfTen.find { number >= it } ?: 1
if (largestPowerNeeded == 1) {
return listOf(PlaceValue(multiplier = number, magnitude = 1))
} else {
val multiplier = number / largestPowerNeeded
val remainder = number % largestPowerNeeded
return listOf(PlaceValue(multiplier,
magnitude = largestPowerNeeded))
+ toDecimalPlaceValues(remainder)
}
}
private fun Int.toRomanDigit(): String = when(this) {
1000 -> "M"
100 -> "C"
10 -> "X"
1 -> "I"
else -> throw RomanNumeralException(
"No mapping to symbol for ${this}")
}
internal class RomanNumeralException(message: String) :
RuntimeException(message)
data class PlaceValue(val multiplier: Int, val magnitude: Int) {
override fun toString(): String = "$multiplier*$magnitude"
}
```

In general, my solution could handle any number whose decimal representation used only the digits 0–3 (and not exceeding 3333).

This post describes my steps to completing the kata, so as to handle the remaining digits.

#### Five, fifty, five hundred

I added my test for 5 ⇒ V. The `toDecimalPlaceValues`

function already worked for all decimal digits so I didn’t need to change that. I just needed to add an entry `5 -> "V"`

in `toRomanDigit`

conversion and then improve the function I mapped over the PlaceValues:

```
fun Int.toRoman(): String {
val placeValues = toDecimalPlaceValues(this)
return placeValues.map {
if (it.multiplier == 5) {
5.toRomanDigit()
} else {
it.magnitude.toRomanDigit().repeat(it.multiplier)
}
}.joinToString(separator = "")
}
```

Obviously, this would only work for 5 in the *units* place, not for 5 tens or 5 hundreds. I had to add a mapping `50 -> "L"`

in `toRomanDigit`

, but then the only change I needed to make inside the PlaceValue mapping function was from this:

```
if (it.multiplier == 5) {
5.toRomanDigit()
}
```

to this:

```
if (it.multiplier == 5) {
(5 * it.magnitude).toRomanDigit()
}
```

500 ⇒ D was as simple as adding a mapping `500 -> "D"`

in `toRomanDigit`

.

At this point I added a (hopefully) redundant test of 1555 ⇒ MDLV just to reassure myself before moving onto the more tricky issue of 4, 40 and 400.

##### Four, forty, four hundred

So, fives turned out to be straightforward — my investment in mapping to PlaceValues was definitely paying off — but fours might be a bit more fiddly?

Rather than add another if/else to the place values mapping function, I used another `when`

-expression:

```
return placeValues.map {
fun one() = it.magnitude.toRomanDigit()
fun five() = (it.magnitude * 5).toRomanDigit()
when (it.multiplier) {
in 1..3 -> one().repeat(it.multiplier)
4 -> one() + five()
5 -> five()
else -> ""
}
}.joinToString(separator = "")
```

At first I defined `val one`

and `val five`

but when mapping a PlaceValue with magnitude of 1000 it blew up because I don’t have a Roman digit mapping for 5000; the kata doesn’t provide one^{1}. So instead I defined a couple of local functions^{2}.

Not too hard, after all!

I was fairly sure this would work for 40 and 400 as well, so added a test for 444 ⇒ CDXLIV, which passed.

#### Six, sixty, six hundred

I was definitely on the home straight now, and went directly to a test for 666 ⇒ DCLXVI. Implementation was obvious:

```
return placeValues.map {
fun one() = it.magnitude.toRomanDigit()
fun five() = (it.magnitude * 5).toRomanDigit()
when (it.multiplier) {
in 1..3 -> one().repeat(it.multiplier)
4 -> one() + five()
5 -> five()
6 -> five() + one() // added this line
else -> ""
}
}.joinToString(separator = "")
```

I was still keeping an eye out for opportunities to refactor, but couldn’t spot any.

#### Seven, seventy, seven hundred

Also really easy at this point! The test was for 777 ⇒ DCCLXXVII.

```
return placeValues.map {
fun one() = it.magnitude.toRomanDigit()
fun five() = (it.magnitude * 5).toRomanDigit()
when (it.multiplier) {
in 1..3 -> one().repeat(it.multiplier)
4 -> one() + five()
5 -> five()
6 -> five() + one()
7 -> five() + one() + one() // added this line
else -> ""
}
}.joinToString(separator = "")
```

#### Eight, eighty, eight hundred

So nearly there… a test for 888 ⇒ DCCCLXXXVIII and the obvious implementation…

```
return placeValues.map {
fun one() = it.magnitude.toRomanDigit()
fun five() = (it.magnitude * 5).toRomanDigit()
when (it.multiplier) {
in 1..3 -> one().repeat(it.multiplier)
4 -> one() + five()
5 -> five()
6 -> five() + one()
7 -> five() + one() + one()
8 -> five() + one() + one() + one() // added this line
else -> ""
}
}.joinToString(separator = "")
```

I decided, though, that I could reduce this a little bit.

```
return placeValues.map {
fun one() = it.magnitude.toRomanDigit()
fun five() = (it.magnitude * 5).toRomanDigit()
when (it.multiplier) {
in 1..3 -> one().repeat(it.multiplier)
4 -> one() + five()
5 -> five()
in 6..8 -> five() + one().repeat(it.multiplier - 5)
else -> ""
}
}.joinToString(separator = "")
```

In retrospect, I think I should have left it alone, as the longer version was more readable.

#### Nine, ninety, nine hundred

Last step! To satisfy 999 ⇒ CMXCIX, I just needed a `ten()`

function and one more case, and I had my final implementation of `toRoman()`

:

```
fun Int.toRoman(): String {
val placeValues = toDecimalPlaceValues(this)
return placeValues.map {
fun one() = it.magnitude.toRomanDigit()
fun five() = (it.magnitude * 5).toRomanDigit()
fun ten() = (it.magnitude * 10).toRomanDigit()
when (it.multiplier) {
in 1..3 -> one().repeat(it.multiplier)
4 -> one() + five()
5 -> five()
in 6..8 -> five() + one().repeat(it.multiplier - 5)
9 -> one() + ten()
else -> ""
}
}.joinToString(separator = "")
}
```

#### Just for fun…

I added a test for the longest Roman numeral representing a year in the past: 1888 ⇒ MDCCCLXXXVIII.

Fortunately, it passed.

#### Closing thoughts

I really like Kotlin for TDD as the ability just to write a function without an enclosing object suits the nature of a lot of these katas. The syntax isn’t too different from Java, and the functional methods on collections are nice. Optional application of named parameters, such as in `PlaceValue(multiplier = 2, magnitude = 100)`

, makes for great clarity.

Apparently, for larger numbers than M, the Romans would draw a line above the digit to indicate it was multiplied by 10, so 5000 would be V with a line above it. This doesn’t come up much these days, as Roman numerals are only really used for dates. ↩

Kotlin has “lazy” properties of classes/objects but not yet lazy local values. It’s on the roadmap. ↩

*Image credit: photograph of Cleveland Bridge plaque, Bath by Jaggery is licensed for reuse under CC BY-SA 2.0*