Day 2
This commit is contained in:
parent
642a3c5773
commit
f8f4db3d7e
6 changed files with 1066 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
result*
|
result*
|
||||||
*.cabal
|
*.cabal
|
||||||
|
dist-newstyle
|
||||||
|
|
4
Main.hs
4
Main.hs
|
@ -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
|
||||||
|
|
6
inputs/day2-example.input
Normal file
6
inputs/day2-example.input
Normal 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
1000
inputs/day2.input
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
55
src/Day2.hs
Normal 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
|
Loading…
Reference in a new issue