[hs] Clean up 2020_16

This commit is contained in:
Joscha 2020-12-16 18:11:42 +00:00
parent 874c7f1e84
commit 155118b5f2

View file

@ -8,22 +8,16 @@ import Control.Monad
import Data.Bifunctor import Data.Bifunctor
import Data.List import Data.List
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as T import qualified Data.Text as T
import Aoc.Day import Aoc.Day
import Aoc.Parse import Aoc.Parse
data Input = Input data Input = Input [(T.Text, Int -> Bool)] [Int] [[Int]]
{ iFields :: Map.Map T.Text [(Int, Int)]
, iMyTicket :: [Int]
, iNearbyTickets :: [[Int]]
} deriving (Show)
parser :: Parser Input parser :: Parser Input
parser = do parser = do
fields <- Map.fromList <$> many (fieldLine <* newline) fields <- many (fieldLine <* newline)
void $ string "\nyour ticket:\n" void $ string "\nyour ticket:\n"
myTicket <- ticket <* newline myTicket <- ticket <* newline
void $ string "\nnearby tickets:\n" void $ string "\nnearby tickets:\n"
@ -33,48 +27,38 @@ parser = do
fieldLine = do fieldLine = do
name <- takeWhileP Nothing $ \c -> (c /= ':') && (c /= '\n') name <- takeWhileP Nothing $ \c -> (c /= ':') && (c /= '\n')
void $ string ": " void $ string ": "
ranges <- sepBy ((,) <$> (decimal <* string "-") <*> decimal) (string " or ") (a, b) <- (,) <$> (decimal <* string "-") <*> decimal
pure (name, ranges) void $ string " or "
(c, d) <- (,) <$> (decimal <* string "-") <*> decimal
pure (name, \n -> (a <= n && n <= b) || (c <= n && n <= d))
ticket = decimal `sepBy` string "," ticket = decimal `sepBy` string ","
valid :: Int -> [(Int, Int)] -> Bool anyValid :: [(T.Text, Int -> Bool)] -> Int -> Bool
valid n = any (\(a, b) -> a <= n && n <= b) anyValid fields n = any (($ n) . snd) fields
findValid :: Map.Map T.Text [(Int, Int)] -> Int -> Set.Set T.Text
findValid fields n = Set.fromList $ map fst $ filter (valid n . snd) $ Map.toList fields
anyValid :: Map.Map T.Text [(Int, Int)] -> Int -> Bool
anyValid fields = not . Set.null . findValid fields
anyOf :: [a] -> [(a, [a])] anyOf :: [a] -> [(a, [a])]
anyOf [] = [] anyOf [] = []
anyOf (a:as) = (a, as) : map (second (a:)) (anyOf as) anyOf (a:as) = (a, as) : map (second (a:)) (anyOf as)
findFields :: [(a, Set.Set T.Text)] -> [[(a, T.Text)]] findFields :: [(a, [T.Text])] -> [[(a, T.Text)]]
findFields [] = pure [] findFields [] = pure []
findFields variants = do findFields variants = do
((index, names), rest) <- anyOf variants ((i, [name]), rest) <- anyOf variants
case Set.toList names of rest2 <- findFields $ map (second $ delete name) rest
[name] -> do pure $ (i, name) : rest2
let rest' = map (second $ Set.delete name) rest
((index, name) :) <$> findFields rest'
_ -> []
solver :: Input -> IO () solver :: Input -> IO ()
solver input = do solver (Input fields ownTicket nearbyTickets) = do
let Input fields ownTicket nearbyTickets = input
putStrLn ">> Part 1" putStrLn ">> Part 1"
print $ sum $ filter (not . anyValid fields) $ concat nearbyTickets print $ sum $ filter (not . anyValid fields) $ concat nearbyTickets
putStrLn "" putStrLn ""
putStrLn ">> Part 2" putStrLn ">> Part 2"
let validTickets = filter (all (anyValid fields)) nearbyTickets let validTickets = filter (all (anyValid fields)) nearbyTickets
possibleFields = map (foldr1 Set.intersection) $ transpose $ map (map (findValid fields)) validTickets possibleNames = map (\ns -> map fst $ filter (\(_, p) -> all p ns) fields) $ transpose validTickets
actualFields = Map.fromList $ head $ findFields $ zip [(0::Int)..] possibleFields actualNames = map snd $ sortOn fst $ head $ findFields $ zip [(0::Int)..] possibleNames
namedOwnValues = zipWith (\i v -> (actualFields Map.! i, v)) [0..] ownTicket relevantValues = map snd $ filter (T.isPrefixOf "departure" . fst) $ zip actualNames ownTicket
relevantOwnValues = map snd $ filter (T.isPrefixOf "departure" . fst) namedOwnValues print $ product relevantValues
print $ product relevantOwnValues
day :: Day day :: Day
day = dayParse parser solver day = dayParse parser solver