Skip to content

Instantly share code, notes, and snippets.

@waynejo

waynejo/.scala Secret

Created July 26, 2020 08:50
Show Gist options
  • Save waynejo/577ec265401b27fd0e00b8477cd7bdcf to your computer and use it in GitHub Desktop.
Save waynejo/577ec265401b27fd0e00b8477cd7bdcf to your computer and use it in GitHub Desktop.
import cats.data.StateT
import cats.implicits._
case class Appliance(power: Double, isOn: Boolean = false, grid: Option[Int] = None)
case class Grid(maxPower: Double)
case class World(grids: Vector[Grid] = Vector(), appliances: Vector[Appliance] = Vector())
object Main extends App {
type Error = String
type ErrorOr[A] = Either[Error, A]
type EitherState[A] = StateT[ErrorOr, World, A]
def newAppliance(power: Double): EitherState[Int] = StateT { world =>
Right(world.copy(appliances = world.appliances :+ Appliance(power)), world.appliances.size)
}
def newGrid(maxPower: Int): EitherState[Int] = StateT { world =>
Right((world.copy(grids = world.grids :+ Grid(maxPower)), world.grids.size))
}
def residualPower(world: World, gridId: Int): Double = {
val grid = world.grids(gridId)
val sumOfPower = world.appliances.filter { appliance => appliance.isOn && appliance.grid.contains(gridId) }.map { _.power }.sum
grid.maxPower - sumOfPower
}
def plugInto(applianceId: Int, gridId: Int): EitherState[Unit] = StateT { world =>
val appliance = world.appliances(applianceId).copy(isOn = false, grid = Some(gridId))
Right(world.copy(appliances = world.appliances.updated(applianceId, appliance)), ())
}
def on(applianceId: Int): EitherState[Unit] = StateT { world =>
val appliance = world.appliances(applianceId).copy(isOn = true)
appliance.grid match {
case Some(grid) if residualPower(world, grid) < appliance.power =>
Left("Not Enough Power")
case _ =>
Right(world.copy(appliances = world.appliances.updated(applianceId, appliance)), ())
}
}
def off(applianceId: Int): EitherState[Unit] = StateT { world =>
val appliance = world.appliances(applianceId).copy(isOn = false)
Right(world.copy(appliances = world.appliances.updated(applianceId, appliance)), ())
}
def printResidualPower(gridId: Int): EitherState[Unit] = StateT { world =>
println(residualPower(world, gridId))
Right(world, ())
}
val world = World()
val program = for {
tv <- newAppliance(150)
radio <- newAppliance(30)
airConditioner <- newAppliance(4000)
grid <- newGrid(3000)
_ <- plugInto(tv, grid)
_ <- plugInto(radio, grid)
_ <- plugInto(airConditioner, grid)
_ <- printResidualPower(grid)
_ <- on(tv)
// _ <- on(airConditioner)
_ <- printResidualPower(grid)
_ <- on(radio)
_ <- printResidualPower(grid)
} yield ()
println(program.run(world))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment