2023-12-16 21:53:51 +01:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
module Day12 where
|
|
|
|
|
|
|
|
import Data.Void (Void)
|
|
|
|
import Data.Text (Text)
|
2023-12-17 00:00:31 +01:00
|
|
|
import Data.List (intercalate)
|
2023-12-16 21:53:51 +01:00
|
|
|
import Text.Megaparsec (Parsec, errorBundlePretty, runParser, many, eof, choice, sepBy)
|
2023-12-17 00:00:31 +01:00
|
|
|
import Data.Bifunctor (first, bimap)
|
2023-12-16 21:53:51 +01:00
|
|
|
import Text.Megaparsec.Char (char, space, newline)
|
|
|
|
import Text.Megaparsec.Char.Lexer (decimal)
|
|
|
|
|
|
|
|
|
|
|
|
data Cell
|
|
|
|
= U -- ? unknown
|
|
|
|
| O -- . operational
|
|
|
|
| D -- # damaged
|
2023-12-16 23:46:21 +01:00
|
|
|
deriving (Show, Eq)
|
2023-12-16 21:53:51 +01:00
|
|
|
|
|
|
|
type Row = ([Cell], [Int])
|
|
|
|
|
|
|
|
type Parser = Parsec Void Text
|
|
|
|
|
|
|
|
|
|
|
|
input :: Text
|
|
|
|
input =
|
|
|
|
"???.### 1,1,3\n\
|
|
|
|
\.??..??...?##. 1,1,3\n\
|
|
|
|
\?#?#?#?#?#?#?#? 1,3,1,6\n\
|
|
|
|
\????.#...#... 4,1,1\n\
|
|
|
|
\????.######..#####. 1,6,5\n\
|
|
|
|
\?###???????? 3,2,1\n"
|
|
|
|
|
|
|
|
parse :: Text -> Either String [Row]
|
|
|
|
parse = first errorBundlePretty . runParser rows ""
|
|
|
|
where
|
|
|
|
cell :: Parser Cell
|
|
|
|
cell = choice [U <$ char '?', O <$ char '.', D <$ char '#']
|
|
|
|
row :: Parser Row
|
|
|
|
row = do
|
|
|
|
cs <- many cell <* space
|
|
|
|
ns <- decimal `sepBy` char ',' <* newline
|
|
|
|
return (cs, ns)
|
|
|
|
rows :: Parser [Row]
|
|
|
|
rows = many row <* eof
|
|
|
|
|
|
|
|
arrange :: [Cell] -> [Int] -> [[Cell]]
|
2023-12-16 23:46:21 +01:00
|
|
|
arrange [] [] = [[]]
|
|
|
|
arrange [] _ = []
|
|
|
|
arrange cs []
|
|
|
|
| D `notElem` cs = [map (const O) cs]
|
|
|
|
| otherwise = []
|
|
|
|
arrange cs@(c:cr) ns@(n:nr)
|
|
|
|
| canFill && canSkip = tryFill <> trySkip
|
|
|
|
| canFill = tryFill
|
|
|
|
| canSkip = trySkip
|
|
|
|
| otherwise = []
|
|
|
|
where
|
|
|
|
(window, rest) = splitAt n cs
|
|
|
|
fill :: [Cell] -> [Cell]
|
|
|
|
fill = (replicate n D ++)
|
|
|
|
canSkip :: Bool
|
|
|
|
canSkip = c /= D
|
|
|
|
trySkip :: [[Cell]]
|
|
|
|
trySkip = map (O:) (arrange cr ns)
|
|
|
|
canFill :: Bool
|
|
|
|
canFill = O `notElem` window && n == length window && (null rest || head rest /= D)
|
|
|
|
tryFill :: [[Cell]]
|
|
|
|
tryFill
|
|
|
|
| null rest = map fill (arrange rest nr)
|
|
|
|
| otherwise = map (fill . (O:)) (arrange (tail rest) nr)
|
2023-12-16 21:53:51 +01:00
|
|
|
|
|
|
|
solveA :: [Row] -> Int
|
|
|
|
solveA = length . concatMap (uncurry arrange)
|
|
|
|
|
2023-12-17 00:00:31 +01:00
|
|
|
unfold :: Row -> Row
|
|
|
|
unfold = bimap (intercalate [U] . replicate 5) (concat . replicate 5)
|
2023-12-16 21:53:51 +01:00
|
|
|
|
2023-12-17 00:00:31 +01:00
|
|
|
solveB :: [Row] -> Int
|
|
|
|
solveB = solveA . map unfold . take 5
|