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*
|
||||
*.cabal
|
||||
dist-newstyle
|
||||
|
|
4
Main.hs
4
Main.hs
|
@ -3,10 +3,12 @@
|
|||
module Main where
|
||||
|
||||
import Day1
|
||||
import Day2
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
putStrLn "AoC 2024"
|
||||
putStrLn "Day 1"
|
||||
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
|
||||
exposed-modules:
|
||||
- Day1
|
||||
# - Day2
|
||||
- Day2
|
||||
# - Day3
|
||||
# - Day4
|
||||
# - 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