argius note

プログラミング関連

ポーカーの役判定

最近ちょっとHaskellやる気が出てきたので、昨日の(どう書く?orgの)Ruby版をベースにHaskellで書いてみました。ふつけるの第8章までに登場するもの以外は、たぶんほとんど使っていません。
自分のHaskell力では、今のところこれが精一杯かな。なので、あまりきれいとは言えないコードですが、この状態で上げてしまいます。

import System
import List
import Char

main = getArgs >>= print . pokerHand . head

pokerHand :: String -> String
pokerHand s -- cards
    | isFlush s && isRoyalStraight s = "Royal Flush"
    | isFlush s && isStraight s = "Straight Flush"
    | isFlush s = "Flush"
    | isStraight s = "Straight"
    | includeNLength s 4 = "Four of a kind"
    | all (includeNLength s) [2, 3] = "Full house"
    | includeNLength s 3 = "Three of a kind"
    | includeNLength s 2 && (length . group . toNumbers) s == 3 = "Two pair"
    | includeNLength s 2 = "One Pair"
    | otherwise = "No Pair"

includeNLength :: String -> Int -> Bool
includeNLength cards n = any (\i -> length i == n) $ group $ toNumbers cards

isRoyalStraight :: String -> Bool
isRoyalStraight cards = sort (toNumbers cards) == [1, 10, 11, 12, 13]

isFlush :: String -> Bool
isFlush cards = (length . group . toSuits) cards == 1

isStraight :: String -> Bool
isStraight cards = any (\i -> take 5 i == toNumbers cards) $ tails [1..13]
                   
toSuits :: String -> String
toSuits cards = [snd x | x <- filter (\i -> even $ fst i) $ zip [0..] cards]

toNumbers :: String -> [Int]
toNumbers cards = sort [ rankToInt(snd x) | x <- filter (\i -> odd $ fst i) $ zip [0..] cards]

rankToInt :: Char -> Int
rankToInt rank
    | rank == 'A' = 1
    | rank == 'T' = 10
    | rank == 'J' = 11
    | rank == 'Q' = 12
    | rank == 'K' = 13
    | isDigit rank = ord rank - 48
    | otherwise = 0