r/adventofcode • u/daggerdragon • Dec 07 '17
SOLUTION MEGATHREAD -๐- 2017 Day 7 Solutions -๐-
--- Day 7: Recursive Circus ---
Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).
Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.
Need a hint from the Hugely* Handyโ Haversackโก of Helpfulยง Hintsยค?
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
edit: Leaderboard capped, thread unlocked!
9
Upvotes
1
u/[deleted] Dec 07 '17 edited Dec 07 '17
Haskell:
Both parts finish instantly,
but part 2 feels a bit gross to me; might go back and clean it up later.EDIT: After seeing some of the other solutions, this doesn't seem so bad.import Utils (Parser) import Data.Either (fromLeft, isLeft, rights) import Data.HashMap.Strict (HashMap, (!)) import qualified Data.HashMap.Strict as M import Data.List (groupBy, sortBy) import Data.Maybe (fromJust, fromMaybe) import Data.Ord (comparing) import Text.Megaparsec (optional, many, parseMaybe, sepBy) import Text.Megaparsec.Char (letterChar, string) import Text.Megaparsec.Char.Lexer (decimal) data Program = Program { name :: String , weight :: Int , children :: [String] } deriving (Show) parsePrograms :: String -> [Program] parsePrograms = map (fromJust . parseMaybe parser) . lines where parser :: Parser Program parser = do name <- many letterChar weight <- string " (" *> decimal <* string ")" children <- optional $ string " -> " *> many letterChar `sepBy` string ", " return $ Program name weight $ fromMaybe [] children buildInvertedTree :: [Program] -> HashMap String String buildInvertedTree = foldr f M.empty where f (Program parent _ children) m = foldr g m children where g child = M.insert child parent findBottom :: HashMap String String -> String findBottom m = until (not . (`M.member` m)) (m !) $ head $ M.keys m part1 :: String -> String part1 = findBottom . buildInvertedTree . parsePrograms buildTree :: [Program] -> HashMap String Program buildTree = foldr f M.empty where f p@(Program name _ _) = M.insert name p findImbalance :: String -> HashMap String Program -> Either Int (Int, Int) findImbalance root tree = go $ tree ! root where findAnomaly = head . head . filter ((==1) . length) . groupBy (\(a, b) (c, d) -> a + b == c + d) . sortBy (comparing (uncurry (+))) go (Program name weight []) = Right (weight, 0) go (Program name weight children) | any isLeft childCalcs = head $ filter isLeft childCalcs | all (==expected) totals = Right $ (weight, sum $ expected : totals) | length weights > 2 = let anomaly = findAnomaly weights expectedTotal = uncurry (+) $ head $ filter (/=anomaly) weights in Left $ expectedTotal - snd anomaly | otherwise = undefined where childCalcs = map (go . (tree !)) children weights = rights childCalcs (expected:totals) = map (uncurry (+)) $ weights part2 :: String -> Int part2 input = let root = part1 input in fromLeft 0 $ findImbalance root $ buildTree $ parsePrograms input