Skip to content

Instantly share code, notes, and snippets.

@horace-velmont
Created July 24, 2020 13:26
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 horace-velmont/c3dbad55a34af2dec5b8fd66e89a43e7 to your computer and use it in GitHub Desktop.
Save horace-velmont/c3dbad55a34af2dec5b8fd66e89a43e7 to your computer and use it in GitHub Desktop.
package execise3
import cats.data.{State, StateT}
import cats.implicits._
case class World(grids: Map[String, Grid], appliances: Map[String, Appliance])
object ops {
def newAppliance(id: String, powerAbsorbed: Int): State[World, Unit] = State.modify{ world => world.copy(
appliances = world.appliances.updated(id, Appliance(powerAbsorbed, None, isOn = false))
)}
def newGrid(id: String, maxPower: Int): State[World, Unit] = State.modify { world =>
world.copy(grids = world.grids.updated(id, Grid(maxPower, maxPower)))
}
type EitherS[A] = Either[String, A]
def addPower(gridId: String, power: Int): StateT[EitherS, World, Unit] = StateT{ (world: World) =>
val grid = world.grids(gridId)
val newPower = grid.residualPower + power
if (newPower < 0) Left("Not Enough Power")
else if (newPower > grid.maxPower) Left("Maximum power exceeded")
else Right(world.copy(grids = world.grids.updated(gridId, grid.copy(residualPower = newPower))), ())
}
def plugInto(applianceId: String, gridId: String): StateT[EitherS, World, Unit] = StateT { (world: World) =>
val appliance = world.appliances(applianceId)
(appliance.gridId match {
case Some(gId) if appliance.isOn => for {
_ <- addPower(gId, appliance.powerAbsorbed)
_ <- addPower(gridId, -appliance.powerAbsorbed)
} yield ()
case Some(_) => Right((world, ()))
case None if appliance.isOn => addPower(gridId, -appliance.powerAbsorbed)
case None => Right((world, ()))
})
}.modify(w1 =>
w1.copy(appliances = w1.appliances.updated(applianceId, appliance.copy(gridId = Some(gridId))))
)
def on(applianceId: String): Either[String, World] = {
val appliance = this.appliances(applianceId)
appliance.gridId match {
case None =>
Left("Cannot turn on when unconnected to any grid")
case Some(gid) if !appliance.isOn =>
addPower(gid, -appliance.powerAbsorbed).map { w1 =>
w1.copy(appliances = w1.appliances.updated(applianceId, appliance.copy(isOn = true)))
}
case Some(_) => Right(this)
}
}
def off(applianceId: String): Either[String, World] = {
val appliance = this.appliances(applianceId)
appliance.gridId match {
case Some(gid) if appliance.isOn =>
addPower(gid, appliance.powerAbsorbed).map { w1 =>
w1.copy(appliances = w1.appliances.updated(applianceId, appliance.copy(isOn = false)))
}
case _ => Right(this)
}
}
}
case class Appliance(powerAbsorbed: Int, gridId: Option[String], isOn: Boolean)
case class Grid(maxPower: Int, residualPower: Int)
object Main extends App {
val world = World(Map.empty, Map.empty)
val world1 = world.newAppliance("tv", 150)
.newAppliance("radio", 30)
.newGrid("grid", 3000)
for {
w1 <- world1.plugInto("tv", "grid")
w2 <- w1.plugInto("radio", "grid")
_ <- Right(println(w2.grids("grid").residualPower))
w3 <- w2.on("tv")
_ <- Right(println(w3.grids("grid").residualPower))
w4 <- w3.on("radio")
_ <- Right(println(w4.grids("grid").residualPower))
} yield ()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment