diff --git a/README.md b/README.md index e4d1706..8625e20 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ To arrive at [⟨ortho|normal⟩](https://hilb.ert.space) as December comes. | 04 | ~ 1 | | 05 | ~ 1 | | 06 | ~ 3 | -| 07 | | +| 07 | ~ 1 | | 08 | | | 09 | | | 10 | | diff --git a/src/Day07.hs b/src/Day07.hs index 527c385..192b913 100644 --- a/src/Day07.hs +++ b/src/Day07.hs @@ -1,28 +1,56 @@ module Day07 (main) where -import Data.Map (Map, fromListWith, fromList, findMin) -import qualified Data.Map as M (union, null, filter, delete) -import Data.Set (Set, singleton, empty) -import qualified Data.Set as S (union, null, delete) +import Data.List (partition) +import Data.Map (Map, fromListWith, fromList, findMin, findMax) +import qualified Data.Map as M (union, null, delete, empty, filter) +import Data.Set (Set, singleton) +import qualified Data.Set as S (union, null, delete, empty) import Data.Tuple.Extra (second) +-- Deps = Task => Dependencies +type Deps = Map Char (Set Char) + +-- Worker = (Task, Time) +type Worker = (Char, Int) +emptyWorker = (' ', 0) + parse :: String -> (Char, Char) parse str = (str !! 36, str !! 5) -dependencies :: [(Char, Char)] -> Map Char (Set Char) +dependencies :: [(Char, Char)] -> Deps dependencies ds = let dependents = fromListWith S.union . map (second singleton) $ ds - independents = fromList . (flip zip) (repeat empty) . snd . unzip $ ds + independents = fromList . (flip zip) (repeat S.empty) . snd . unzip $ ds in M.union dependents independents -part1 :: Map Char (Set Char) -> String -> String +part1 :: Deps -> String -> String part1 deps str | M.null deps = reverse str | otherwise = let available = fst . findMin . M.filter S.null $ deps in part1 (fmap (S.delete available) (M.delete available deps)) (available:str) +part2 :: Deps -> [Worker] -> Int -> Int +part2 deps workers time + | M.null deps = time + (maximum . snd . unzip $ workers) + | otherwise = + let elapsedTime = minOrDefault 0 . filter (/= 0) . snd . unzip $ workers + (done, working) = partition ((== 0) . snd) . map (second $ max 0 . subtract elapsedTime) $ workers + clearedDeps = foldr (fmap . S.delete) deps . map fst $ done + (newWorkers, newDeps) = foldr assign (working, clearedDeps) $ [1 .. length done] + in part2 newDeps newWorkers (time + elapsedTime) + where + minOrDefault n ns = if null ns then n else minimum ns + len task = fromEnum task - fromEnum 'A' + 61 + assign :: Int -> ([Worker], Deps) -> ([Worker], Deps) + assign _ (w, d) + | M.null $ M.filter S.null d = ((emptyWorker:w), d) + | otherwise = + let task = fst . findMax . M.filter S.null $ d + in (((task, len task):w), (M.delete task d)) + main :: IO () main = do - input <- map parse . lines <$> readFile "input/07.txt" - putStrLn $ part1 (dependencies input) "" \ No newline at end of file + input <- dependencies . map parse . lines <$> readFile "input/07.txt" + putStrLn $ part1 input "" + print $ part2 input (replicate 5 emptyWorker) 0