import Aoc import Data.Bifunctor ( bimap ) import Data.List ( sort, group ) parseLine :: String -> (String, (Int, Int, Int)) parseLine line = let [name, "can", "fly", speed, "km/s", "for", flyTime, "seconds,", "but", "then", "must", "rest", "for", restTime, "seconds."] = words line in (name, (read speed, read flyTime, read restTime)) atTime :: Int -> (String, (Int, Int, Int)) -> (String, Int) atTime time (name, (s, f, r)) = (name, (*s) $ uncurry (+) $ bimap (*f) (min f) $ quotRem time (f+r)) part1 :: [(String, (Int, Int, Int))] -> Int part1 = maximum . map (snd . atTime 2503) part2 :: [(String, (Int, Int, Int))] -> Int part2 reindeer = maximum $ map length $ group $ sort $ concatMap winners [1..2503] where winners t = let distances = map (atTime t) reindeer in let maxDistance = maximum $ map snd distances in map fst $ filter ((==maxDistance) . snd) distances main :: IO () main = aocMain (map parseLine) part1 part2