feat: day5 part one

This commit is contained in:
Victor Martinez 2025-03-14 00:55:20 +01:00
parent 05900411a2
commit 76db862cb0
5 changed files with 1469 additions and 0 deletions

View file

@ -28,6 +28,7 @@ library
Day1
Day2
Day3
Day5
other-modules:
Paths_aoc2024
autogen-modules:
@ -37,7 +38,9 @@ library
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
build-depends:
base >=4.7 && <5
, containers
, regex-tdfa >=1.3.2 && <1.4
, text >=2.0.2
default-language: Haskell2010
test-suite aoc2024-test
@ -47,6 +50,7 @@ test-suite aoc2024-test
Day1Spec
Day2Spec
Day3Spec
Day5Spec
Paths_aoc2024
autogen-modules:
Paths_aoc2024
@ -57,6 +61,8 @@ test-suite aoc2024-test
QuickCheck >=2.14.3 && <2.15
, aoc2024
, base >=4.7 && <5
, containers
, hspec >=2.0.0
, regex-tdfa >=1.3.2 && <1.4
, text >=2.0.2
default-language: Haskell2010

1366
input/day5.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,8 @@ description: Please see the README on GitHub at <https://github.com/githubuser/a
dependencies:
- base >= 4.7 && < 5
- regex-tdfa ^>= 1.3.2
- text >= 2.0.2
- containers
ghc-options:
- -Wall

55
src/Day5.hs Normal file
View file

@ -0,0 +1,55 @@
module Day5 (ParseError, partOne, partTwo) where
import qualified Data.Bifunctor as BF
import Data.List (sortBy)
import Data.Set (Set, fromList, member)
import qualified Data.Text as T
import Data.Text.Read (decimal)
data ParseError = ParseIntError String | ParseRuleError T.Text | ParseInputError
deriving (Show, Eq)
type Rule = (Int, Int)
type Update = [Int]
partOne :: String -> Either ParseError Int
partOne input = do
(rules, updates) <- parseInput input
return $ sum $ map middleElem $ filter (isValidUpdate rules) updates
where
isValidUpdate rules update = sortBy (compareByRules rules) update == update
compareByRules rules x y = if member (x, y) rules then LT else GT
middleElem update = update !! (length update `div` 2)
partTwo :: String -> Either ParseError Int
partTwo _ = Right 0
parseInput :: String -> Either ParseError (Set Rule, [Update])
parseInput content = case T.splitOn separator text of
[left, right] -> do
rules <- parseRules left
updates <- parseUpdates right
return (rules, updates)
_ -> Left ParseInputError
where
text = T.pack content
separator = T.pack "\n\n"
parseRules :: T.Text -> Either ParseError (Set Rule)
parseRules rules = fromList <$> mapM parseRule (T.lines rules)
where
parseRule rule = case T.split (== '|') rule of
[left, right] -> do
leftNum <- parseInt left
rightNum <- parseInt right
return (leftNum, rightNum)
_ -> Left (ParseRuleError rule)
parseUpdates :: T.Text -> Either ParseError [Update]
parseUpdates updates = mapM parseUpdate $ T.lines updates
where
parseUpdate = mapM parseInt . T.split (== ',')
parseInt :: T.Text -> Either ParseError Int
parseInt v = fst <$> BF.first ParseIntError (decimal v)

40
test/Day5Spec.hs Normal file
View file

@ -0,0 +1,40 @@
module Day5Spec (spec) where
import Day5 (partOne)
import Test.Hspec
spec :: Spec
spec = do
describe "PartOne" $ do
it "works" $ do
partOne input `shouldBe` Right 143
where
input =
"47|53\n\
\97|13\n\
\97|61\n\
\97|47\n\
\75|29\n\
\61|13\n\
\75|53\n\
\29|13\n\
\97|29\n\
\53|29\n\
\61|53\n\
\97|53\n\
\61|29\n\
\47|13\n\
\75|47\n\
\97|75\n\
\47|61\n\
\75|61\n\
\47|29\n\
\75|13\n\
\53|13\n\
\\n\
\75,47,61,53,29\n\
\97,61,53,29,13\n\
\75,29,13\n\
\75,97,47,61,53\n\
\61,13,29\n\
\97,13,75,29,47"