Skip to content

Instantly share code, notes, and snippets.

@sangkeon
Last active October 23, 2020 13:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sangkeon/a226ca134adfcac6def617a956480701 to your computer and use it in GitHub Desktop.
Save sangkeon/a226ca134adfcac6def617a956480701 to your computer and use it in GitHub Desktop.
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