aoc2024

My solutions to the 2024 Advent of Code puzzles
git clone git://git.ethandl.dev/aoc2024
Log | Files | Refs | LICENSE

Day1.hs (3156B)


      1 module Day1 (solution) where
      2 
      3 import Control.Monad (liftM, join)
      4 import Data.List (sort)
      5 
      6 import Utils (SolType(..), safeRead, liftMonadTuple, both, integerDiff)
      7 
      8 input :: IO String
      9 input = readFile "inputs/day1"
     10 
     11 exampleInput :: String
     12 exampleInput = join [
     13     "3   4\n",
     14     "4   3\n",
     15     "2   5\n",
     16     "1   3\n",
     17     "3   9\n",
     18     "3   3\n"
     19   ]
     20 
     21 -- | Split an input string into two smaller strings on any whitespace. All
     22 --   further whitespace is ignored
     23 -- Example:
     24 -- >>> splitWhitespace "3   4"
     25 -- Just ("3","4")
     26 -- >>> splitWhitespace "4   3"
     27 -- Just ("4","3")
     28 -- >>> splitWhitespace "2   5"
     29 -- Just ("2","5")
     30 -- >>> splitWhitespace "1   3"
     31 -- Just ("1","3")
     32 -- >>> splitWhitespace "3   9"
     33 -- Just ("3","9")
     34 -- >>> splitWhitespace "3   3"
     35 -- Just ("3","3")
     36 -- >>> splitWhitespace "agasdfadpc"
     37 -- Nothing
     38 -- >>> splitWhitespace "abcde fghi jk"
     39 -- Just ("abcde","fghijk")
     40 splitWhitespace :: String -> Maybe (String, String)
     41 splitWhitespace = helper [] Nothing
     42   where
     43     helper :: String -> Maybe String -> String -> Maybe (String, String)
     44     --helper lAcc rAcc str
     45     helper l Nothing (' ':rest) = helper l (Just []) rest
     46     helper l Nothing (c:rest) = helper (c:l) Nothing rest
     47     helper l r (' ':rest) = helper l r rest
     48     helper l (Just r) (c:rest) = helper l (Just (c:r)) rest
     49     helper l r [] = do
     50       rStr <- r
     51       return (reverse l, reverse rStr)
     52 
     53 -- | Parse the input into the two lists of integers
     54 -- Example:
     55 -- >>> parse exampleInput
     56 -- Just ([3,4,2,1,3,3],[4,3,5,3,9,3])
     57 parse :: String -> Maybe ([Integer], [Integer])
     58 parse inputStr = do
     59   let ls = lines inputStr
     60   lrs <- mapM splitWhitespace ls
     61   (l, r) <- liftM unzip $ mapM (liftMonadTuple . both safeRead) lrs
     62   return (l, r)
     63 
     64 -- | Solution to day 1 part 1
     65 -- Example:
     66 -- >>> liftM solution1 $ parse exampleInput
     67 -- Just 11
     68 solution1 :: ([Integer], [Integer]) -> Integer
     69 solution1 (l, r) = helper 0 (sort l, sort r)
     70   where
     71     helper :: Integer -> ([Integer], [Integer]) -> Integer
     72     helper n (x:xs, y:ys) = helper (n + integerDiff x y) (xs, ys)
     73     helper n ([], _) = n
     74     helper n (_, []) = n
     75 
     76 -- | Return the number of times something appears in a list
     77 -- Example:
     78 -- >>> numInstances 3 [4,3,5,3,9,3]
     79 -- 3
     80 -- >>> numInstances 4 [4,3,5,3,9,3]
     81 -- 1
     82 -- >>> numInstances 2 [4,3,5,3,9,3]
     83 -- 0
     84 -- >>> numInstances 1 [4,3,5,3,9,3]
     85 -- 0
     86 numInstances :: Eq a => a -> [a] -> Integer
     87 numInstances = helper 0
     88   where
     89     helper :: Eq a => Integer -> a -> [a] -> Integer
     90     helper n x (el:rest)
     91       | x == el   = helper (n + 1) x rest
     92       | otherwise = helper n x rest
     93     helper n _ [] = n
     94 
     95 -- | Solution to day 1 part 2
     96 -- Example:
     97 -- >>> liftM solution2 $ parse exampleInput
     98 -- Just 31
     99 solution2 :: ([Integer], [Integer]) -> Integer
    100 solution2 = helper 0
    101   where
    102     helper :: Integer -> ([Integer], [Integer]) -> Integer
    103     helper n (x:xs, ys) = helper (n + x * numInstances x ys) (xs, ys)
    104     helper n ([], _) = n
    105 
    106 solution :: IO (SolType, SolType)
    107 solution = do
    108   probStr <- input
    109   let parsedLists = parse probStr
    110   let sol1 = liftM (IntSol . solution1) parsedLists
    111   let sol2 = liftM (IntSol . solution2) parsedLists
    112   return $ (MaybeSol sol1, MaybeSol sol2)