元の問題(Elixir) https://gist.github.com/cooldaemon/35acccd20d226ee33b639b17156242dc
Mission2
walk
関数を隠ぺいする方法もありますが、今回はそのまま。
Gumimaze.fs
module Gumimaze =
let read =
let withIndex xs = Array.mapi (fun i x -> x, i) xs
let lines = "maze.txt" |> System.IO.File.ReadAllLines
seq {
for line, y in withIndex lines do
for c, x in withIndex (line.ToCharArray ()) ->
(x, y), c
}
|> Map.ofSeq
let rec walk maze p walked pt =
let walked = Map.add p true walked
let aroundP =
let x, y = p
[x+1, y; x, y+1; x-1, y; x, y-1]
let checkAndWalk p =
match Map.containsKey p walked, Map.find p maze with
| true, _ -> []
| _ , 'W' -> []
| _ , '1' -> walk maze p walked (pt + 1)
| _ , 'G' -> [pt]
| _ , _ -> walk maze p walked pt
List.collect checkAndWalk aroundP
let solve maze =
let p = maze |> Map.pick (fun k v -> if v = 'S' then Some k else None)
walk maze p Map.empty 0 |> List.max
[<EntryPoint>]
let main argv =
read |> solve |> printfn "%A"
0
Mission3
MailboxProcessor
クラスでアクターモデルにするのが、お題に沿った回答になるでしょうか。ただし、以下の実装では余計に遅くなります。
Gumimaze.fs
module GumimazeAgent
open Microsoft.FSharp.Control
open System.Threading.Tasks
type ReducerMessage = Point of int | End
type CounterMessage = Inc | Dec
type WalkerMessage = Map<int*int, char> * (int * int) * Map<int*int, bool> * int;
let answer = new TaskCompletionSource<int>()
let reducer = MailboxProcessor<_>.Start(fun mb ->
let rec mainLoop max = async {
let! message = mb.Receive()
match message with
| Point pt -> return! mainLoop (if pt > max then pt else max)
| _ -> return answer.SetResult(max)
}
mainLoop 0
)
let counter = MailboxProcessor<_>.Start(fun mb ->
let rec mainLoop count = async {
let! message = mb.Receive()
let count =
match message with
| Inc -> count + 1
| Dec -> count - 1
if count > 0 then
return! mainLoop count
else
End |> reducer.Post(ReducerMessage.End)
}
mainLoop 0
)
let rec walkerBody = fun (mb: MailboxProcessor<_>) -> async {
let! msg = mb.Receive()
let walked = Map.add msg.Position true msg.Walked
let aroundP =
let x, y = msg.Position
[x+1, y; x, y+1; x-1, y; x, y-1]
for p in aroundP do
match Map.containsKey p walked, Map.find p msg.Maze with
| true, _ -> ()
| _ , 'W' -> ()
| _ , '1' ->
Inc |> counter.Post
let walker = MailboxProcessor<_>.Start(walkerBody)
(msg.Maze, p, walked, msg.Point + 1) |> walker.Post
| _ , 'G' ->
Point msg.Point |> reducer.Post
| _ , _ ->
Inc |> counter.Post
let walker = MailboxProcessor<_>.Start(walkerBody)
(msg.Maze, p, walked, msg.Point) |> walker.Post
Dec |> counter.Post
}
let walker = MailboxProcessor<_>.Start(walkerBody)
let withIndex xs =
Array.mapi (fun i x -> x, i) xs
let read =
let lines = "maze.txt" |> System.IO.File.ReadAllLines
seq {
for line, y in withIndex lines do
for c, x in withIndex (line.ToCharArray ()) ->
(x, y), c
}
|> Map.ofSeq
let solve maze =
let p = maze |> Map.pick (fun k v -> if v = 'S' then Some k else None)
Inc |> counter.Post
(maze, p, Map.empty, 0) |> walker.Post
[<EntryPoint>]
let main argv =
read |> solve
answer.Task.Result |> printfn "%A"
0