第12回オフラインリアルタイムどう書くの参考問題をF#で

[問題はこちら](http://qiita.com/Nabetani/items/1de39df381dfeee305ab)。

3時間ぐらいかかってしまった。挙句、パターンマッチと言う名の条件分岐の嵐に。

```fsharp:doukaku12pre.fs
open System

type Area      = N | S | E | W
type Direction = U | D | L | R

let move (  x,  y) = function
  | L -> (x-1,  y)
  | U -> (x,  y-1)
  | R -> (x+1,  y)
  | D -> (x,  y+1)

let turnLeft  = function D->R | R->U | U->L | L->D
let turnRight = function L->U | U->R | R->D | D->L

let moveOnMap a p d =
  match a with
  | N -> match (p,d) with
         | ((_,0),U) -> None
         | ((_,2),D) -> None
         | ((0,y),L) -> Some (W,    (2,y), L)
         | ((4,y),R) -> Some (E,    (0,y), R)
         | (    _,_) -> Some (a, move p d, d)
  | S -> match (p,d) with
         | ((_,0),U) -> None
         | ((_,2),D) -> None
         | ((0,y),L) -> Some (W,  (2-y,2), U)
         | ((8,y),R) -> Some (E,  (  y,2), U)
         | (    _,_) -> Some (a, move p d, d)
  | E -> match (p,d) with
         | ((2,_),R) -> None
         | ((_,0),U) -> None
         | ((0,y),L) -> Some (N,    (4,y), L)
         | ((x,2),D) -> Some (S,    (8,x), L)
         | (    _,_) -> Some (a, move p d, d)
  | W -> match (p,d) with
         | ((0,_),L) -> None
         | ((_,0),U) -> None
         | ((2,y),R) -> Some (N,  (0,  y), R)
         | ((x,2),D) -> Some (S,  (0,2-x), R)
         | (    _,_) -> Some (a, move p d, d)

let map a (x,y) =
  match a with
  | N -> [|"DEFGH";"OPQRS";"Zabcd"|].[y].[x]
  | S -> [|"jmpsvy147";"ilorux036";"hknqtwz25"|].[y].[x]
  | E -> [|"IJK";"TUV";"efg"|].[y].[x]
  | W -> [|"ABC";"LMN";"WXY"|].[y].[x]

let (|Left|_|) c =
  if c = 'L' then Some Left  else None
let (|Right|_|) c =
  if c = 'R' then Some Right else None
let (|Forward|_|) (c: char) =
  let i = "0123456789abcdef".IndexOf(c)
  if i < 0 then None else Some i

let rec parse a p d = function
  | []    -> []
  | c::cs -> match c with
             | Left      -> parse a p (turnLeft  d) cs
             | Right     -> parse a p (turnRight d) cs
             | Forward i -> go i a p d cs
             | _         -> failwith "invalid input"
and go i a p d cs =
  match i with
  | 0 -> parse a p d cs
  | _ -> match (moveOnMap a p d) with
         | Some (a',p',d') -> map a' p' :: go (i-1) a' p' d' cs
         | None            -> ['?']

let start cs = map W (0,0) :: parse W (0,0) R cs

let solve (s: string) =
  s.ToCharArray()
  |> Array.toList
  |> start
  |> List.toArray
  |> fun x -> new string(x)

(* for test *)

type TestResult = Success | Failure

let test target expected =
  let actual = solve target
  printfn "%A" (if expected = actual then Success else Failure)

[<EntryPoint>]
let main args =
  test "2RcL3LL22" "ABCNYjmpsvy147edcbcdef"
  test "L3R4L5RR5R3L5" "A?"
  test "2ReLLe" "ABCNYjmpsvy147eTITe741yvspmjYNC"
  test "1ReRRe" "ABMXilorux036fUJUf630xuroliXMB"
  test "ReRRe" "ALWhknqtwz25gVKVg52zwtqnkhWLA"
  test "f" "ABCDEFGHIJK?"
  test "Rf" "ALWhknqtwz25gVK?"
  test "1Rf" "ABMXilorux036fUJ?"
  test "2Rf" "ABCNYjmpsvy147eTI?"
  test "aR1RaL1LaR1R2L1L2" "ABCDEFGHIJKVUTSRQPONMLWXYZabcdefg567432"
  test "2R1R2L1L2R1R2L1L2R1R2L1L2R1R2L1L2" "ABCNMLWXYjihklmponqrsvutwxy"
  test "2R4R2L4L2R4R2L4L2R4R2L4L2" "ABCNYjmlknqtwxy147efgVK?"
  test "R1L2R4R2L4L2R4R2L4L2R4R2L4L2" "ALMNYjmponqtwz0147eTUVK?"
  test "R2L2R4R2L4L2R4R2L4L2R4R2L4L2" "ALWXYjmpsrqtwz2347eTIJK?"
  test "R3L2R4R2L4L2R4R2L4L2R4R2L4L2" "ALWhijmpsvutwz2567eTI?"
  test "R5L2L5L1LaR1L4L5" "ALWhknopmjYNCBMXilorux0325gVKJIHGF"
  test "1R2L4L2R4R2L4L2R4" "ABMXYZabQFGHIJUfg?"
  test "2R2L4L2R4R2L4L2R4" "ABCNYZabcRGHIJKVg?"
  test "3R2L4L2R4R2L4L2R4" "ABCDOZabcdSHIJK?"
  test "4R2L4L2R4R2L4L2R4" "ABCDEPabcdeTIJK?"
  test "5R2L4L2R4R2L4L2R4" "ABCDEFQbcdefUJK?"
  test "LLL1RRR1LLL1RRR2R1" "ALMXYZ?"
  test "R3RRR3" "ALWhij?"
  test "1LLL4RRR1LR1RL1" "ABMXilm?"
  test "R2L1R2L1R3R4" "ALWXilmpsvut?"
  test "7R4f47LLLc6R9L" "ABCDEFGHSd?"
  test "5RR868L8448LL4R6" "ABCDEFEDCBA?"
  test "42Rd1RLLa7L5" "ABCDEFGRc?"
  test "RRLL6RLR1L5d12LaLRRL529L" "ABCDEFGRSTUV?"
  test "RLR7L6LL1LRRRcRL52R" "ALWhknqtuv?"
  test "1RLR8RLR1R437L99636R" "ABMXiloruxwtqnkhWLA?"
  test "LLL2L3La9Le5LRR" "ALWXYZOD?"
  test "R1LcRR491" "ALMNOPQRSTUV?"
  test "R8L1R1R512L8RLLReRf" "ALWhknqtwx0z?"
  test "1RcL8f1L29a5" "ABMXilorux036fedcbaZYXW?"
  test "R822LeL46LL39LL" "ALWhknqtwz25gfedcbaZYXW?"
  test "9R3L5LRRLb5R3L7cLLLR4L" "ABCDEFGHIJUf65?"
  test "7LLRRR2R3R69Lf76eR2L" "ABCDEFGHSdcbaPE?"
  test "8RRRLL3Le" "ABCDEFGHITe765?"
  test "8R5RLL6LbL4LL5bL" "ABCDEFGHITe7410z?"
  test "6LR2R1LR5LRLRL484L63" "ABCDEFGHITe741yxw?"
  0
```