読者です 読者をやめる 読者になる 読者になる

サンタクロース問題

Scala

このエントリは Scala Advent Calendar jp 2010 : ATND の 24 日のものです。


前日に id:mzp (mzp さん) から「サンタクロース問題というのがあってね」という話を聞いたので、イヴだしやってみることにしました。ネタの提供ありがとう!
サンタクロース問題の詳細については、

とかを見てもらえばいいでしょう。
面倒な人向けに概要:
トナカイ (reindeer) が 9 匹いて、全員揃うとおもちゃを配りに行く。終わったら解散。
こびと (elf) が 10 人いて、そのうち 3 人そろうと次期のおもちゃをどうするかの会議を開く。終わったら解散。
以上です。


これを、Scala のアクター使って書いてみました。
アクター使って何か書くのは初めてだったけど、これは楽でいいですね。

import scala.actors._
import scala.actors.Actor._

// サンタを表す・・・というより、サンタの家を表してる感のあるアクター
object Santa extends Actor {
  import scala.collection.mutable._
  val reindeers = new ListBuffer[SantaTeam]()
  val elves = new ListBuffer[SantaTeam]()

  def act() {
    def work(team: ListBuffer[SantaTeam], job: String, treat: Symbol) {
      println(job)
      team.foreach(_ ! treat)
      team.clear()
    }

    // そろったかどうか確認して、そろってたら仕事する
    def arrive(member: SantaTeam) {
      println(member.name + "到着")
      member match {
        case r: Reindeer =>
          reindeers += r
          if (reindeers.length == 9) work(reindeers, "配達!", 'play)
        case e: Elf =>
          elves += e
          if (elves.length == 3) work(elves, "会議!", 'work)
      }
    }

    // 誰か着いたら、そのままarrive関数に丸投げ
    loop { react { case m: SantaTeam => arrive(m) } }
  }
}

object Thread {
  def sleep() = java.lang.Thread.sleep((java.lang.Math.random() * 1000).toLong)
}

// サンタチームを表す抽象クラス
abstract sealed class SantaTeam(val name: String, action: PartialFunction[Any, Unit]) extends Actor {
  def act() = loop { Thread.sleep(); react(action) }
}
// トナカイ
case class Reindeer(n: String, santa: Actor)
  extends SantaTeam(n, { case 'play => santa ! self })
// こびと
case class Elf(n: String, santa: Actor)
  extends SantaTeam(n, { case 'work => santa ! self })

object Main {
  def main(args: Array[String]) {
    // トナカイたちとこびとたち
    val reindeers = for (i <- 1 to 9) yield Reindeer("トナカイ" + i, Santa)
    val elves = for (i <- 1 to 10) yield Elf("こびと" + i, Santa)

    // 全てのアクターを開始
    Santa.start
    reindeers.foreach(_.start)
    elves.foreach(_.start)

    // 最初のメッセージを送る
    reindeers.foreach(_ ! 'play)
    elves.foreach(_ ! 'work)
  }
}

Santa オブジェクトでフィールド使っちゃってるのがちょっと負けた感ありますかね。
Actor で 2 つ List 渡すようにするとかすればもっときれいに書けるのかな?


ということで、クリスマスイヴを Scala と過ごした俺は勝ち組!
Scala は俺の嫁!
・・・はい、ごめんなさい。次はまたまた id:mzp です。超楽しみですね!正座して待機!!


そしてみなさんメリークリスマス!