Skip to content

Instantly share code, notes, and snippets.

@archevel
Created August 10, 2015 00:49
Show Gist options
  • Save archevel/d343ba07fb8fdfcfdf4f to your computer and use it in GitHub Desktop.
Save archevel/d343ba07fb8fdfcfdf4f to your computer and use it in GitHub Desktop.
Roman Numerals
object RomanNumerals {
import annotation._
trait Numeral {
def num:Int
}
class RomanNumeral[T<:Numeral](n:Int) extends Number with Ordered[RomanNumeral[Numeral]] {
private val MAX_ROMAN = 3999
val num = if(n > 0 && n % MAX_ROMAN != 0) n % MAX_ROMAN else (n % MAX_ROMAN) + MAX_ROMAN
def compare(that:RomanNumeral[Numeral]) = this.num compare that.num
def +(number:Number) = new RomanNumeral[Numeral](num + number.intValue)
def -(number:Number) = new RomanNumeral[Numeral](num - number.intValue)
def *(number:Number) = new RomanNumeral[Numeral](num * number.intValue)
def /(number:Number) = new RomanNumeral[Numeral](num / number.intValue)
def apply[N >: T <: Numeral](rn:NumeralI[N]) =
new RomanNumeral[Numeral](rn.num + num) with Numeral
def apply[N >: T <: Numeral](rn:NumeralV[N]) =
new RomanNumeral[NumeralI[Numeral]](rn.num + num) with NumeralV[NumeralI[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralX[N]) =
new RomanNumeral[NumeralV[Numeral]](rn.num + num) with NumeralX[NumeralV[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralL[N]) =
new RomanNumeral[NumeralX[Numeral]](rn.num + num) with NumeralL[NumeralX[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralC[N]) =
new RomanNumeral[NumeralL[Numeral]](rn.num + num) with NumeralC[NumeralL[Numeral]]
def apply[N >: T <: Numeral](rn:NumeralD[N]) =
new RomanNumeral[NumeralC[Numeral]](rn.num + num) with NumeralD[NumeralC[Numeral]]
override def intValue = num
override def byteValue = num.toByte
override def floatValue = num.toFloat
override def doubleValue = num.toDouble
override def longValue = num.toLong
override def equals(that:Any) =
that.isInstanceOf[RomanNumeral[Numeral]] && num == that.asInstanceOf[RomanNumeral[Numeral]].num
override def hashCode = num
override def toString = {
@tailrec
def innerLoop(int:Int, count:Int,
sb:StringBuilder,
rPair:(Int,String)):(StringBuilder, Int, Int) = {
if(int > 0 && count > 0
&& rPair._1 > 0
&& (int - rPair._1) >= 0) {
if(count > int) {
innerLoop(int, count - rPair._1, sb, rPair)
} else {
sb.append(rPair._2)
innerLoop(int - rPair._1, count, sb, rPair)
}
} else {
(sb, int, rPair._1)
}
}
val listOfPairs:List[(Int,String)] =
(1000, "M")::(900, "CM")::
(500, "D")::(400, "CD")::
(100, "C")::(90, "XC")::
(50, "L")::(40, "XL")::
(10, "X")::(9, "IX")::
(5,"V")::(4, "IV")::
(1,"I")::Nil
listOfPairs.foldLeft((new StringBuilder(), num, 3999))(
(sbNumCounter,romanNumPair) => {
val (sb, int, counter) = sbNumCounter
innerLoop(int, counter, sb, romanNumPair)
})._1 toString
}
}
object RomanNumeral {
def apply[T<:Numeral](int:Int) = new RomanNumeral[T](int)
def unapply(rn:RomanNumeral[Numeral]) = Some(rn.num)
}
trait NumeralI[N<:Numeral] extends Numeral
trait NumeralV[N<:Numeral] extends NumeralI[N] {
def I = new RomanNumeral[Numeral](1 + this.num) with Numeral
def II = new RomanNumeral[Numeral](2 + this.num) with Numeral
def III = new RomanNumeral[Numeral](3 + this.num) with Numeral
}
trait NumeralX[N<:Numeral] extends NumeralV[N] {
def IV = new RomanNumeral[Numeral](4 + this.num) with Numeral
def V = new RomanNumeral[NumeralI[Numeral]](5 + this.num) with NumeralV[NumeralI[Numeral]]
def IX = new RomanNumeral[Numeral](9 + this.num) with Numeral
}
trait NumeralL[N<:Numeral] extends NumeralX[N] {
def X = new RomanNumeral[NumeralV[Numeral]](10 + this.num) with NumeralX[NumeralV[Numeral]]
def XX = new RomanNumeral[NumeralV[Numeral]](20 + this.num) with NumeralX[NumeralV[Numeral]]
def XXX = new RomanNumeral[NumeralV[Numeral]](30 + this.num) with NumeralX[NumeralV[Numeral]]
}
trait NumeralC[N<:Numeral] extends NumeralL[N] {
def XL = new RomanNumeral[NumeralV[Numeral]](40 + this.num) with NumeralX[NumeralV[Numeral]]
def L = new RomanNumeral[NumeralX[Numeral]](50 + this.num) with NumeralL[NumeralX[Numeral]]
def XC = new RomanNumeral[NumeralV[Numeral]](90 + this.num) with NumeralX[NumeralV[Numeral]]
}
trait NumeralD[N<:Numeral] extends NumeralC[N] {
def C = new RomanNumeral[NumeralL[Numeral]](100 + this.num) with NumeralC[NumeralL[Numeral]]
def CC = new RomanNumeral[NumeralL[Numeral]](200 + this.num) with NumeralC[NumeralL[Numeral]]
def CCC = new RomanNumeral[NumeralL[Numeral]](300 + this.num) with NumeralC[NumeralL[Numeral]]
}
trait NumeralM[N<:Numeral] extends NumeralD[N] {
def CD = new RomanNumeral[NumeralL[Numeral]](400 + this.num) with NumeralC[NumeralL[Numeral]]
def D = new RomanNumeral[NumeralC[Numeral]](500 + this.num) with NumeralD[NumeralC[Numeral]]
def CM = new RomanNumeral[NumeralL[Numeral]](900 + this.num) with NumeralC[NumeralL[Numeral]]
}
val I = new RomanNumeral[NumeralI[Numeral]](1) with NumeralI[Numeral]
val II = new RomanNumeral[NumeralI[Numeral]](2) with NumeralI[Numeral]
val III = new RomanNumeral[NumeralI[Numeral]](3) with NumeralI[Numeral]
val IV = new RomanNumeral[NumeralI[Numeral]](4) with NumeralI[Numeral]
val V = new RomanNumeral[NumeralI[Numeral]](5) with NumeralV[NumeralV[Numeral]]
val IX = new RomanNumeral[NumeralI[Numeral]](9) with NumeralI[Numeral]
val X = new RomanNumeral[NumeralV[Numeral]](10) with NumeralX[NumeralX[Numeral]]
val XX = new RomanNumeral[NumeralV[Numeral]](20) with NumeralX[NumeralX[Numeral]]
val XXX = new RomanNumeral[NumeralV[Numeral]](30) with NumeralX[NumeralX[Numeral]]
val XL = new RomanNumeral[NumeralV[Numeral]](40) with NumeralX[NumeralX[Numeral]]
val L = new RomanNumeral[NumeralX[Numeral]](50) with NumeralL[NumeralL[Numeral]]
val XC = new RomanNumeral[NumeralV[Numeral]](90) with NumeralX[NumeralX[Numeral]]
val C = new RomanNumeral[NumeralL[Numeral]](100) with NumeralC[NumeralC[Numeral]]
val CC = new RomanNumeral[NumeralL[Numeral]](200) with NumeralC[NumeralC[Numeral]]
val CCC = new RomanNumeral[NumeralL[Numeral]](300) with NumeralC[NumeralC[Numeral]]
val CD = new RomanNumeral[NumeralL[Numeral]](400) with NumeralC[NumeralC[Numeral]]
val D = new RomanNumeral[NumeralC[Numeral]](500) with NumeralD[NumeralD[Numeral]]
val CM = new RomanNumeral[NumeralL[Numeral]](900) with NumeralC[NumeralC[Numeral]]
val M = new RomanNumeral[NumeralD[Numeral]](1000) with NumeralM[NumeralM[Numeral]]
val MM = new RomanNumeral[NumeralD[Numeral]](2000) with NumeralM[NumeralM[Numeral]]
val MMM = new RomanNumeral[NumeralD[Numeral]](3000) with NumeralM[NumeralM[Numeral]]
implicit def num2RomanNumeral(n:Number):RomanNumeral[Numeral] =
new RomanNumeral[Numeral](n.intValue)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment