Day 6 was much easier than the other days, almost to the extent that I initially confused myself. It's also continuting the trend that reading and parsing the input data is almost the hardest part.
I started by defining a data type for a Race
. I think even this was excessive for this problem; a tuple would have done.
data Race = Race Int Int deriving (Eq, Show)
Parsing
One little wrinkle was walking along two lines in parallel to generate the races. But as there were only two lines, they were easy enough to combine with zipWith
.
racesP = zipWith Race <$> (timesP <* endOfLine) <*> distancesP
timesP = ("Time:" *> skipSpace) *> numbersP
distancesP = ("Distance:" *> skipSpace) *> numbersP
numbersP = decimal `sepBy` skipSpace
Part 1
This was almost as simple as "write down the problem statement": for each possible hold time, calculate the distance, check if it's over the current record distance, count how many you have. Do that for all the races, multiply them.
part1 :: [Race] -> Int
part1 = product . fmap waysToWin
waysToWin :: Race -> Int
waysToWin (Race timeLimit record) =
length $ filter (> record) [(timeLimit - h) * h | h <- [1..timeLimit]]
Part 2
If the problem for part 2 is "read the input but without the spaces", how about I … read the input but without the spaces?
let races1 = successfulParse text
let races2 = successfulParse $ T.filter (/= ' ') text
That works.
Code
You can get the code from my locally-hosted Git repo, or from Gitlab.