aboutsummaryrefslogtreecommitdiff
path: root/2023/07-Camel_Cards/first.hs
diff options
context:
space:
mode:
Diffstat (limited to '2023/07-Camel_Cards/first.hs')
-rw-r--r--2023/07-Camel_Cards/first.hs110
1 files changed, 110 insertions, 0 deletions
diff --git a/2023/07-Camel_Cards/first.hs b/2023/07-Camel_Cards/first.hs
new file mode 100644
index 0000000..0afd4a7
--- /dev/null
+++ b/2023/07-Camel_Cards/first.hs
@@ -0,0 +1,110 @@
+-- requires cabal install --lib megaparsec parser-combinators
+module Main (main) where
+
+import Control.Applicative.Permutations
+import Control.Monad (void, when)
+import Data.Char qualified as C
+import Data.Either
+import Data.Functor
+import Data.List qualified as L
+import Data.Map qualified as M
+import Data.Maybe
+import Data.Set qualified as S
+import Data.Void (Void)
+import Text.Megaparsec
+import Text.Megaparsec.Char
+
+import Debug.Trace
+
+exampleExpectedOutput = 6440
+
+data Card = Two | Three | Four | Five | Six | Seven | Eight | Nine | T | J | Q | K | A deriving (Eq, Ord)
+
+instance Show Card where
+ show Two = "2"
+ show Three = "3"
+ show Four = "4"
+ show Five = "5"
+ show Six = "6"
+ show Seven = "7"
+ show Eight = "8"
+ show Nine = "9"
+ show T = "T"
+ show J = "J"
+ show Q = "Q"
+ show K = "K"
+ show A = "A"
+
+data Rank = HighCard
+ | Pair
+ | Pairs
+ | Brelan
+ | FullHouse
+ | Quartet
+ | Quintet
+ deriving (Eq, Ord, Show)
+
+data Hand = Hand Rank [Card] Int deriving (Eq, Show)
+
+compareCards :: [Card] -> [Card] -> Ordering
+compareCards (x:xs) (y:ys) | x == y = compareCards xs ys
+ | otherwise = x `compare` y
+instance Ord Hand where
+ (Hand a x _) `compare` (Hand b y _) | a == b = compareCards x y
+ | otherwise = a `compare` b
+
+type Input = [Hand]
+
+type Parser = Parsec Void String
+
+parseCard :: Parser Card
+parseCard = char '2' $> Two
+ <|> char '3' $> Three
+ <|> char '4' $> Four
+ <|> char '5' $> Five
+ <|> char '6' $> Six
+ <|> char '7' $> Seven
+ <|> char '8' $> Eight
+ <|> char '9' $> Nine
+ <|> char 'T' $> T
+ <|> char 'J' $> J
+ <|> char 'Q' $> Q
+ <|> char 'K' $> K
+ <|> char 'A' $> A
+
+evalRank :: [Card] -> Rank
+evalRank n@(a:b:c:d:e:_) | not (a<=b && b<=c && c<=d && d<=e) = evalRank $ L.sort n
+ | a==b && b==c && c==d && d==e = Quintet
+ | (a==b && b==c && c==d) || (b==c && c==d && d==e) = Quartet
+ | a==b && (b==c || c==d) && d==e = FullHouse
+ | (a==b && b==c) || (b==c && c==d) || (c==d && d==e) = Brelan
+ | (a==b && (c==d || d==e)) || (b==c && d==e) = Pairs
+ | a==b || b==c || c==d || d==e = Pair
+ | otherwise = HighCard
+
+parseHand :: Parser Hand
+parseHand = do
+ cards <- some parseCard <* char ' '
+ bid <- read <$> (some digitChar <* eol)
+ return $ Hand (evalRank cards) cards bid
+
+parseInput' :: Parser Input
+parseInput' = some parseHand <* eof
+
+parseInput :: String -> IO Input
+parseInput filename = do
+ input <- readFile filename
+ case runParser parseInput' filename input of
+ Left bundle -> error $ errorBundlePretty bundle
+ Right input' -> return input'
+
+compute :: Input -> Int
+compute = sum . zipWith (*) [1..] . map (\(Hand _ _ bid) -> bid) . L.sort
+
+main :: IO ()
+main = do
+ example <- parseInput "example"
+ let exampleOutput = compute example
+ when (exampleOutput /= exampleExpectedOutput) (error $ "example failed: got " ++ show exampleOutput ++ " instead of " ++ show exampleExpectedOutput)
+ input <- parseInput "input"
+ print $ compute input