-
-
Save sangkeon/a226ca134adfcac6def617a956480701 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
class Container() { | |
var Amount:Double = 0.0 | |
var Group = Set[Container](this) | |
def connectTo(other: Container) { | |
assert(other != null, "Cannot connect to a null container.") | |
if(this.Group != other.Group) { | |
val postData = saveConnectPostData(other) | |
val size1 = this.Group.size | |
val size2 = other.Group.size | |
val tot1 = this.Amount * size1 | |
val tot2 = other.Amount * size2 | |
val newAmount = (tot1 + tot2) / (size1 + size2) | |
this.Group = this.Group ++ other.Group | |
other.Group.foreach(_.Group = this.Group) | |
this.Group.foreach(_.Amount = newAmount) | |
assert(postConnect(postData),"connectTo failed its post-condition!") | |
} | |
} | |
case class ConnectPostData(val group1:Set[Container] , val group2 : Set[Container], val amount1:Double, val amount2:Double) | |
private def saveConnectPostData(other: Container) : ConnectPostData = { | |
ConnectPostData(this.Group, other.Group, this.Amount, other.Amount) | |
} | |
private def postConnect(postData: ConnectPostData) = { | |
areMemberGroupCorrect(postData) && isGroupAmountCorect(postData) && isGroupBalanced && isGroupBalanced | |
} | |
private def areMemberGroupCorrect(postData: ConnectPostData) = { | |
postData.group1.diff(this.Group).isEmpty && postData.group2.diff(this.Group).isEmpty && this.Group.size == postData.group1.size + postData.group2.size | |
} | |
private def isGroupAmountCorect(postData: ConnectPostData) = { | |
val size1 = postData.group1.size | |
val size2 = postData.group2.size | |
val tot1 = postData.amount1 * size1 | |
val tot2 = postData.amount2 * size2 | |
val newAmount = (tot1 + tot2) / (size1 + size2) | |
almostEqual(this.Amount, newAmount) | |
} | |
def addWater(amount:Double): Unit = { | |
val amountPerContainer:Double = amount / this.Group.size | |
if(this.Amount + amountPerContainer < 0) { | |
throw new IllegalArgumentException("Not enough water to match the addWater request.") | |
} | |
val oldTotal = this.groupAmount | |
assert(oldTotal >= 0.0) | |
this.Group.foreach(_.Amount += amountPerContainer) | |
assert(postAddWater(oldTotal,amount), "Not enough water to match the addWater request.") | |
} | |
private def postAddWater(oldTotal:Double, addedAmout :Double) = { | |
isGroupBalanced && almostEqual(groupAmount, oldTotal + addedAmout) | |
} | |
private def isGroupBalanced = { | |
this.Group.forall(_.Amount == this.Amount) | |
} | |
private def isGroupConsistent = { | |
this.Group.forall(_ == this.Group) | |
} | |
private def groupAmount:Double = { | |
this.Group.foldLeft(0.0)( (a, c) => a + c.Amount ) | |
} | |
private def almostEqual(x: Double, y: Double) = { | |
val EPSILON = 1E-4 | |
Math.abs(x - y) < EPSILON | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment