LARA

object GradingPolicy {
  import scala.math.{min,max,round}
  val version = "December 2012, Version 1.0"
 
  def roundToHalf(grade: Double) : Double =
    round(grade*2.0)/2.0
 
  def ratioToGrade(ratio: Double) : Double =
    roundToHalf(5*ratio + 1.24999)
 
  def baseGrade(project: Double, theory: Double) =
    ratioToGrade(0.55*project + 0.45*theory)
 
  val threshold = 0.5
 
  def isRatio(x:Double):Boolean = {0.0 <= x && x <= 1.0}
 
  // Input: ratios of points achieved relative to maximum possible
  def finalGrade(project: Double, homeworks: Double, quiz: Double) : Double = {
    require(isRatio(project) && isRatio(homeworks) && isRatio(quiz))
    val theory = 0.45*homeworks + 0.55*quiz
    val base = baseGrade(project, theory)
    if (project >= threshold && theory >= threshold)
      base
    else
      min(base, 3.5)
  } ensuring (result => 1.0 <= result && result <= 6.0)
 
  // ==================== Tests =============================
 
  def illustrate(scores : (Double,Double,Double)) = {
    val (project, homeworks, quiz) = scores
    val grade = finalGrade(project, homeworks, quiz)
 
    printf("project=%4.2f, homeworks=%4.2f, quiz=%4.2f  ==>  GRADE = %3.1f \n", 
	   project, homeworks, quiz, grade)
  }
 
  def main(args : Array[String]) = {
    List[(Double, Double, Double)](
      (0.2 ,0.3 ,0),
      (0.2 ,0.4 ,0),
      (0.4 ,0.2 ,0.24),
      (0.49, 0.5, 0.5),
      (0.49,1.0,1.0),
      (0.5 ,0   ,0.23),
      (0.5 ,0   ,0.25),
      (0.5, 0.5, 0.5),
      (0.5,1.0,1.0),
      (0.51, 0.51, 0.51),
      (0.6, 0.5, 0.0),
      (0.6, 0.6, 0.6),
      (0.6,1.0,1.0),
      (0.7 ,0.7 ,0.66),
      (0.7 ,0.7 ,0.88),
      (0.7 ,0.8 ,0.87),
      (0.7,1.0,1.0),
      (0.8 ,0.6 ,0.75),
      (0.8 ,0.7 ,0.63),
      (0.8 ,0.7 ,0.85),
      (0.8 ,0.8 ,0.78),
      (0.8, 0.8, 0.0),
      (0.8,1.0,1.0),
      (0.9 ,0.7 ,0.59),
      (0.9 ,0.8 ,0.63),
      (0.9 ,0.8 ,0.8),
      (0.9 ,0.9 ,0.88),
      (0.9,1.0,1.0),
      (1   ,0.8 ,0.88),
      (1   ,1.0 ,0.91),
      (1.0,0.2,1.0),
      (1.0,1.0,0.2),
      (1.0,1.0,0.2),
      (1.0,1.0,1.0)
    ) foreach illustrate
  }
}