fork(7) download
  1. // タンピン二盃口が成立しているかを判定する。
  2. // 鳴き、カン、七対子形、国士形はタンピン二盃口と両立しないので最初から考慮しない。
  3. // ツモピンフあり、大車輪ありとする。
  4.  
  5. open System.Text.RegularExpressions
  6. open System.Collections.Generic
  7.  
  8. let input() =
  9. printfn "Manzu:1m-9m Pinzu:1p-9p Souzu:1s-9s Jihai:1j-7j (The last input means 'Agari Hai')"
  10. let inp = System.Console.ReadLine()
  11. match Regex.Match(inp, @"\A\s*(?:([1-9][mps]|[1-7]j)\s*){14}\Z") with
  12. | m when m.Success ->
  13. let hais =
  14. m.Groups.[1].Captures |> Seq.cast<Capture>
  15. |> Seq.map (fun c -> c.Value.[1], int c.Value.[.. 0]) |> Seq.toList
  16. let agariHai = hais |> List.rev |> List.head
  17. let haiCountMap = hais |> Seq.countBy id |> Map.ofSeq
  18. if haiCountMap |> Map.forall (fun _ -> (>=) 4) then Some(haiCountMap, agariHai) else None
  19. | _ -> None
  20.  
  21. let getAllMentsu haiCountMap agariHai =
  22. let tryRemoveCount n key map =
  23. map |> Map.tryFind key |> Option.bind (function
  24. | c when c > n -> map |> Map.add key (c - n) |> Some
  25. | c when c = n -> map |> Map.remove key |> Some
  26. | _ -> None)
  27.  
  28. let tryTakeSame count haiCountMap (hai : char * int) =
  29. tryRemoveCount count hai haiCountMap |> Option.map (fun m -> Map.ofList [hai, count], m)
  30.  
  31. let tryTakeShuntsu haiCountMap (suit, num) =
  32. if suit = 'j' then None else
  33. (Some haiCountMap, [num .. num + 2])
  34. ||> List.fold (fun m n -> m |> Option.bind (tryRemoveCount 1 (suit, n)))
  35. |> Option.map (fun m -> Map.ofList [for n in num .. num + 2 -> (suit, n), 1], m)
  36.  
  37. let memo = HashSet(HashIdentity.Structural)
  38. let rec getMentsu haiCountMap mentsus =
  39. if memo.Add(haiCountMap, List.sort mentsus) |> not then Seq.empty
  40. elif Map.isEmpty haiCountMap then
  41. let mentsus = mentsus |> List.rev
  42. mentsus |> Seq.mapi (fun i m -> i, m) |> Seq.choose (fun (i, mentsu) ->
  43. tryRemoveCount 1 agariHai mentsu |> Option.map (fun m ->
  44. mentsus |> List.mapi (fun j mentsu -> if j = i then m else mentsu)))
  45. |> Seq.map (fun (jantou::rest) -> jantou::List.sortBy Seq.length rest)
  46. elif List.isEmpty mentsus then
  47. haiCountMap |> Map.toSeq |> Seq.choose (fst >> tryTakeSame 2 haiCountMap)
  48. |> Seq.collect (fun (jantou, rest) -> getMentsu rest [jantou])
  49. else
  50. haiCountMap |> Map.toSeq |> Seq.collect (fun (hai, _) ->
  51. [tryTakeSame 3; tryTakeShuntsu] |> Seq.choose (fun f-> f haiCountMap hai)
  52. |> Seq.collect (fun (mentsu, rest) -> getMentsu rest (mentsu::mentsus)))
  53.  
  54. getMentsu haiCountMap []
  55.  
  56. let isYaochuu = function 'j', _ | _, 1 | _, 9 -> false | _ -> true
  57.  
  58. let isTanyao agariHai mentsus =
  59. mentsus |> List.forall (Map.toSeq >> Seq.forall (fst >> isYaochuu)) && isYaochuu agariHai
  60.  
  61. let isPinfu agariHai (jantou::taatsu::rest) =
  62. let isSequence count mentsu =
  63. let hais = mentsu |> Map.toSeq |> Seq.toList
  64. List.length hais = count
  65. && hais |> Seq.map (fst >> snd) |> Seq.sort |> Seq.pairwise
  66. |> Seq.map ((<||) (-)) |> Seq.forall ((=) -1)
  67.  
  68. jantou |> Map.forall (fun _ -> (=) 2) && taatsu |> isSequence 2
  69. && rest |> List.forall (isSequence 3)
  70.  
  71. let isRyanpeikou agariHai (jantou::taatsu::rest) =
  72. let mentsus =
  73. if jantou |> Map.forall (fun _ -> (=) 1) then taatsu::rest else
  74. let c = Map.tryFind agariHai taatsu in Map.add agariHai (defaultArg c 0 + 1) taatsu::rest
  75. let counts = mentsus |> Seq.countBy id |> Seq.toList
  76. (List.length counts = 2 && counts |> List.forall (snd >> (=) 2))
  77. || (List.length counts = 1 && counts |> List.forall (snd >> (=) 4))
  78.  
  79. let isDaisharin agariHai =
  80. List.collect (Map.toList >> List.collect (fun (hai, count) -> List.replicate count hai))
  81. >> (fun hais -> agariHai::hais) >> Seq.countBy id >> Seq.toList >> List.unzip
  82. >> fun (hais, counts) ->
  83. let suits, nums = List.unzip hais
  84. suits |> Seq.distinct |> Seq.length |> (=) 1 && Seq.head suits <> 'j'
  85. && nums |> List.forall (fun num -> 1 < num && num < 9)
  86. && counts |> List.forall ((=) 2)
  87.  
  88. let main() =
  89. match input() with
  90. | Some(haiCountMap, agariHai) ->
  91. getAllMentsu haiCountMap agariHai |> Seq.exists (fun mentsus ->
  92. [isTanyao agariHai; isPinfu agariHai; isRyanpeikou agariHai; isDaisharin agariHai >> not]
  93. |> List.forall ((|>) mentsus))
  94. |> printfn "%O"
  95. | _ -> printfn "Illegal input"
  96.  
  97. main()
Success #stdin #stdout 0.3s 13880KB
stdin
2m2m3m3m4m4m 5p5p 6s6s7s7s8s 8s
stdout
Manzu:1m-9m Pinzu:1p-9p Souzu:1s-9s Jihai:1j-7j (The last input means 'Agari Hai')
True