challenge ポーカーの役判定

引数に手札を与えると、ポーカーの役を表示するプログラムを作ってください。

条件:

  • スートはS,D,H,C、ランクはA,2~9,T,J,Q,Kのそれぞれ一文字で表します。
  • 手札は S2D5H3CQS9 のように10文字で指定されます。特にソートはされていません。
  • 手札にジョーカーは含まれません。
  • ストレートで取りうるランクの種類はA2345, 23456 ... 9TJQK, TJQKAの10種類で、JQKA2のようにK-A-2をまたぐものはストレートではありません。

実行例:

% ./poker SQSJSASKST
Royal flush

% ./poker D9D7D6D5D8
Straight flush

% ./poker C2D2S2H3H2
Four of a kind

% ./poker C2D3S2H3H2
Full house

% ./poker S9S4S8STSJ
Flush

% ./poker C4H7D5S6H3
Straight

% ./poker S6H6C5DQC6
Three of a kind

% ./poker S6HQC5DQC6
Two pair

% ./poker S6H4C5DQC6
One pair

% ./poker SJSQSKSAC2
No pair

お題にしようと思っていたのに間違えてしまいました。今から変更可能でしょうか?

(説明)
当初間違ってトピックに投稿していたので、このようなコメントを付けていたのですが、
このコメントに気づいた管理人さんにお題に移していただきました。
(最初の2つだけ投稿日時が早いのはそのためです)

Posted feedbacks - Haskell

ストレートの判定がなかなかきれいにまとまりませんね。ソートしておいて隣り合う数の差で判断してみましたが……うーん。

 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
import Data.List as List

hand :: String -> (String, Bool)
hand cards =
    (case kinds of
       [1, 4] -> "Four of a kind"
       [2, 3] -> "Full house"
       [1, 1, 3] -> "Three of a kind"
       [1, 2, 2] -> "Two pair"
       [1, 1, 1, 2] -> "One pair"
       otherwise ->
           case rdiff of
               [1, 1, 1, 1] | head ranks == 10 && isFlush -> "Royal"
                            | True -> "Straight"
               [1, 1, 1, 9] -> "Straight"
               otherwise -> "No pair"
    , isFlush)
    where suits = List.nub [cards !! n | n <- [0,2..8]]
          isFlush = length suits == 1
          ranks = List.sort [rankToInt $ cards !! n | n <- [1,3..9]]
          rankToInt r = case List.elemIndex r "23456789TJQKA" of Just n -> n+2
          kinds = List.sort $ map length $ List.group ranks
          rdiff = zipWith (-) (tail ranks) ranks

main = mapM test ["SQSJSASKST", "D9D7D6D5D8", "C2D2S2H3H2", "C2D3S2H3H2",
                  "S9S4S8STSJ", "C4H7D5S6H3", "S6H6C5DQC6", "S6HQC5DQC6",
                  "S6H4C5DQC6" ,"SJSQSKSAC2"]
    where test s = putStrLn (s ++ " => " ++ (showHand $ hand s))
          showHand ("No pair", True) = "Flush"
          showHand (s, True) = s ++ " flush"
          showHand (s, False) = s

data使いたがりなhaskellコード。
 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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import System
import List(sort,group,elemIndex)
import Maybe(fromJust)

data Card = Card {suits::Suits,rank::Int} deriving Show
data Suits = S | D | H | C deriving (Read,Eq,Show)
data Hand = RF | STF | FK | FH | F | ST | TK | TP | OP | NO

read_cards :: String -> [Card]
read_cards str = map read_card $ split_2 str
    where 
      read_card [s,r] = Card (read [s])
                        (fromJust (elemIndex r "DD23456789TJQKA"))
      split_2 [] = []
      split_2 list = let (hd,rest) = splitAt 2 list in  hd : split_2 rest

instance Show Hand where
    show h = case h of
               RF  -> "Royal flush"
               STF -> "Straight flush"
               FK  -> "Four of a kind"
               FH  -> "Full House"
               F   -> "Flush"
               ST  -> "Straight"
               TK  -> "Three of a kind"
               TP  -> "Two pair"
               OP  -> "One pair"
               NO  -> "No pair"

hand :: [Card] -> Hand
hand  cards
    | check_st  && check_flush  && head rank_seq == 10 = RF
    | check_st  && check_flush  = STF
    | max_group == 4 = FK
    | sort group_count == [2,3] = FH
    | check_flush  = F
    | check_st = ST
    | max_group ==  3 = TK
    | pair_count == 2 = TP
    | pair_count == 1 = OP
    | otherwise = NO
    where
      rank_seq = sort $ map rank cards
      groups = group rank_seq
      group_count = map length groups
      max_group = foldl1 max group_count
      pair_count = length (filter (\l->length l == 2) groups)

      check_flush = all (\c->suits c==suits (head cards)) cards
      check_st = normal || rank_seq == [2,3,4,5,14]
          where
            normal = and $ zipWith (\a b->a-b == head rank_seq) rank_seq [0..]

main = getArgs >>= print . hand . read_cards . head

-- Test

test = zip testlist (map (hand .read_cards) testlist)

testlist = ["SQSJSASKST",
            "D9D7D6D5D8",
            "C2D2S2H3H2",
            "C2D3S2H3H2",
            "S9S4S8STSJ",
            "C4H7D5S6H3",
            "S6H6C5DQC6",
            "S6HQC5DQC6",
            "S6H4C5DQC6",
            "SJSQSKSAC2"]

Index

Feed

Other

Link

Pathtraq

loading...