From: Neil Smith Date: Thu, 7 Dec 2023 10:49:59 +0000 (+0000) Subject: Done day 7 X-Git-Url: https://git.njae.me.uk/?a=commitdiff_plain;h=c7364d4e2de33c97a720e1654e296d3f4c304756;p=advent-of-code-23.git Done day 7 --- diff --git a/advent-of-code23.cabal b/advent-of-code23.cabal index 99b2c32..c0bb353 100644 --- a/advent-of-code23.cabal +++ b/advent-of-code23.cabal @@ -135,3 +135,9 @@ executable advent06 import: common-extensions, build-directives main-is: advent06/Main.hs build-depends: text, attoparsec + +executable advent07 + import: common-extensions, build-directives + main-is: advent07/Main.hs + build-depends: text, attoparsec + \ No newline at end of file diff --git a/advent07/Main.hs b/advent07/Main.hs new file mode 100644 index 0000000..6d326a4 --- /dev/null +++ b/advent07/Main.hs @@ -0,0 +1,113 @@ +-- Writeup at https://work.njae.me.uk/2023/12/07/advent-of-code-2023-day-07/ + +import AoC +import Data.Text (Text) +import qualified Data.Text.IO as TIO +import Data.Attoparsec.Text -- hiding (take) +import Control.Applicative +import Data.List + +data Card = Joker | Two | Three | Four | Five | Six | Seven | Eight | Nine | + Ten | Jack | Queen | King | Ace deriving (Eq, Ord, Show) + +data HandClass = HighCard | OnePair | TwoPair | ThreeOfAKind | FullHouse | + FourOfAKind | FiveOfAKind deriving (Eq, Ord, Show) + +data Hand = Hand [Card] Int deriving (Eq, Ord, Show) +data ClassifiedHand = CHand HandClass [Card] Int deriving (Eq, Ord, Show) + +type SignatureElement = (Int, [Card]) +type Signature = [SignatureElement] + +main :: IO () +main = + do dataFileName <- getDataFileName + text <- TIO.readFile dataFileName + let hands = successfulParse text + print $ part1 hands + print $ part2 hands + +part1, part2 :: [Hand] -> Int +part1 hands = sum $ fmap score rankedHands + where sortedHands = sort $ fmap classify hands + rankedHands = zip [1..] sortedHands + score (r, CHand _ _ bid) = r * bid + +part2 hands = part1 $ fmap enJoker hands + +enJoker :: Hand -> Hand +enJoker (Hand cards bid) = Hand jCards bid + where jCards = replace Jack Joker cards + +replace :: Eq a => a -> a -> [a] -> [a] +replace _ _ [] = [] +replace f t (x:xs) + | x == f = t : replace f t xs + | otherwise = x : replace f t xs + +classify :: Hand -> ClassifiedHand +classify (Hand cards bid) + | isFiveOfAKind signature = CHand FiveOfAKind cards bid + | isFourOfAKind signature = CHand FourOfAKind cards bid + | isFullHouse signature = CHand FullHouse cards bid + | isThreeOfAKind signature = CHand ThreeOfAKind cards bid + | isTwoPair signature = CHand TwoPair cards bid + | isOnePair signature = CHand OnePair cards bid + | otherwise = CHand HighCard cards bid + where signature = sign cards + +sign :: [Card] -> Signature +-- sign = reverse . sort . fmap (\g -> (length g, g)) . group . sort +sign cards = addJokers nonJokerSigned (length jokers, jokers) + where (jokers, nonJokers) = partition (== Joker) cards + -- numJokers = length jokers + nonJokerSigned = reverse $ sort $ fmap (\g -> (length g, g)) $ + group $ sort nonJokers + +addJokers :: Signature -> SignatureElement -> Signature +addJokers [] js = [js] +addJokers ((n, cs):xs) (jn, js) = (n + jn, cs ++ js):xs + +isFiveOfAKind, isFourOfAKind, isFullHouse, isThreeOfAKind, isTwoPair, + isOnePair :: Signature -> Bool +isFiveOfAKind ((5, _):_) = True +isFiveOfAKind _ = False + +isFourOfAKind ((4, _):_) = True +isFourOfAKind _ = False + +isFullHouse ((3, _):(2, _):_) = True +isFullHouse _ = False + +isThreeOfAKind ((3, _):_) = True +isThreeOfAKind _ = False + +isTwoPair ((2, _):(2, _):_) = True +isTwoPair _ = False + +isOnePair ((2, _):_) = True +isOnePair _ = False + +-- isHighCard :: Signature -> Bool +-- isHighCard _ = True + +-- Parse the input file + +handsP :: Parser [Hand] +handP :: Parser Hand +cardP :: Parser Card + +handsP = handP `sepBy` endOfLine +handP = Hand <$> ((many1 cardP) <* space) <*> decimal + +cardP = (Two <$ "2") <|> (Three <$ "3") <|> (Four <$ "4") <|> + (Five <$ "5") <|> (Six <$ "6") <|> (Seven <$ "7") <|> + (Eight <$ "8") <|> (Nine <$ "9") <|> (Ten <$ "T") <|> + (Jack <$ "J") <|> (Queen <$ "Q") <|> (King <$ "K") <|> + (Ace <$ "A") + +successfulParse :: Text -> [Hand] +successfulParse input = + case parseOnly handsP input of + Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err + Right matches -> matches