module Commons where import GHC.IO.Handle (isEOF) import Data.Array (Array, bounds, listArray, (!)) data Tile = Ash | Rock deriving (Eq, Show) type Pattern = Array (Int, Int) Tile parseLine :: String -> [Tile] parseLine [] = [] parseLine ('.': t) = Ash: parseLine t parseLine ('#': t) = Rock: parseLine t parsePattern :: IO [[Tile]] parsePattern = do done <- isEOF if done then return [] else do line <- getLine if null line then return [] else do let parsedLine = parseLine line otherLines <- parsePattern return $ parsedLine: otherLines parsePatterns :: [[[Tile]]] -> IO [Pattern] parsePatterns otherPatterns = do done <- isEOF if done then return $ map (\ p -> listArray ((1, 1), (length p, length (p !! 1))) $ concat p) otherPatterns else do pattern <- parsePattern parsePatterns $ otherPatterns ++ [pattern] parse :: IO [Pattern] parse = parsePatterns [] isLineReflected :: (Int, Int) -> (Int, Int) -> Pattern -> Bool isLineReflected (y1, x1) (y2, x2) p | x1 < 1 || x2 > snd (snd $ bounds p) = True | otherwise = p ! (y1, x1) == p ! (y2, x2) && isLineReflected (y1, x1 - 1) (y2, x2 + 1) p isVerticalReflection :: (Int, Int) -> Pattern -> Bool isVerticalReflection (y, x) p | y <= fst (snd $ bounds p) = isLineReflected (y, x) (y, x + 1) p && isVerticalReflection (y + 1, x) p | otherwise = True isColReflected :: (Int, Int) -> (Int, Int) -> Pattern -> Bool isColReflected (y1, x1) (y2, x2) p | y1 < 1 || y2 > fst (snd $ bounds p) = True | otherwise = p ! (y1, x1) == p ! (y2, x2) && isColReflected (y1 - 1, x1) (y2 + 1, x2) p isHorizontalReflection :: (Int, Int) -> Pattern -> Bool isHorizontalReflection (y, x) p | x <= snd (snd $ bounds p) = isColReflected (y, x) (y + 1, x) p && isHorizontalReflection (y, x + 1) p | otherwise = True getVerticalReflection :: Int -> Int -> Pattern -> Int getVerticalReflection x ignore p | x >= snd (snd $ bounds p) = 0 | x == ignore = getVerticalReflection (x + 1) ignore p | isVerticalReflection (1, x) p = x | otherwise = getVerticalReflection (x + 1) ignore p getHorizontalReflection :: Int -> Int -> Pattern -> Int getHorizontalReflection y ignore p | y >= fst (snd $ bounds p) = 0 | y == ignore = getHorizontalReflection (y + 1) ignore p | isHorizontalReflection (y, 1) p = y | otherwise = getHorizontalReflection (y + 1) ignore p