argius note

プログラミング関連

ポーカーの役判定 (改良版)

1/17に作ったものを元に、単純で明解にしつつ、かつ、よりHaskellっぽく(なってるかな?)させてみました。
あと、個人的なこだわりで、バックスラッシュと"$"を排除しています。そのためにわざわざ内包表記にしていると見受けられる部分もありますが、そのせいで読みにくくはなってないと思います。

import System
import Maybe
import List

main = getArgs >>= putStrLn . pokerHand . head

pokerHand :: String -> String
pokerHand cards
    | royalflush             = "Royal flush"
    | straight && flush      = "Straight flush"
    | flush                  = "Flush"
    | straight               = "Straight"
    | groups == [1, 4]       = "Four of a kind"
    | groups == [2, 3]       = "Full house"
    | groups == [1, 1, 3]    = "Three of a kind"
    | groups == [1, 2, 2]    = "Two pair"
    | groups == [1, 1, 1, 2] = "One pair"
    | otherwise              = "No Pair"
    where
      royalflush :: Bool
      royalflush = flush && ranks == "AJKQT"
      flush :: Bool
      flush = length (group suits) == 1
      straight :: Bool
      straight = any (rankNumbers ==) sequences
      groups :: [Int]
      groups = sort [ length x | x <- group rankNumbers ]
      suits :: String
      suits = pickupBy even cards
      ranks :: String
      ranks = sort (pickupBy odd cards)
      rankNumbers :: [Int]
      rankNumbers = map rankNumber ranks
      rankNumber :: Char -> Int
      rankNumber rank
          | isNothing index = -1
          | otherwise       = fromJust index + 1
          where
            index = elemIndex rank "A23456789TJQK"

pickupBy :: (Int -> Bool) -> String -> String
pickupBy f cards = [ cards !! x | x <- [0..9], f x ]

sequences :: [[Int]]
sequences = [ take 5 x | x <- tails [1..13], length(x) >= 5 ]