前回のせんだみつおゲームで Fantom の Actor の使い方が何となく分かったので、サンタクロース問題でもやってみようと思う。クリスマスも近いしな。まあ、本物のプログラマには、そんなの関係ないけどな。
====
SantaClausProblem.main()は、サンタ、トナカイ、小人を生成して起動する
using concurrent class SantaClausProblem { Void main() { ActorPool pool := ActorPool() Santa santa := Santa(pool) Deer[] deers := (1..9).map |Int n->Deer| { Deer(pool, n, santa) } Elf[] elves := (1..10).map |Int n->Elf| { Elf(pool, n, santa) } deers.each |Deer deer| { deer.send("vacation") } elves.each |Elf elf| { elf.send("home") } while (!pool.isStopped) { Actor.sleep(1sec) } } }
Player は登場人物共通のコード。ActorUnderSanta はトナカイと小人の共通コード。
Actor └ Player ├ Santa └ ActorUnderSanta ├ Deer └ Elf
const class Player: Actor { new make(ActorPool pool) : super(pool) {} Void sleepRandom(Range r) { Actor.sleep(1sec* Int.random(r)) } } const class ActorUnderSanta: Player { const Int number const Santa santa new make(ActorPool pool, Int number, Santa santa) : super(pool) { this.number = number this.santa = santa } Str name() { this.typeof().name + number } }
トナカイと小人はこんな感じ
const class Deer: ActorUnderSanta { new make(ActorPool pool, Int number, Santa santa) : super(pool, number, santa) {} override Obj? receive(Obj? msg) { if ("vacation" == msg) { sleepRandom(1..10); santa.send(this) } return msg } } const class Elf: ActorUnderSanta { new make(ActorPool pool, Int number, Santa santa) : super(pool, number, santa) {} override Obj? receive(Obj? msg) { if ("home" == msg) { sleepRandom(2..15); santa.send(this) } return msg } }
サンタはこんな感じ
const class Santa: Player { new make(ActorPool pool) : super(pool) {} override Obj? receive(Obj? msg) { echo (((ActorUnderSanta)msg).name + " が来た") if (msg is Deer) addDeer((Deer)msg) else if (msg is Elf) addElf((Elf)msg) return msg } Void addDeer(Deer deer) { Deer[] deers := get("deers", (Deer[])[,]) deers.add(deer) wakeUpIfConditionIsMet } Void addElf(Elf elf) { Elf[] elves := get("elves", (Elf[])[,]) elves.add(elf) wakeUpIfConditionIsMet } Void wakeUpIfConditionIsMet() { if (9 == getDeers().size) deliverToys else if (3 <= getElves().size) meetInStudy } Void deliverToys() { echo("おもちゃを配る") sleepRandom(1..2) getDeers().each|Deer deer| { deer.send("vacation") } Actor.locals["deers"] = (Deer[])[,] } Void meetInStudy() { echo("小人と打ち合わせ") sleepRandom(1..2) Elf[] elves := getElves() elves.eachRange(0..2, |Elf elf| { elf.send("home") }) Actor.locals["elves"] = elves.removeRange(0..2) } Deer[] getDeers() { (Deer[])Actor.locals["deers"] } Elf[] getElves() { (Elf[])Actor.locals["elves"] } Obj get(Str key, Obj defaultValue) { Obj? result := Actor.locals[key] if (null == result) { result = defaultValue Actor.locals[key] = result } return result } }こんな結果が得られる
$ fan santaClausProblem.fan Deer6 が来た Deer1 が来た Elf2 が来た Elf9 が来た Deer9 が来た Deer2 が来た Deer8 が来た Deer3 が来た Elf3 が来た 小人と打ち合わせ Elf5 が来た Elf8 が来た Deer4 が来た Deer7 が来た Elf1 が来た 小人と打ち合わせ Deer5 が来た おもちゃを配る Elf2 が来た Elf7 が来た Elf9 が来た 小人と打ち合わせ Deer9 が来た Deer5 が来た Elf4 が来た Elf6 が来た Elf3 が来た 小人と打ち合わせ
0 件のコメント:
コメントを投稿