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 = (+ startBreakHere) . worksHere 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"