Skip to content

Instantly share code, notes, and snippets.

@thatwist
Created November 24, 2015 11:40
Show Gist options
  • Save thatwist/44cdd1cc15ff808eb1af to your computer and use it in GitHub Desktop.
Save thatwist/44cdd1cc15ff808eb1af to your computer and use it in GitHub Desktop.
Example of convertion decimal to romans until 4999 (with old rules) using tail recursion
import scala.annotation.tailrec
object App1 extends App {
import Romans._
assert(resolveRoman(3999) == "MMMCMXCIX")
assert(resolveRoman(0) == "—")
def read(): Unit = {
scala.io.StdIn.readInt() match {
case i if i < 0 || i > 4999 => println("couldn't parse less 0 or more 4999")
case i =>
println(resolveRoman(i))
read()
}
}
read()
}
object Const {
val romans = List(
//(0, "—"),
(1, "I"),
(5, "V"),
(10, "X"),
(50, "L"),
(100, "C"),
(500, "D"),
(1000, "M"))
}
object Romans {
import Const._
val romansMap = romans.reverse.toMap
def resolveRoman(num: Int, debug: Boolean = false): String = rec(num, 1000, "")(debug)
private implicit class IntToRoman(i: Int) {
def toRoman(times: Int): String = (1 to times).map(_ => romansMap(i)).mkString
def toRoman: String = romansMap(i)
}
@tailrec
private def rec(num: Int, decRang: Int, result: String)(debug: Boolean): String = {
if (num == 0) "—" // zero case
else {
val (remains, resultPos) = resolvePos(num, decRang)(debug)
if (debug) println(s"$remains - $result")
if (remains > 0 && decRang > 0)
rec(remains, decRang / 10, result + resultPos)(debug)
else result + resultPos
}
}
private def resolvePos(num: Int, pos: Int)(debug: Boolean): (Int, String) = {
if (debug) println(s"resolve $num, $pos")
val result = num / pos match {
case times if pos == 1000 => pos.toRoman(times)
case 0 => ""
case times@(1 | 2 | 3) => pos.toRoman(times)
case 4 => pos.toRoman + (5 * pos).toRoman
case 5 => (5 * pos).toRoman
case times@(6 | 7 | 8) => (5 * pos).toRoman + pos.toRoman(times - 5)
case 9 => pos.toRoman + (10 * pos).toRoman
}
(num % pos, result)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment