advent-of-code/2023/12/Main2.hs

48 lines
1.4 KiB
Haskell
Raw Normal View History

2023-12-14 00:36:26 -08:00
import Control.Monad (guard)
import Data.List.Split (splitOn)
import Data.Maybe (fromMaybe)
import qualified Data.Vector as V
import Data.Vector (Vector)
nFolds :: Int
nFolds = 5
solve :: (Vector Int, Vector Char) -> Int
solve (records, fences) = getAt 0 0
where
v = V.generate (V.length records + 1)
$ V.generate (V.length fences + 1) . getAt'
getAt r f = v V.! r V.! f
getAt' r f = maybe noFencesLeft getWithFence $ fences V.!? f
where
noFencesLeft
| r == V.length records = 1
| otherwise = 0
getWithFence thisFence = worksHere thisFence + startBreakHere
worksHere '#' = 0
worksHere _ = getAt r (f + 1)
startBreakHere = fromMaybe 0
$ do
thisRecord <- records V.!? r
let remainingFences = V.drop f fences
fenceAfter <- remainingFences V.!? thisRecord
guard $ '.' `notElem` V.take thisRecord remainingFences
guard $ fenceAfter /= '#'
return $ getAt (r + 1) (f + thisRecord + 1)
parseLine :: String -> (Vector Int, Vector Char)
parseLine l = ( unfoldRecords . map read . splitOn "," $ y
, (`V.snoc` '.') . V.tail . unfoldRecords $ '?':x)
where
(x:y:_) = splitOn " " l
unfoldRecords = V.concat . replicate nFolds . V.fromList
main :: IO ()
main = print . sum . map (solve . parseLine) . lines =<< readFile "data.txt"