Skip to content
Snippets Groups Projects
Commit 0d0c1322 authored by Will Billingsley's avatar Will Billingsley
Browse files

Remove extraneous weekSix code so sbt run will work

parent 784009ae
No related branches found
No related tags found
No related merge requests found
package cosc250.weekSix
import akka.actor.{Actor, ActorRef, ActorSystem}
import akka.stream.ActorMaterializer
import play.api.libs.json
import play.api.libs.json.{JsValue, Json}
import scala.concurrent.{Promise, Future}
import scala.concurrent.ExecutionContext.Implicits.global
/**
* This week, let's play FizzBuzz with Actors.
*
* If you're not sure what FizzBuzz is, see https://en.wikipedia.org/wiki/Fizz_buzz
*
*/
object Exercise {
/*
* First, because we're working with Actors, we need some messages to pass
* Note: we can also just pass a bare Int! Normally we wouldn't -- it's nice to have a single trait
* or abstract class all our messages belong to -- but for this exercise let's show it's possible
*/
case class Fizz(i:Int)
case class Buzz(i:Int)
case class FizzBuzz(i:Int)
/*
* And we need a message so the next player can say "Wrong! You're out!"
*
* Note, I've made this message generic, so it can contain any of our messages
*/
case class Wrong[T](item:T)
/*
* We're also going to need some "set-up" messages, to tell the Actors who is standing
* next to whom (if Alice goes "Fizz(3)", who goes next?
*/
case class NextPlayerIs(a:ActorRef)
/**
* This is a little utility method I've made. It creates a PartialFunction that
* writes out whatever it received.
*
* PartialFunctions can be composed together using "andThen". So if you want a method
* that logs what it receives and then takes an action depending on what method it receives...
*
* log("MyActor") andThen { case ... }
*/
def log(name:String):PartialFunction[Any, Any] = {
case m =>
println(name + " received " + m)
m
}
/*
* Now you need to define your FizzBuzz Actor...
*/
class FizzBuzzActor extends Actor {
var nextPlayer:Option[ActorRef] = None
def nextResponse(i:Int) = {
val nextNum = i + 1
if (nextNum % 3 == 0 && nextNum % 5 == 0) {
FizzBuzz(nextNum)
} else if (nextNum % 5 == 0) {
Buzz(nextNum)
} else if (nextNum % 3 == 0) {
Fizz(nextNum)
} else nextNum
}
/**
* This should check the veracity of a FizzBuzz message.
* (Including checking whether a Fizz should really have been a FizzBuzz!)
*/
def checkMessage(m:Any):Boolean = m match {
case 0 => true
case FizzBuzz(i) => i % 3 == 0 && i % 5 == 0
case Fizz(i) => i % 3 == 0 && i % 5 != 0
case Buzz(i) => i % 3 != 0 && i % 5 == 0
case i:Int => i % 3 != 0 && i % 5 != 0
case _ => false
}
def respond(i:Int) = {
val n = nextResponse(i)
println("FBA says " + n)
for { p <- nextPlayer } p ! n
}
/**
* We want to check the message, and that means we need a reference to it.
* So I've broken this out as its own function, taking the message m as a parameter
*/
def checkAndRespond(m:Any) = {
if (checkMessage(m)) {
// If the message is good, then we keep going as before
m match {
case i:Int => respond(i)
case Fizz(i) => respond(i)
case Buzz(i) => respond(i)
case FizzBuzz(i) => respond(i)
}
} else {
// But if the message was wrong, we send "Wrong" to the sender
// sender is a message defined on ActorRef that gets the sender of the message we're dealing with.
sender ! Wrong(m)
}
}
def receive = Exercise.log("FBA") andThen {
case NextPlayerIs(p) => {
nextPlayer = Some(p)
// Let's send a message back so there is some kind of response, so the set-up code can know we've done it.
sender ! "Ok"
}
// We need to handle the Wrong message
case Wrong(x) => println("Someone just said I got it wrong.")
// I've broken this code out into the checkAndRespond method
case m => checkAndRespond(m)
}
}
}
package cosc250.weekSix
import java.util.concurrent.TimeoutException
import akka.actor._
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import scala.concurrent.ExecutionContext.Implicits.global
object MyApp extends App {
import Exercise._
// Create the actor system
val system = ActorSystem("PingPongSystem")
// Let's create five Terrible players.
// Each of these returns an ActorRef
val algernon = system.actorOf(Props[FizzBuzzActor], name = "Algernon")
val bertie = system.actorOf(Props[Terrible], name = "Bertie")
val cecily = system.actorOf(Props[FizzBuzzActor], name = "Cecily")
val daliah = system.actorOf(Props[FizzBuzzActor], name = "Dahlia")
val earnest = system.actorOf(Props[FizzBuzzActor], name = "Earnest")
// Ok, this code I'll need to put in the README.md
// To use the "ask" pattern, we need an implicit timeout.
// This sets a default timeout of 5 seconds
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
implicit val timeout = Timeout(5.seconds)
/*
Here, we're putting the players in a circle and checking they've done it.
It relies on the ask pattern (actor ? message)
This will wait for a reply to come back, and gives us a Future[Any]
And then we're using for notation to chain these together. We don't actually care what comes
back in the future (it'll be the string "Ok"), we just care that the reply has come in before we
move on to the next line. So we're getting the value 'a' from the first future ... but then not doing
anything with it.
*/
for {
a <- algernon ? NextPlayerIs(bertie)
b <- bertie ? NextPlayerIs(cecily)
c <-cecily ? NextPlayerIs(daliah)
d <- daliah ? NextPlayerIs(earnest)
e <- earnest ? NextPlayerIs(algernon)
} {
/*
Now this line -- effectively in the middle of a foreach on all those nested futures -- can
only happen when all the Futures have completed. ie, when all the actors have responded to their
NextPlayerIs messages.
*/
algernon ! 0
}
}
package cosc250.weekSix
import akka.actor.{ActorRef, Actor}
import cosc250.weekSix.Exercise._
import scala.util.Random
/**
* This Actor is shockingly awful at this game. It gets the number and increments it,
* but
*/
class Terrible extends Actor {
var nextPlayer:Option[ActorRef] = None
def nextResponse(i:Int) = {
Seq(
i + 1,
Fizz(i + 1),
Buzz(i + 1),
FizzBuzz(i + 1)
)(Random.nextInt(4))
}
def respond(i:Int) = {
val n = nextResponse(i)
println("Terrible says " + n)
for { p <- nextPlayer } p ! n
}
def receive = Exercise.log("Terrible") andThen {
case NextPlayerIs(p) => {
nextPlayer = Some(p)
// Let's send a message back so there is some kind of response, so the set-up code can know we've done it.
sender ! "Ok"
}
case i:Int => respond(i)
case Fizz(i) => respond(i)
case Buzz(i) => respond(i)
case FizzBuzz(i) => respond(i)
// Terrible also needs to handle the Wrong message
case Wrong(x) => println("Someone just said I got it wrong.")
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment