Guest User

Untitled

a guest
Jul 17th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.18 KB | None | 0 0
  1. module Poker (Value(..), Suit(..), Card(..), Hand, hand) where
  2. import Control.Exception
  3. import Data.List
  4.  
  5. data Value = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
  6. | Jack | Queen | King | Ace deriving (Eq, Ord, Bounded, Enum, Show)
  7. data Suit = Clubs | Diamonds | Hearts | Spades deriving (Eq, Show)
  8. data Card = Card {val :: Value, suit :: Suit} deriving (Eq, Show)
  9.  
  10. data HandType = HighCard
  11. | OnePair
  12. | TwoPairs
  13. | ThreeOfAKind
  14. | Straight
  15. | Flush
  16. | FullHouse
  17. | FourOfAKind
  18. | StraightFlush
  19. deriving (Eq, Ord, Show)
  20. data Hand = Hand [Card] deriving (Eq, Show)
  21.  
  22. hand :: [Card] -> Hand
  23. hand cards =
  24. assert (length cards == 5) -- A poker hand most consist of five cards
  25. $ assert (nub cards == cards) -- No two cards may have the same suit/val
  26. $ Hand $ sortBy (\x y -> val x `compare` val y) cards -- Normalize
  27.  
  28. {--
  29. valCounts takes a Hand and returns a list of (Value, Count) pairs ordered
  30. first by count greatest to least and then by value also greatest to least.
  31.  
  32. Example:
  33. valCounts (hand [Card Two Clubs, Card Two Hearts, Card King Diamonds,
  34. Card King Spades, Card Ace Spades])
  35. == [(King, 2), (Two, 2), (Ace, 1)] -- The result of this expression is True
  36. --}
  37. valCounts :: Hand -> [(Value, Int)]
  38. valCounts (Hand a) =
  39. sortBy (\x y -> snd y `compare` snd x) -- Put highest counts first
  40. $ nubBy sameVal -- Only keep unique vals and their counts in the list
  41. $ reverse -- Make nub keep only the highest count and put high vals first
  42. $ scanl1 (\x y -> if sameVal x y then (fst y, snd x + 1) else y) -- inc cnt
  43. [(val x, 1) | x <- a] -- Ignore suits, initialize counts to 1
  44. where sameVal x y = fst x == fst y
  45.  
  46. isAceLowStraight :: Hand -> Bool
  47. isAceLowStraight (Hand a) = map val a == [Two, Three, Four, Five, Ace]
  48.  
  49. isStraight :: Hand -> Bool
  50. isStraight h@(Hand a)
  51. | isAceLowStraight h = True
  52. | otherwise =
  53. vals == take 5 [head vals..] -- equal to straight starting at head?
  54. where vals = map val a
  55.  
  56. isFlush :: Hand -> Bool
  57. isFlush (Hand a) = (length $ nub $ map suit a) == 1 -- Super easy
  58.  
  59. handType :: Hand -> HandType
  60. handType a
  61. | isStraight a && isFlush a = StraightFlush
  62. | count 0 == 4 = FourOfAKind
  63. | count 0 == 3 && count 1 == 2 = FullHouse
  64. | isFlush a = Flush
  65. | isStraight a = Straight
  66. | count 0 == 3 = ThreeOfAKind
  67. | count 0 == 2 && count 1 == 2 = TwoPairs
  68. | count 0 == 2 = OnePair
  69. | otherwise = HighCard
  70. where count = (map snd (valCounts a) !!)
  71.  
  72. instance Ord Hand where
  73. compare a b
  74. | handType a < handType b = LT
  75. | handType a > handType b = GT
  76. | otherwise =
  77. map fst (valCounts a') `compare` map fst (valCounts b')
  78. where
  79. fixAceLow h@(Hand x) = if isAceLowStraight h
  80. then Hand $ drop 4 x ++ take 4 x -- Breaks Hand ordering
  81. else h
  82. a' = fixAceLow a
  83. b' = fixAceLow b
Add Comment
Please, Sign In to add comment