Created
August 10, 2015 00:49
-
-
Save archevel/d343ba07fb8fdfcfdf4f to your computer and use it in GitHub Desktop.
Roman Numerals
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 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