This commit is contained in:
Samae 2024-12-03 22:11:13 +02:00
parent 642a3c5773
commit f8f4db3d7e
6 changed files with 1066 additions and 2 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
result* result*
*.cabal *.cabal
dist-newstyle

View file

@ -3,10 +3,12 @@
module Main where module Main where
import Day1 import Day1
import Day2
main :: IO () main :: IO ()
main = do main = do
putStrLn "AoC 2024" putStrLn "AoC 2024"
putStrLn "Day 1" putStrLn "Day 1"
Day1.main Day1.main
putStrLn "Day 2"
Day2.main

View file

@ -0,0 +1,6 @@
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9

1000
inputs/day2.input Normal file

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@ library:
source-dirs: src source-dirs: src
exposed-modules: exposed-modules:
- Day1 - Day1
# - Day2 - Day2
# - Day3 # - Day3
# - Day4 # - Day4
# - Day5 # - Day5

55
src/Day2.hs Normal file
View file

@ -0,0 +1,55 @@
{-# LANGUAGE OverloadedStrings #-}
module Day2 where
-- import Debug.Trace
import Data.Scientific (coefficient)
import Data.Attoparsec.Text (Parser)
import Data.Either (fromRight)
import Data.List (subsequences)
import qualified Data.Attoparsec.Text as P
import qualified Data.Text.IO as T
type Report = [Integer]
parseInput :: Parser [Report]
parseInput = (coefficient <$> P.scientific) `P.sepBy1` " " `P.sepBy1` P.endOfLine
-- Count how many reports are safe
solveA :: [Report] -> Integer
solveA = toInteger . length . filter id . fmap isSafe
-- The levels are either all increasing or all decreasing.
-- Any two adjacent levels differ by at least one and at most three.
isSafe :: Report -> Bool
isSafe = check . reportDiff
where
check dx = (all (>= 0) dx || all (<= 0) dx)
&& all (\d -> 1 <= abs d && abs d <= 3) dx
reportDiff :: Report -> [Integer]
reportDiff r = tail $ zipWith (-) r (0:r)
-- Count how many reports are safe, if one can remove up to one
-- A report can be safe directly OR it can be safe if any of its levels can be
-- removed to make it safe.
solveB :: [Report] -> Integer
solveB = toInteger . length . filter id . fmap isSafeOrAboutSafe
isSafeOrAboutSafe :: Report -> Bool
isSafeOrAboutSafe r = isSafe r || solveA dropOneLevel > 0
where
dropOneLevel :: [Report]
dropOneLevel = filter ((== (l-1)) . length) $ subsequences r
l = length r
main :: IO ()
main = do
_input <- T.readFile "inputs/day2-example.input"
input <- T.readFile "inputs/day2.input"
putStrLn "Part 1"
let xs = fromRight [] $ P.parseOnly parseInput input
print $ solveA xs
putStrLn "Part 2"
print $ solveB xs