Skip to content

Instantly share code, notes, and snippets.

@mathieuancelin
Forked from ruaudl/SmartElevatorManager.scala
Last active December 24, 2015 01:39
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 mathieuancelin/6724998 to your computer and use it in GitHub Desktop.
Save mathieuancelin/6724998 to your computer and use it in GitHub Desktop.
package elevator
import akka.actor.{ ActorSystem }
import akka.agent.Agent
import akka.util.Timeout
import java.util.concurrent.{TimeUnit}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
case class SmartElevator(
floor: Integer = 0, direction: Direction = Direction.UP, nextCommand: Command = Command.UP,
targets: List[Integer] = List[Integer]()) {
def withFloor(f: Integer) = copy(floor = f)
def withDirection(d: Direction) = copy(direction = d)
def withNextState(c: Command) = copy(nextCommand = c)
def next = this match {
case SmartElevator(_, _, Command.OPEN, _) => withNextState(Command.CLOSE)
case SmartElevator(f, _, _, t) if t.contains(f) => withNextState(Command.OPEN).copy(targets = targets.filter(_ != f))
case SmartElevator(f, Direction.UP, _, t) if t.filter(_ > f).nonEmpty => withNextState(Command.UP) withFloor (f + 1)
case SmartElevator(f, Direction.UP, _, t) if t.filter(_ < f).nonEmpty => withNextState(Command.DOWN) withFloor (f - 1) withDirection (Direction.DOWN)
case SmartElevator(f, Direction.DOWN, _, t) if t.filter(_ < f).nonEmpty => withNextState(Command.DOWN) withFloor (f - 1)
case SmartElevator(f, Direction.DOWN, _, t) if t.filter(_ > f).nonEmpty => withNextState(Command.UP) withFloor (f + 1) withDirection (Direction.UP)
case _ => withNextState(Command.NOTHING)
}
def withNewTarget(t: Integer) = copy(targets = (targets :+ t).removeDuplicates)
}
class SmartElevatorManager extends ElevatorEngine {
val elevator = Agent(SmartElevator(0, Direction.UP, Command.OPEN))
def nextCommand = {
val currentState = elevator().nextCommand
elevator.send(_.next)
currentState
}
def call(atFloor: Integer, to: Direction) = {
elevator.send(_.withNewTarget(atFloor))
this
}
def go(floorToGo: Integer) = {
elevator.send(_.withNewTarget(floorToGo))
this
}
def userHasEntered(user: User) = this
def userHasExited(user: User) = this
def reset(cause: String) = {
elevator.send(SmartElevator(0, Direction.UP, Command.OPEN))
this
}
}
package elevator
import akka.actor.{Props, ActorSystem, Actor}
import akka.pattern._
import java.util.concurrent.atomic.AtomicReference
import akka.util.Timeout
import java.util.concurrent.{TimeUnit}
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
case class NextCommand()
case class GotoNextState()
case class NewTarget(floor: Int)
case class SmartElevator(
floor: Integer = 0, direction: Direction = Direction.UP, nextCommand: Command = Command.UP,
targets: List[Integer] = List[Integer]()) {
def withFloor(f: Integer) = copy(floor = f)
def withDirection(d: Direction) = copy(direction = d)
def withNextState(c: Command) = copy(nextCommand = c)
def next = this match {
case SmartElevator(_, _, Command.OPEN, _) => withNextState(Command.CLOSE)
case SmartElevator(f, _, _, t) if t.contains(f) => withNextState(Command.OPEN).copy(targets = targets.filter(_ != f))
case SmartElevator(f, Direction.UP, _, t) if t.filter(_ > f).nonEmpty => withNextState(Command.UP) withFloor (f + 1)
case SmartElevator(f, Direction.UP, _, t) if t.filter(_ < f).nonEmpty => withNextState(Command.DOWN) withFloor (f - 1) withDirection (Direction.DOWN)
case SmartElevator(f, Direction.DOWN, _, t) if t.filter(_ < f).nonEmpty => withNextState(Command.DOWN) withFloor (f - 1)
case SmartElevator(f, Direction.DOWN, _, t) if t.filter(_ > f).nonEmpty => withNextState(Command.UP) withFloor (f + 1) withDirection (Direction.UP)
case _ => withNextState(Command.NOTHING)
}
def withNewTarget(t: Integer) = copy(targets = (targets :+ t).removeDuplicates)
}
class SmartElevatorManager extends ElevatorEngine {
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
implicit val max = Duration(5, TimeUnit.SECONDS)
implicit val system = ActorSystem("elevator")
val elevatorRef = system.actorOf(Props(new Actor {
val ref = new AtomicReference[SmartElevator]( SmartElevator(0, Direction.UP, Command.OPEN) )
def receive = {
case e: SmartElevator => ref.set(e)
case _: GotoNextState => ref.set(ref.get().next)
case _: NextCommand => sender ! ref.get().nextCommand
case NewTarget(floor) => ref.set(ref.get().copy(floor = floor))
case _ =>
}
}))
def nextCommand = {
val currentState = (elevatorRef ? NextCommand()).mapTo[Command]
elevatorRef ! GotoNextState
Await.result( currentState, Duration(5, TimeUnit.SECONDS) )
}
def call(atFloor: Integer, to: Direction) = {
Await.result( elevatorRef ? NewTarget(atFloor), max )
this
}
def go(floorToGo: Integer) = {
Await.result( elevatorRef ? NewTarget(floorToGo), max )
this
}
def userHasEntered(user: User) = this
def userHasExited(user: User) = this
def reset(cause: String) = {
Await.result( elevatorRef ? SmartElevator(0, Direction.UP, Command.OPEN), max )
this
}
}
package elevator.scala
import elevator.Command
import elevator.engine.ElevatorEngine
import elevator.engine.ElevatorEngine._
import elevator.User
import elevator.Direction
import scala.collection.immutable.Queue
case class SmartElevator(
floor: Integer = 0, direction: Direction = Direction.UP, nextCommand: Command = Command.UP,
targets: List[Integer] = List[Integer]()) {
def withFloor(f: Integer) = copy(floor = f)
def withDirection(d: Direction) = copy(direction = d)
def withNextState(c: Command) = copy(nextCommand = c)
def next = this match {
case SmartElevator(_, _, Command.OPEN, _) => withNextState(Command.CLOSE)
case SmartElevator(f, _, _, t) if t.contains(f) => withNextState(Command.OPEN).copy(targets = targets.filter(_ != f))
case SmartElevator(f, Direction.UP, _, t) if t.filter(_ > f).nonEmpty => withNextState(Command.UP) withFloor (f + 1)
case SmartElevator(f, Direction.UP, _, t) if t.filter(_ < f).nonEmpty => withNextState(Command.DOWN) withFloor (f - 1) withDirection (Direction.DOWN)
case SmartElevator(f, Direction.DOWN, _, t) if t.filter(_ < f).nonEmpty => withNextState(Command.DOWN) withFloor (f - 1)
case SmartElevator(f, Direction.DOWN, _, t) if t.filter(_ > f).nonEmpty => withNextState(Command.UP) withFloor (f + 1) withDirection (Direction.UP)
case _ => withNextState(Command.NOTHING)
}
def withNewTarget(t: Integer) = copy(targets = (targets :+ t).removeDuplicates)
}
class SmartElevatorManager extends ElevatorEngine {
var elevator = SmartElevator(0, Direction.UP, Command.OPEN)
def nextCommand = {
val currentState = elevator.nextCommand
elevator = elevator.next
currentState
}
def call(atFloor: Integer, to: Direction) = {
elevator = elevator withNewTarget atFloor
this
}
def go(floorToGo: Integer) = {
elevator = elevator withNewTarget floorToGo
this
}
def userHasEntered(user: User) = this
def userHasExited(user: User) = this
def reset(cause: String) = {
elevator = SmartElevator(0, Direction.UP, Command.OPEN)
this
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment