使用scala-akka演员模型调用生活游戏中的邻居演员 我只是Scala的初学者,但在java和C++方面有经验,现在我想用AkkAc能能能者模型来实现考平的并行游戏。我的想法是创建一个50*50的网格,每个单元格都是一个参与者,并在参与者之间传递消息以进行更新。以下是我创建演员的方式: class World(row: Int, col: Int, step: Int) extends Actor { val random = new Random() //generate the alive or dead cell for the game val cellgrid = new World(row, col, step) def receive = { case Start => { for(gridrow <- 0 until row) { for(gridcol <- 0 until col) { context.actorOf(Props(new Grid(random.nextBoolean, gridrow, gridcol, row, col, step))) } } for (gridrow <- 0 until row) { for (gridcol <- 0 until col) { sender ! Compare() } } } case Done(gridrow, gridcol, alive) => { for(gridrow <- 0 until row) { for(gridcol <- 0 until col) { if(alive) print("* ") else print(" ") } print("\n") } sender ! Stop } case Stop => {context.stop(self); println("Stopped the actor system!")} case _ => context.stop(self) } } 类世界(行:Int,列:Int,步:Int)扩展了Actor{ val random=new random()//为游戏生成活的或死的单元格 val cellgrid=新世界(行、列、步) def接收={ 案例开始=>{ 对于(gridrow
,这里是一个完整的工作示例,带有一些注释使用scala-akka演员模型调用生活游戏中的邻居演员 我只是Scala的初学者,但在java和C++方面有经验,现在我想用AkkAc能能能者模型来实现考平的并行游戏。我的想法是创建一个50*50的网格,每个单元格都是一个参与者,并在参与者之间传递消息以进行更新。以下是我创建演员的方式: class World(row: Int, col: Int, step: Int) extends Actor { val random = new Random() //generate the alive or dead cell for the game val cellgrid = new World(row, col, step) def receive = { case Start => { for(gridrow <- 0 until row) { for(gridcol <- 0 until col) { context.actorOf(Props(new Grid(random.nextBoolean, gridrow, gridcol, row, col, step))) } } for (gridrow <- 0 until row) { for (gridcol <- 0 until col) { sender ! Compare() } } } case Done(gridrow, gridcol, alive) => { for(gridrow <- 0 until row) { for(gridcol <- 0 until col) { if(alive) print("* ") else print(" ") } print("\n") } sender ! Stop } case Stop => {context.stop(self); println("Stopped the actor system!")} case _ => context.stop(self) } } 类世界(行:Int,列:Int,步:Int)扩展了Actor{ val random=new random()//为游戏生成活的或死的单元格 val cellgrid=新世界(行、列、步) def接收={ 案例开始=>{ 对于(gridrow,scala,akka,actor,Scala,Akka,Actor,,这里是一个完整的工作示例,带有一些注释 import akka.actor._ import scala.concurrent.duration._ object GameOfLife extends App { val system = ActorSystem("game-of-life") implicit val ec = system.dispatcher // implicit ExecutionContext for scheduler val Wi
import akka.actor._
import scala.concurrent.duration._
object GameOfLife extends App {
val system = ActorSystem("game-of-life")
implicit val ec = system.dispatcher // implicit ExecutionContext for scheduler
val Width = 20
val Height = 20
// create view so we can send results to
val view = system.actorOf(Props(classOf[View], Width, Height), "view")
// create map of cells, key is coordinate, a tuple (Int, Int)
val cells = (for { i <- 0 until Width; j <- 0 until Height } yield {
val cellRef = system.actorOf(Props[Cell], s"cell_$i-$j") // correct usage of Props, see docs for details
((i,j), cellRef)
}).toMap
// we need some helpers to work with grid
val neighbours = (x:Int, y:Int) => Neighbours(
for (i <- x - 1 to x + 1; j <- y - 1 to y + 1; if ((i,j) != (x,y))) yield {
cells( ( (i + Width) % Width, (j + Height) % Height) )
}
)
for { i <- 0 until Width; j <- 0 until Height } { // notice that this loop doesn't have yield, so it is foreach loop
cells((i,j)) ! neighbours(i,j) // send cell its' neighbours
}
// now we need to synchronously update all cells,
// this is the main reason why suggested model (one actor - one cell) is probably not the most adequate
for { i <- 0 until Width; j <- 0 until Height } {
cells((i,j)) ! SetState(alive = util.Random.nextBoolean, x = i, y = j)
}
// for simplicity I assume that update will take less then update time
val refreshTime = 100.millis
system.scheduler.schedule(1.second, refreshTime) {
view ! Run
for { i <- 0 until Width; j <- 0 until Height } {
cells((i,j)) ! Run
}
}
}
class View(w:Int, h:Int) extends Actor {
var actorStates: Map[(Int,Int), Boolean] = Map()
def receive:Receive = {
case Run => actorStates = Map.empty
case UpdateView(alive, x, y) =>
actorStates = actorStates + (((x,y), alive))
if (actorStates.size == w * h) {
for { j <- 0 until h } {
for(i <- 0 until w) {
if(actorStates((i,j))) {
print("x ")
} else {
print(". ")
}
}
println()
}
}
}
}
class Cell extends Actor {
var neighbours:Seq[ActorRef] = Seq()
var neighbourStates: Map[ActorRef, Boolean] = Map() // Map.empty[Map[ActorRef, Boolean]] is better
var alive:Boolean = false
var previousState:Boolean = false
var x:Int = 0
var y:Int = 0
def receive : Receive = {
case Run =>
neighbourStates = Map.empty
previousState = alive
neighbours.foreach(_ ! QueryState)
case SetState(alive,x,y) =>
this.alive = alive
this.x = x
this.y = y
case Neighbours(xs) =>
neighbours = xs
case QueryState =>
sender ! NeighbourState(alive = previousState)
case NeighbourState(alive) =>
neighbourStates = neighbourStates + ((sender, alive))
// this is tricky when all senders has send you their states it doesn't mean that you can mutate your own,
// they could still may request your internal state, will use hackish previousState
if (neighbourStates.size == 8) { // total of 8 neighbours sent their states, we are complete with update
val aliveMembers = neighbourStates.values.filter(identity).size
aliveMembers match {
case n if n < 2 => this.alive = false
case 3 => this.alive = true
case n if n > 3 => this.alive = false;
case _ => // 2, state doesn't change
}
context.actorSelection("/user/view") ! UpdateView(this.alive, x, y)
}
}
}
case class SetState(alive:Boolean, x:Int, y:Int)
case class Neighbours(xs:Seq[ActorRef])
case object QueryState
case object Run
case class NeighbourState(alive:Boolean)
case class UpdateView (alive:Boolean, x:Int, y:Int)
导入akka.actor_
导入scala.concurrent.duration_
对象GameOfLife扩展应用程序{
val系统=ActorSystem(“生命游戏”)
隐式val ec=system.dispatcher//调度程序的隐式ExecutionContext
val宽度=20
val高度=20
//创建视图,以便将结果发送到
val view=system.actorOf(道具(类别[视图]、宽度、高度),“视图”)
//创建单元格地图,关键是坐标,一个元组(Int,Int)
val单元格=(用于{我仍然不确定代码是否有效,因此如果您认为有问题,请告诉我,我已经尝试了您的代码,它确实有效,但不是以并行方式。我的想法是创建角色并让它们并行运行。我认为一种方法是使用并行集合,但有没有其他方法可以创建不使用集合的角色?Fo例如,递归地创建参与者,但如果是这样,如何实现这一点并获得没有坐标的邻居?:)你怎么说不是以并行方式?它是99.999%并行的,所有计算都通过参与者之间的消息通信进行)当然,在执行下一次更新之前,我必须等待所有参与者更改其状态。为了避免这种情况,可以使用不可变的单元格数组,然后下一次更新不会更改上一次更新的状态,因此可以以真正的并行方式(可能是使用并行集合)执行此操作。但这样一来,您就不需要那么多参与者,事实上,您不会这样做根本不需要演员。
import akka.actor._
import scala.concurrent.duration._
object GameOfLife extends App {
val system = ActorSystem("game-of-life")
implicit val ec = system.dispatcher // implicit ExecutionContext for scheduler
val Width = 20
val Height = 20
// create view so we can send results to
val view = system.actorOf(Props(classOf[View], Width, Height), "view")
// create map of cells, key is coordinate, a tuple (Int, Int)
val cells = (for { i <- 0 until Width; j <- 0 until Height } yield {
val cellRef = system.actorOf(Props[Cell], s"cell_$i-$j") // correct usage of Props, see docs for details
((i,j), cellRef)
}).toMap
// we need some helpers to work with grid
val neighbours = (x:Int, y:Int) => Neighbours(
for (i <- x - 1 to x + 1; j <- y - 1 to y + 1; if ((i,j) != (x,y))) yield {
cells( ( (i + Width) % Width, (j + Height) % Height) )
}
)
for { i <- 0 until Width; j <- 0 until Height } { // notice that this loop doesn't have yield, so it is foreach loop
cells((i,j)) ! neighbours(i,j) // send cell its' neighbours
}
// now we need to synchronously update all cells,
// this is the main reason why suggested model (one actor - one cell) is probably not the most adequate
for { i <- 0 until Width; j <- 0 until Height } {
cells((i,j)) ! SetState(alive = util.Random.nextBoolean, x = i, y = j)
}
// for simplicity I assume that update will take less then update time
val refreshTime = 100.millis
system.scheduler.schedule(1.second, refreshTime) {
view ! Run
for { i <- 0 until Width; j <- 0 until Height } {
cells((i,j)) ! Run
}
}
}
class View(w:Int, h:Int) extends Actor {
var actorStates: Map[(Int,Int), Boolean] = Map()
def receive:Receive = {
case Run => actorStates = Map.empty
case UpdateView(alive, x, y) =>
actorStates = actorStates + (((x,y), alive))
if (actorStates.size == w * h) {
for { j <- 0 until h } {
for(i <- 0 until w) {
if(actorStates((i,j))) {
print("x ")
} else {
print(". ")
}
}
println()
}
}
}
}
class Cell extends Actor {
var neighbours:Seq[ActorRef] = Seq()
var neighbourStates: Map[ActorRef, Boolean] = Map() // Map.empty[Map[ActorRef, Boolean]] is better
var alive:Boolean = false
var previousState:Boolean = false
var x:Int = 0
var y:Int = 0
def receive : Receive = {
case Run =>
neighbourStates = Map.empty
previousState = alive
neighbours.foreach(_ ! QueryState)
case SetState(alive,x,y) =>
this.alive = alive
this.x = x
this.y = y
case Neighbours(xs) =>
neighbours = xs
case QueryState =>
sender ! NeighbourState(alive = previousState)
case NeighbourState(alive) =>
neighbourStates = neighbourStates + ((sender, alive))
// this is tricky when all senders has send you their states it doesn't mean that you can mutate your own,
// they could still may request your internal state, will use hackish previousState
if (neighbourStates.size == 8) { // total of 8 neighbours sent their states, we are complete with update
val aliveMembers = neighbourStates.values.filter(identity).size
aliveMembers match {
case n if n < 2 => this.alive = false
case 3 => this.alive = true
case n if n > 3 => this.alive = false;
case _ => // 2, state doesn't change
}
context.actorSelection("/user/view") ! UpdateView(this.alive, x, y)
}
}
}
case class SetState(alive:Boolean, x:Int, y:Int)
case class Neighbours(xs:Seq[ActorRef])
case object QueryState
case object Run
case class NeighbourState(alive:Boolean)
case class UpdateView (alive:Boolean, x:Int, y:Int)