Day 1 - Intro Problem

As a reminder, these writeups won't be super detailed, since I have to do one every day. I'll try to focus on the key ideas though, and I'll always link to my code!

Solution code on GitHub

All 2022 Problems

Subscribe to Monday Morning Haskell!

Problem Overview

This year we're dealing with elves. Each elf is carrying some snack items with a certain number of calories. Our input has one calorie count per line, and an empty line denotes that we have reached the end of one elf's snack collection and started another.

1000
2000
3000

4000

5000
6000

7000
8000
9000

10000

For the first part, we just want to find the elf with the most calories. This is the 4th elf, with a total of 24000 calories (7000+8000+9000).

For the second part, we want the sum of calories from the three elves with the most. So we take the 24000 from the elf with the most, and add the 3rd elf (11000 calories) and the 5th elf (10000 calories). This gives a total of 45000.

Full Description

Solution Approach and Insights

Nothing complicated here. Once we parse into list-of-lists-of-ints, we just use map sum and either take the maximum or the sum of the top 3.

Relevant Utilities

Function parseFile

Parsing the Input

Here's our parsing code. One nuance...I needed to add an extra empty line to the given inputs in order to make this parse work. Dealing with empty line separators is a little tricky with megaparsec (or at least I haven't mastered the right pattern yet), because the "chunk separator" is the same as the "line separator" within each chunk (eol parser).

parseInput :: (MonadLogger m) => ParsecT Void Text m [[Int]]
parseInput =
  sepEndBy1 parseIntLines eol
  where
    parseIntLines = some parseIntLine
    parseIntLine = do
      i <- parsePositiveNumber
      eol
      return i

Getting the Solution

As above, nothing complicated here. Use map sum and take the maximum.

processInputEasy :: (MonadLogger m) => [[Int]] -> m Int
processInputEasy intLists = return $ maximum (map sum intLists)

With the hard part, we sort, reverse, take 3, and then take another sum.

processInputHard :: (MonadLogger m) => [[Int]] -> m Int
processInputHard intLists = return $ sum $ take 3 $ reverse $ sort (map sum intLists)

Answering the Question

And no additional processing is needed - we have our answer! (My standard template has the answer always wrapped in Maybe to account for failure cases).

solveEasy :: FilePath -> IO (Maybe Int)
solveEasy fp = runStdoutLoggingT $ do
  input <- parseFile parseInput fp
  Just <$> processInputEasy input

solveHard :: FilePath -> IO (Maybe Int)
solveHard fp = runStdoutLoggingT $ do
  input <- parseFile parseInput fp
  Just <$> processInputHard input

Video

YouTube Link

Previous
Previous

Day 2 - Rock, Paper, Scissors

Next
Next

Advent of Code 2022!