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