Created
November 2, 2011 13:31
-
-
Save edamico/1333626 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object RomanConverter { | |
val ENTRY_LIST = collection.immutable.List(1 -> "I", 5 -> "V", 10 -> "X", 50 -> "L", 100 -> "C", 500 -> "D", 1000 -> "M").reverse | |
val ENTRY_MAP = collection.immutable.Map[String, Int]("I" -> 1, "V" -> 5, "X" -> 10, "L" -> 50, "C" -> 100, "D" -> 500, "M" -> 1000) | |
/** | |
* Retrieves the number converted to Roman expression | |
*/ | |
def convertToArabic(roman: String): Int = { | |
convertToArabic(roman.toList, 0) | |
} | |
def convertToArabic(roman: List[Char], previousValue: Int): Int = { | |
val currentValue = ENTRY_MAP.get(roman.head.toString()).get | |
roman match { | |
case head :: Nil => | |
if (previousValue < currentValue && is10Power(previousValue)) { | |
return currentValue - previousValue | |
} else { | |
return currentValue + previousValue | |
} | |
case head :: tail => | |
if (previousValue < currentValue && is10Power(previousValue)) { | |
return convertToArabic(roman.tail, currentValue) - previousValue | |
} else { | |
return convertToArabic(roman.tail, currentValue) + previousValue | |
} | |
case (_) => return -1 | |
} | |
} | |
def convertToRoman(decimal: Int): String = { | |
return convertToRoman(decimal, 0) | |
} | |
/** | |
* Converts an arabic number to a roman representation | |
*/ | |
private def convertToRoman(arabicNumber: Int, index: Int): String = { | |
if (index >= 0 && index > ENTRY_LIST.size - 1 || arabicNumber == 0) return "" | |
val entry = ENTRY_LIST(index) | |
val factor = arabicNumber / entry._1 | |
if (factor < 1) { | |
val closestMinuend = retrieveClosestMinuend(arabicNumber) | |
val factorIncreased = (arabicNumber + closestMinuend) / entry._1 | |
if (factorIncreased == 1) { | |
val rest = arabicNumber - (entry._1 - closestMinuend) | |
return convertToRoman(closestMinuend, index + 1) + entry._2 + convertToRoman(rest, index) | |
} else { | |
return convertToRoman(arabicNumber, index + 1) | |
} | |
} else { | |
if (factor <= 3) { | |
return entry._2 * (factor) + convertToRoman(arabicNumber - (factor * entry._1), index) | |
} else { | |
return entry._2 + convertToRoman(arabicNumber + entry._1, index - 1) | |
} | |
} | |
"ERROR" | |
} | |
/** | |
* | |
*/ | |
def retrieveClosestMinuend(decimal: Int): Int = { | |
var result = 0 | |
if (decimal > 1) { | |
val tenPowers = ENTRY_LIST.filter { entry => is10Power(entry._1) } | |
result = tenPowers.find { entry => decimal - entry._1 > 0 }.first._1 | |
} | |
result | |
} | |
def is10Power(number: Double): Boolean = { | |
if (number == 0) return false | |
else | |
return (java.lang.Math.log10(number) - Math.floor(java.lang.Math.log10(number)) == 0) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class RomanTest extends FlatSpec with ShouldMatchers{ | |
"1" should "be converted as I" in { | |
RomanConverter.convertToRoman(1) should equal("I") | |
} | |
"2" should "be converted as II" in { | |
RomanConverter.convertToRoman(2) should equal("II") | |
} | |
"3" should "be converted as III" in { | |
RomanConverter.convertToRoman(3) should equal("III") | |
} | |
"4" should "be converted as IV" in { | |
RomanConverter.convertToRoman(4) should equal("IV") | |
} | |
"5" should "be converted as V" in { | |
RomanConverter.convertToRoman(5) should equal("V") | |
} | |
"6" should "be converted as VI" in { | |
RomanConverter.convertToRoman(6) should equal("VI") | |
} | |
"7" should "be converted as VII" in { | |
RomanConverter.convertToRoman(7) should equal("VII") | |
} | |
"8" should "be converted as VIII" in { | |
RomanConverter.convertToRoman(8) should equal("VIII") | |
} | |
"9" should "be converted as IX" in { | |
RomanConverter.convertToRoman(9) should equal("IX") | |
} | |
"10" should "be converted as X" in { | |
RomanConverter.convertToRoman(10) should equal("X") | |
} | |
"39" should "be converted as XXXIX" in { | |
RomanConverter.convertToRoman(39) should equal("XXXIX") | |
} | |
"45" should "be converted as XLV" in { | |
RomanConverter.convertToRoman(45) should equal("XLV") | |
} | |
"50" should "be converted as L" in { | |
RomanConverter.convertToRoman(50) should equal("L") | |
} | |
"100" should "be converted as C" in { | |
RomanConverter.convertToRoman(100) should equal("C") | |
} | |
"666" should "be converted as DCLXVI" in { | |
RomanConverter.convertToRoman(666) should equal("DCLXVI") | |
} | |
"999" should "be converted as CMXCIX" in { | |
RomanConverter.convertToRoman(999) should equal("CMXCIX") | |
} | |
"1444" should "be converted as MCDXLIV" in { | |
RomanConverter.convertToRoman(1444) should equal("MCDXLIV") | |
} | |
"2008" should "be converted as MMVIII" in { | |
RomanConverter.convertToRoman(2008) should equal("MMVIII") | |
} | |
"I" should "be converted as 1" in { | |
RomanConverter.convertToArabic("I") should equal(1) | |
} | |
"II" should "be converted as 2" in { | |
RomanConverter.convertToArabic("II") should equal(2) | |
} | |
"III" should "be converted as 3" in { | |
RomanConverter.convertToArabic("III") should equal(3) | |
} | |
"IV" should "be converted as 4" in { | |
RomanConverter.convertToArabic("IV") should equal(4) | |
} | |
"V" should "be converted as 5" in { | |
RomanConverter.convertToArabic("V") should equal(5) | |
} | |
"VI" should "be converted as 6" in { | |
RomanConverter.convertToArabic("VI") should equal(6) | |
} | |
"VII" should "be converted as 7" in { | |
RomanConverter.convertToArabic("VII") should equal(7) | |
} | |
"VIII" should "be converted as 8" in { | |
RomanConverter.convertToArabic("VIII") should equal(8) | |
} | |
"IX" should "be converted as 9" in { | |
RomanConverter.convertToArabic("IX") should equal(9) | |
} | |
"X" should "be converted as X" in { | |
RomanConverter.convertToArabic("X") should equal(10) | |
} | |
"XXXIX" should "be converted as 39" in { | |
RomanConverter.convertToArabic("XXXIX") should equal(39) | |
} | |
"XLV" should "be converted as 45" in { | |
RomanConverter.convertToArabic("XLV") should equal(45) | |
} | |
"L" should "be converted as 50" in { | |
RomanConverter.convertToArabic("L") should equal(50) | |
} | |
"C" should "be converted as 100" in { | |
RomanConverter.convertToArabic("C") should equal(100) | |
} | |
"DCLXVI" should "be converted as 666" in { | |
RomanConverter.convertToArabic("DCLXVI") should equal(666) | |
} | |
"CMXCIX" should "be converted as 999" in { | |
RomanConverter.convertToArabic("CMXCIX") should equal(999) | |
} | |
"MCDXLIV" should "be converted as 1444" in { | |
RomanConverter.convertToArabic("MCDXLIV") should equal(1444) | |
} | |
"MMVIII" should "be converted as 2008" in { | |
RomanConverter.convertToArabic("MMVIII") should equal(2008) | |
} | |
"All numbers from 1 to 3000 converted to roman " should "be converted back to arabic returning the original value" in { | |
for (number <- 1 to 3000){ | |
val roman = RomanConverter.convertToRoman(number) | |
val arabic = RomanConverter.convertToArabic(roman) | |
number should equal(arabic) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment