diff --git a/advent-of-code-2023.cabal b/advent-of-code-2023.cabal index 2371589..ceda03f 100644 --- a/advent-of-code-2023.cabal +++ b/advent-of-code-2023.cabal @@ -52,3 +52,11 @@ executable day06 build-depends: base ^>=4.15.1.0, MissingH hs-source-dirs: day06 default-language: Haskell2010 + +executable day07 + main-is: Main.hs + other-modules: Commons Part1 Part2 + + build-depends: base ^>=4.15.1.0, MissingH + hs-source-dirs: day07 + default-language: Haskell2010 diff --git a/day07/Commons.hs b/day07/Commons.hs new file mode 100644 index 0000000..a34c454 --- /dev/null +++ b/day07/Commons.hs @@ -0,0 +1,53 @@ +module Commons where + +import Data.List.Utils (split) +import GHC.IO.Handle (isEOF) +import Data.Char (digitToInt, isDigit) +import Data.List (sortOn) + + +data Hand = Hand { values :: [Int], bid :: Int } deriving Show +data HandValue = HandValue { hand :: Hand, value :: Int } deriving Show + + +parseValues :: String -> [Int] +parseValues (v: t) | isDigit v = digitToInt v: parseValues t + | v == 'T' = 10: parseValues t + | v == 'J' = 11: parseValues t + | v == 'Q' = 12: parseValues t + | v == 'K' = 13: parseValues t + | v == 'A' = 14: parseValues t +parseValues [] = [] + +parseHand :: String -> Hand +parseHand handRaw = let valuesRaw: bidRaw: _ = split " " handRaw + in Hand {values = parseValues valuesRaw, bid = read bidRaw} + +parse :: IO [Hand] +parse = do done <- isEOF + if done + then return [] + else do line <- getLine + let hand = parseHand line + otherHands <- parse + return $ hand: otherHands + + +getHandValueTypeFromSorted :: [Int] -> Int +getHandValueTypeFromSorted [a, b, c, d, e] | a == e = 6 + | a == d || b == e = 5 + | a == c && d == e || a == b && c == e = 4 + | a == c || b == d || c == e = 3 + | a == b && (c == d || d == e) || b == c && d == e = 2 + | a == b || b == c || c == d || d == e = 1 + | otherwise = 0 + +getHandSecondValue :: [Int] -> Int +getHandSecondValue [a, b, c, d, e] = 100 * (100 * (100 * (100 * a + b) + c) + d) + e + +sortHandValues :: [HandValue] -> [HandValue] +sortHandValues = sortOn value + +getWinningsFromSorted :: Int -> [Hand] -> Int +getWinningsFromSorted _ [] = 0 +getWinningsFromSorted i (hh: t) = i * bid hh + getWinningsFromSorted (i + 1) t diff --git a/day07/Main.hs b/day07/Main.hs new file mode 100644 index 0000000..3e211bb --- /dev/null +++ b/day07/Main.hs @@ -0,0 +1,12 @@ +module Main where + +import Commons +import qualified Part1 +import qualified Part2 + + +main = do hands <- parse + let part1Res = Part1.getTotalWinnings hands + print part1Res + let part2Res = Part2.getTotalWinnings hands + print part2Res diff --git a/day07/Part1.hs b/day07/Part1.hs new file mode 100644 index 0000000..25d744c --- /dev/null +++ b/day07/Part1.hs @@ -0,0 +1,15 @@ +module Part1 where + +import Commons +import Data.List (sort, sortOn) + + +getHandValue :: Hand -> HandValue +getHandValue hand = HandValue {hand = hand, value = 100 ^ 5 * (getHandValueTypeFromSorted . sort) (values hand) + + getHandSecondValue (values hand)} + +sortHands :: [Hand] -> [Hand] +sortHands = map hand . sortHandValues . map getHandValue + +getTotalWinnings :: [Hand] -> Int +getTotalWinnings = getWinningsFromSorted 1 . sortHands diff --git a/day07/Part2.hs b/day07/Part2.hs new file mode 100644 index 0000000..d2fa0b1 --- /dev/null +++ b/day07/Part2.hs @@ -0,0 +1,34 @@ +module Part2 where + +import Commons +import Data.List (sort, sortOn) + + +getHandValueTypeFromSortedJokers :: [Int] -> Int +getHandValueTypeFromSortedJokers [0, b, c, d, e] | e == 0 = 6 + | d == 0 || b == e = 6 + | c == 0 && d == e || b == 0 && c == e = 6 + | c == 0 || b == d || c == e = 5 + | b == 0 && (c == d || d == e) = 5 + | b == c && d == e = 4 + | b == 0 || b == c || c == d || d == e = 3 + | otherwise = 1 +getHandValueTypeFromSortedJokers values = getHandValueTypeFromSorted values + +getHandValue :: Hand -> HandValue +getHandValue hand = HandValue {hand = hand, value = 100 ^ 5 * (getHandValueTypeFromSortedJokers . sort) (values hand) + + getHandSecondValue (values hand)} + +sortHands :: [Hand] -> [Hand] +sortHands = map hand . sortHandValues . map getHandValue + +applyJokers :: [Int] -> [Int] +applyJokers [] = [] +applyJokers (v: t) | v == 11 = 0: applyJokers t + | otherwise = v: applyJokers t + +applyJokersToHands :: [Hand] -> [Hand] +applyJokersToHands = map (\ hand -> Hand {values = applyJokers (values hand), bid = bid hand}) + +getTotalWinnings :: [Hand] -> Int +getTotalWinnings = getWinningsFromSorted 1 . sortHands . applyJokersToHands