F#でActor的にサンタクロース問題書いたのをWPFでアニメーションしてみた。
詳しく知らないけれどエルフがサンタの元に3人集まったら話し合いをする。それかトナカイが6人集まったら配達する。早い者勝ちでダメだった方は追い出される。
アニメーションするといい感じですね。
メインロジックは下のような感じ。
他のナイスなソースは見てないのできっともっといい感じの書き方があるはず…
※少し整理したので更新
let spawnSanta santaNum elfNum rdeerNum (notifyE:Event<_>)= let notify e=notifyE.Trigger e let santas=ref [||]:Actor<_>[] ref let mutable elfs=[||]//とりあえず残しとく let mutable rdeers=[||] //santa---------- let santa id=fun (actor:Actor<_>)-> let rec loop stat elfs rdeers=async{ let accept newId newAccepts others (r:AsyncReplyChannel<_>) nEvtF limit getout startX onFreeNext onXNext= r.Reply FreeTime notify <|nEvtF(newId,id,List.length newAccepts) if List.length newAccepts<limit then onFreeNext else startX() others|>List.iter(fun (o:Actor<_>)->o.Post<|getout) onXNext let toFreeTime xs evt= xs|>List.iter(fun (e:Actor<_>)->e.Post <|evt) notify<|SantaStateChanged(id,FreeTime) loop FreeTime [] [] let! msg=actor.Receive() let next=msg|>function |ElfVisit (elf,elfId,r)->stat|>function |FreeTime-> //accept elf let elfs=elf::elfs accept elfId elfs rdeers r AcceptElf meetingNum (ReindeerEndVisit Getout) startMeeting (loop FreeTime elfs rdeers) (loop OnMeeting elfs []) |_->r.Reply stat loop stat elfs rdeers |ReindeerVisit(rdeer,rdeerId,r)->stat|>function |FreeTime-> //accept reindeer let rdeers=rdeer::rdeers accept rdeerId rdeers elfs r AcceptReindeer deliveryNum (ElfEndVisit Getout) startDelivering (loop FreeTime elfs rdeers) (loop OnDelivering [] rdeers) |_->r.Reply stat loop stat elfs rdeers |EndMeeting-> toFreeTime elfs (ElfEndVisit MeetingEnd) |EndDelivering->toFreeTime rdeers (ReindeerEndVisit DeliveringEnd) return! next } and startMeeting()=startX OnMeeting meetingTime EndMeeting and startDelivering()=startX OnDelivering deliveryTime EndDelivering and startX stat wait evt= async{notify <|SantaStateChanged(id,stat) do! Async.Sleep(wait) actor.Post evt }|>Async.Start loop FreeTime [] [] //elf---------- let elf id=fun (actor:Actor<_>)-> let rec loop()=async{ let notify_loop e= async{notify e do! Async.Sleep(1000+rnd.Next 2000) return! loop()} let nSanta=rnd.Next santaNum notify<|ElfVisitSanta (id,nSanta+1) do! Async.Sleep(1000) let! sStat= (!santas).[nSanta].PostAndAsyncReply(fun r->ElfVisit(actor,id,r)) let next=sStat|>function |OnMeeting-> notify_loop<|ElfGoHome (id, Busy) |OnDelivering-> notify_loop<|ElfGoHome (id, Absent) |FreeTime->async{ let! ElfEndVisit(reason)=actor.Receive() return! notify_loop<|ElfGoHome (id,reason) } return! next} loop() //rdeer---------- let rdeer id=fun (actor:Actor<_>)-> let rec loop()=async{ let notify_loop e= async{notify e do! Async.Sleep(1000+rnd.Next 2000) return! loop()} let next= //eat kusa? if rnd.Next rdeerSelect=0 then notify_loop<|ReindeerEating id else async{ let nSanta=rnd.Next santaNum notify<|ReindeerVisitSanta (id,nSanta+1) do! Async.Sleep(1000) let! sStat= (!santas).[nSanta].PostAndAsyncReply(fun r->ReindeerVisit(actor,id,r)) let next= sStat|>function |OnMeeting-> notify_loop<|ReindeerGoHome (id, Busy) |OnDelivering-> notify_loop<|ReindeerGoHome (id, Absent) |FreeTime->async{ let! ReindeerEndVisit(reason)=actor.Receive() return! notify_loop<|ReindeerGoHome (id,reason) } return! next} return! next } loop() santas:=[|1..santaNum|]|>Array.map (santa>>Actor<_>.Start) elfs<-[|1..elfNum|]|>Array.map (elf>>Actor<_>.Start) rdeers<-[|1..rdeerNum|]|>Array.map (rdeer>>Actor<_>.Start) >Actor<_>.Start)
ソースはこちらGitHub - omanuke/santaclaus