Life Goes On

まあまあだけど楽しんでる方です

54問目

http://projecteuler.net/index.php?section=problems&id=54
ポーカーの手を二人分千組含むファイルから、一人目のプレイヤーが勝つ組がいくつあるかを求める。
それぞれの手についてワンペアは1点、ロイヤルフラッシュは9点といった点数をつけ、その大小を比べています。点数が同じときは手に含まれるカードの数字を順番に比べていきます。
実際のファイルにはロイヤルフラッシュもストレートフラッシュもありませんでした。残念。

import Data.Char
import Data.List
import Data.Ord

main = do
  cs <- readFile "poker.txt"
  print $ length $ euler054 $ map ((splitAt 5) . (map pre) . words) $ lines cs

pre :: String -> (Int, Char)
pre [n, c] = (n', c)
  where n'
      | (n == 'A') = 14
      | (n == 'K') = 13
      | (n == 'Q') = 12
      | (n == 'J') = 11
      | (n == 'T') = 10
      | otherwise = digitToInt n

euler054 :: [([(Int, Char)], [(Int, Char)])] -> [([Int], [Int])]
euler054 = filter p1win . map (\ (a, b) -> (score $ order a, score $ order b))

order :: [(Int, Char)] -> ([[Int]], [Char])
order xs = (reverse $ sortBy (comparing length) $ group $ sort $ fst $ unzip xs,
  nub $ snd $ unzip xs)

p1win :: ([Int], [Int]) -> Bool
p1win (n1:ns1, n2:ns2) = if (n1 > n2)
  then True
  else if (n1 < n2)
    then False
    else p1win (ns1, ns2)

score :: ([[Int]], [Char]) -> [Int]
score (ns, cs) = if (isFlush cs)
    then if (isStraight ns)
      then if (isRoyal ns)
        then 9 : map head ns -- Royal Flush
        else 8 : map head ns -- Straight Flush
      else 5 : map head ns -- Flush
    else if ((map length ns) == [1,1,1,1,1])
      then if (isStraight ns)
        then 4 : map head ns -- Straight
        else 0 : map head ns -- High Card
      else if ((map length ns) == [2,1,1,1])
        then 1 : map head ns -- One Pair
        else if ((map length ns) == [2,2,1])
          then 2 : map head ns -- Two Pairs
          else if ((map length ns) == [3,1,1])
            then 3 : map head ns -- Three of a Kind
            else if ((map length ns) == [3,2])
              then 6 : map head ns -- Full House
              else 7 : map head ns -- Four of a Kind

isStraight :: [[Int]] -> Bool
isStraight (n:ns) = ns == [ [(head n) - i] | i <- [1..4] ]

isFlush :: [Char] -> Bool
isFlush cs = length cs == 1

isRoyal:: [[Int]] -> Bool
isRoyal (n:ns) = head n == 10