diff --git a/advent-of-code-2023.cabal b/advent-of-code-2023.cabal index 66e1475..ca694f8 100644 --- a/advent-of-code-2023.cabal +++ b/advent-of-code-2023.cabal @@ -36,3 +36,11 @@ executable day04 build-depends: base ^>=4.15.1.0, MissingH hs-source-dirs: day04 default-language: Haskell2010 + +executable day05 + main-is: Main.hs + other-modules: Commons Part1 Part2 + + build-depends: base ^>=4.15.1.0, MissingH + hs-source-dirs: day05 + default-language: Haskell2010 diff --git a/day05/Commons.hs b/day05/Commons.hs new file mode 100644 index 0000000..7e82306 --- /dev/null +++ b/day05/Commons.hs @@ -0,0 +1,55 @@ +module Commons where + +import Data.List.Utils (split) +import GHC.IO.Handle (isEOF) + + +data ConversionEntry = ConversionEntry { sourceStart :: Int, destinationStart :: Int, size :: Int } deriving Show +type ConversionMap = [ConversionEntry] +data Almanac = Almanac { seeds :: [Int], toSoil :: ConversionMap, toFertilizer :: ConversionMap, + toWater :: ConversionMap, toLight :: ConversionMap, toTemperature :: ConversionMap, + toHumidity :: ConversionMap, toLocation :: ConversionMap } deriving Show + +parseSeeds :: [String] -> [Int] +parseSeeds = map read + +parseSeedsRaw :: IO [Int] +parseSeedsRaw = do line <- getLine + getLine + let seeds = parseSeeds $ tail $ split " " line + return seeds + +parseConversionEntry :: [String] -> ConversionEntry +parseConversionEntry (ds: ss: size: _) = ConversionEntry {sourceStart = read ss, destinationStart = read ds, + size = read size} + +parseConversionMapRaw :: IO ConversionMap +parseConversionMapRaw = do done <- isEOF + if done + then return [] + else do line <- getLine + case line of + [] -> do return [] + _ -> do let eMap = parseConversionEntry $ split " " line + othersEMap <- parseConversionMapRaw + return $ eMap: othersEMap + +parse :: IO Almanac +parse = do seeds <- parseSeedsRaw + getLine + toSoil <- parseConversionMapRaw + getLine + toFertilizer <- parseConversionMapRaw + getLine + toWater <- parseConversionMapRaw + getLine + toLight <- parseConversionMapRaw + getLine + toTemperature <- parseConversionMapRaw + getLine + toHumidity <- parseConversionMapRaw + getLine + toLocation <- parseConversionMapRaw + return Almanac {seeds = seeds, toSoil = toSoil, toFertilizer = toFertilizer, toWater = toWater, + toLight = toLight, toTemperature = toTemperature, toHumidity = toHumidity, + toLocation = toLocation} diff --git a/day05/Main.hs b/day05/Main.hs new file mode 100644 index 0000000..c479846 --- /dev/null +++ b/day05/Main.hs @@ -0,0 +1,12 @@ +module Main where + +import Commons +import qualified Part1 +import qualified Part2 + + +main = do almanac <- parse + let part1Res = minimum $ Part1.getLocations almanac + print part1Res + let part2Res = minimum $ Part2.getLocationsStarts almanac + print part2Res diff --git a/day05/Part1.hs b/day05/Part1.hs new file mode 100644 index 0000000..ecc8169 --- /dev/null +++ b/day05/Part1.hs @@ -0,0 +1,18 @@ +module Part1 where + +import Commons + + +applyConversionMap :: ConversionMap -> Int -> Int +applyConversionMap [] v = v +applyConversionMap (e: t) v | v >= sourceStart e && v <= sourceStart e + size e = destinationStart e - sourceStart e + v + | otherwise = applyConversionMap t v + +applyConversionMapToList :: ConversionMap -> [Int] -> [Int] +applyConversionMapToList cm = map $ applyConversionMap cm + +getLocations :: Almanac -> [Int] +getLocations a = applyConversionMapToList (toLocation a) . applyConversionMapToList (toHumidity a) + . applyConversionMapToList (toTemperature a) . applyConversionMapToList (toLight a) + . applyConversionMapToList (toWater a) . applyConversionMapToList (toFertilizer a) + . applyConversionMapToList (toSoil a) $ seeds a diff --git a/day05/Part2.hs b/day05/Part2.hs new file mode 100644 index 0000000..486ea38 --- /dev/null +++ b/day05/Part2.hs @@ -0,0 +1,33 @@ +module Part2 where + +import Commons + + +applyConversionMap :: ConversionMap -> Int -> Int -> [Int] +applyConversionMap [] v vs = [v, vs] +applyConversionMap _ _ 0 = [] +applyConversionMap (e: t) v vs + | v >= sourceStart e && v <= sourceStart e + size e = + let newVs = min (sourceStart e + size e) (v + vs) - v + in (destinationStart e - sourceStart e + v): newVs: applyConversionMap t (v + newVs) (vs - newVs) + | v < sourceStart e && v + vs >= sourceStart e = + let newVs = v + vs - sourceStart e + in applyConversionMap (e: t) (sourceStart e) newVs ++ applyConversionMap t v (vs - newVs) + | otherwise = applyConversionMap t v vs + +applyConversionMapToList :: ConversionMap -> [Int] -> [Int] +applyConversionMapToList cm [] = [] +applyConversionMapToList cm (v: vs: t) = applyConversionMap cm v vs ++ applyConversionMapToList cm t + +getLocations :: Almanac -> [Int] +getLocations a = applyConversionMapToList (toLocation a) . applyConversionMapToList (toHumidity a) + . applyConversionMapToList (toTemperature a) . applyConversionMapToList (toLight a) + . applyConversionMapToList (toWater a) . applyConversionMapToList (toFertilizer a) + . applyConversionMapToList (toSoil a) $ seeds a + +dropLocationsSizes :: [Int] -> [Int] +dropLocationsSizes [] = [] +dropLocationsSizes (start: size: t) = start: dropLocationsSizes t + +getLocationsStarts :: Almanac -> [Int] +getLocationsStarts = dropLocationsSizes . getLocations