{ 对于(gridrow,scala,akka,actor,Scala,Akka,Actor" /> { 对于(gridrow,scala,akka,actor,Scala,Akka,Actor" />

使用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)