feat(day5): Implement part 2 (7.46s of execution, we ain't ballin)

This commit is contained in:
kale 2024-12-11 13:59:43 +01:00
parent 14a6f5ce1d
commit 501b2fc19e
Signed by: kalmenn
GPG key ID: F500055C44BC3834

View file

@ -2,21 +2,22 @@ module Main where
import System.Environment (getArgs) import System.Environment (getArgs)
import Data.Maybe (mapMaybe) import Data.Maybe (mapMaybe)
import Data.List (find)
import Text.Parsec (parse, Parsec, endBy, sepBy1, char, newline, many) import Text.Parsec (parse, Parsec, endBy, sepBy1, char, newline, many)
import Text.ParserCombinators.Parsec.Number (decimal) import Text.ParserCombinators.Parsec.Number (decimal)
type PageOrdering = (Int, Int) type OrderingRule = (Int, Int)
type PagesUpdate = [Int] type PagesUpdate = [Int]
printInfo :: Parsec String () ([PageOrdering], [PagesUpdate]) printInfo :: Parsec String () ([OrderingRule], [PagesUpdate])
printInfo = (,) <$> orderings <*> (newline *> pagesUpdates) <* many (char '\n') printInfo = (,) <$> orderingRules <*> (newline *> pagesUpdates) <* many (char '\n')
where where
pagesUpdates :: Parsec String () [PagesUpdate] pagesUpdates :: Parsec String () [PagesUpdate]
pagesUpdates = endBy (sepBy1 decimal $ char ',') newline pagesUpdates = endBy (sepBy1 decimal $ char ',') newline
orderings :: Parsec String () [PageOrdering] orderingRules :: Parsec String () [OrderingRule]
orderings = endBy ((,) <$> decimal <*> (char '|' *> decimal)) $ char '\n' orderingRules = endBy ((,) <$> decimal <*> (char '|' *> decimal)) $ char '\n'
allDependencies :: [a] -> [(a, a)] allDependencies :: [a] -> [(a, a)]
allDependencies (h:tl) = map (flip (,) h) tl ++ allDependencies tl allDependencies (h:tl) = map (flip (,) h) tl ++ allDependencies tl
@ -29,16 +30,40 @@ middleElement (_:h':tl) = case reverse (h':tl) of
(_:middle) -> middleElement middle (_:middle) -> middleElement middle
[] -> Nothing [] -> Nothing
part1 :: FilePath -> IO Int isWellOrdered :: [OrderingRule] -> PagesUpdate -> Bool
part1 fp = do isWellOrdered orderingRules = all (`notElem` orderingRules) . allDependencies
content <- readFile fp
(requiredOrderings, pagesUpdates) <- either (fail . show) return $ parse printInfo fp content part1 :: [OrderingRule] -> [PagesUpdate] -> Int
let wellOrdered = filter (all (`notElem` requiredOrderings) . allDependencies) pagesUpdates part1 orderingRules pagesUpdates = (sum . mapMaybe middleElement) onlyWellOrdered
return $ sum $ mapMaybe middleElement wellOrdered where onlyWellOrdered = filter (isWellOrdered orderingRules) pagesUpdates
partitions :: [a] -> [([a], a, [a])]
partitions (h:tl) = ([], h, tl) : map (\(as, a, bs) -> (h:as, a, bs)) (partitions tl)
partitions [] = []
doublePartitions :: [a] -> [([a], a, [a], a, [a])]
doublePartitions ls = [(as, a, bs, b, cs)
| (as, a, bs') <- partitions ls
, (bs, b, cs) <- partitions bs']
reorder :: [OrderingRule] -> PagesUpdate -> PagesUpdate
reorder orderingRules pagesUpdate = case find badlyOrdered $ doublePartitions pagesUpdate of
Just (as, a, bs, b, cs) -> reorder orderingRules (as ++ b : bs ++ a : cs)
Nothing -> pagesUpdate
where
badlyOrdered :: ([Int], Int, [Int], Int, [Int]) -> Bool
badlyOrdered (_, a, _, b, _) = (b, a) `elem` orderingRules
part2 :: [OrderingRule] -> [PagesUpdate] -> Int
part2 orderingRules = sum
. mapMaybe (middleElement . reorder orderingRules)
. filter (not . isWellOrdered orderingRules)
main :: IO () main :: IO ()
main = do main = do
args <- getArgs args <- getArgs
(fp:_) <- return args (fp:_) <- return args
resPart1 <- part1 fp content <- readFile fp
putStrLn $ "Solution (Part 1) : " ++ show resPart1 input <- either (fail . show) return $ parse printInfo fp content
-- putStrLn $ "Solution (Part 1) : " ++ show (uncurry part1 input)
putStrLn $ "Solution (Part 2) : " ++ show (uncurry part2 input)