Advent of Code solutions

2020:21

+56 -1
+22
2020/21/p1.hs
··· 1 + import Text.Parsec 2 + import Data.Set qualified as Set 3 + import Data.Set ((\\)) 4 + import Data.Map.Strict qualified as Map 5 + import Data.List (foldl1) 6 + 7 + food = do 8 + ingredients <- many1 letter `endBy` char ' ' 9 + string "(contains " 10 + allergens <- many1 letter `sepBy` string ", " 11 + char ')' 12 + return (ingredients, allergens) 13 + 14 + answer contents = length $ filter (`elem` safe) $ concat $ (fst <$> foods) 15 + where 16 + Right foods = parse (food `endBy` newline) "" contents 17 + allergens = Set.unions (Set.fromList <$> snd <$> foods) 18 + ingredients = Set.unions (Set.fromList <$> fst <$> foods) 19 + candidates = Map.fromList $ Set.toList allergens `zip` fmap (\a -> foldl1 Set.intersection $ fmap (Set.fromList . fst) $ filter (\(_, i) -> a `elem` i) foods) (Set.toList allergens) 20 + safe = Set.toList $ ingredients \\ (Set.unions $ Map.elems candidates) 21 + 22 + main = getContents >>= print . answer
+32
2020/21/p2.hs
··· 1 + import Text.Parsec 2 + import Data.Bifunctor 3 + import Data.Set qualified as Set 4 + import Data.Set (Set) 5 + import Data.Map.Strict qualified as Map 6 + import Data.Map (Map) 7 + import Data.List 8 + 9 + food = do 10 + ingredients <- many1 letter `endBy` char ' ' 11 + string "(contains " 12 + allergens <- many1 letter `sepBy` string ", " 13 + char ')' 14 + return (ingredients, allergens) 15 + 16 + solve :: [(String, Set String)] -> Map String String 17 + solve [] = Map.empty 18 + solve candidates = Map.fromList singles `Map.union` rest 19 + where 20 + singles = second Set.findMin <$> filter (\(_, c) -> Set.size c == 1) candidates 21 + eliminating = snd <$> singles 22 + eliminate = Set.filter (`notElem` eliminating) 23 + rest = solve $ filter (not . null . snd) $ fmap (second eliminate) candidates 24 + 25 + answer contents = intercalate "," $ Map.elems $ solve candidates 26 + where 27 + Right foods = parse (food `endBy` newline) "" contents 28 + allergens = Set.unions (Set.fromList <$> snd <$> foods) 29 + ingredients = Set.unions (Set.fromList <$> fst <$> foods) 30 + candidates = Set.toList allergens `zip` fmap (\a -> foldl1 Set.intersection $ fmap (Set.fromList . fst) $ filter (\(_, i) -> a `elem` i) foods) (Set.toList allergens) 31 + 32 + main = getContents >>= putStrLn . answer
+2 -1
Justfile
··· 2 2 set quiet 3 3 set shell := ["fish", "-c"] 4 4 5 - default_year := "2024" 5 + default_year := env_var_or_default("YEAR", "2024") 6 6 session := env_var("SESSION") 7 7 8 8 [no-cd] ··· 73 73 end 74 74 75 75 get day year=default_year: 76 + echo "Getting {{year}} day {{day}}" 76 77 mkdir -p {{year}}/{{day}} 77 78 curl https://adventofcode.com/{{year}}/day/{{day}}/input \ 78 79 -X GET \