1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#light
open List

let poker cs =
  let is_all_elems_same l = tryfind ((<>) (hd l)) (tl l) |> Option.is_none
  let tally l =
    let h = Hashtbl.create (length l)
    for x in l do
      if Hashtbl.mem h x then Hashtbl.replace h x (Hashtbl.find h x + 1)
                         else Hashtbl.add     h x 1
    h
  (* 手札の情報をスートとランクの 2 つの情報に分離 *)
  let maxi = String.length cs - 1
  let suit = [for i in 0..2..maxi -> cs.[i]]
  let rank = [for i in 1..2..maxi -> String.index "A23456789TJQK" cs.[i] + 1]
             |> sort (-)
  (* 判定基準となる条件役を算出 *)
  let rst = rank = [1;10;11;12;13]
  let flu = is_all_elems_same suit
  let str = is_all_elems_same (mapi (fun i x -> x - i) rank)
  let pnt = [for p in (tally rank) when p.Value > 1 -> p.Value] |> sort (-)
  (* 役判定 *)
  match rst, flu, str, pnt with
    true, true, _,    _     -> "Royal flush"
  | _,    true, true, _     -> "Straight flush"
  | _,    _,    _,    [4]   -> "Four of a kind"
  | _,    _,    _,    [2;3] -> "Full house"
  | _,    true, _,    _     -> "Flush"
  | _,    _,    true, _     -> "Straight"
  | _,    _,    _,    [3]   -> "Three of a kind"
  | _,    _,    _,    [2;2] -> "Two pair"
  | _,    _,    _,    [2]   -> "One pair"
  | _ -> "No pair"

let _ =
  let ($) f g x = f (g x)
  ["SQSJSASKST";"D9D7D6D5D8";"C2D2S2H3H2";"C2D3S2H3H2";"S9S4S8STSJ"
   "C4H7D5S6H3";"S6H6C5DQC6";"S6HQC5DQC6";"S6H4C5DQC6";"SJSQSKSAC2"]
  |> iter (printfn "%s" $ poker)