module Day8.Main where import System.IO import Data.List main :: IO () main = do putStrLn "Day 8" handle <- openFile "app/Day8/input" ReadMode contents <- hGetContents handle let r1 = part1 contents putStrLn $ "part 1: " ++ show r1 let r2 = part2 contents putStrLn $ "part 2: " ++ show r2 type Tree = (Int,[Int],[Int],[Int],[Int]) -- Self, N, E, S, W enumerate :: [a] -> [(Int, a)] enumerate = zip [0..] parseData :: String -> [[Int]] parseData contents = (map . map) (read . singleton :: Char -> Int) $ lines contents toTrees :: [[Int]] -> [Tree] toTrees rows = [(tree, north r c, east r c, south r c, west r c) | (r, line) <- enumerate rows, (c, tree) <- enumerate line] where columns = transpose rows east r c = drop (c + 1) $ rows !! r west r c = reverse $ take c $ rows !! r north r c = reverse $ take r $ columns !! c south r c = drop (r + 1) $ columns !! c isVisible :: Int -> [Int] -> Bool isVisible _ [] = True isVisible t ts = all (< t) ts invisibleFromOutside :: Tree -> Bool invisibleFromOutside (t,n,e,s,w) = all (not . isVisible t) [n,e,s,w] part1 :: String -> Int part1 = length . filter (not . invisibleFromOutside) . toTrees . parseData -- Includive version of takeWhile (because lentgh takeWhile + 1 doesn't work for when the outer border is the reason you can't see further) takeWhileI :: (a -> Bool) -> [a] -> [a] takeWhileI _ [] = [] takeWhileI p (x:xs) = x : if p x then takeWhileI p xs else [] viewingDistance :: Int -> [Int] -> Int viewingDistance t ts = length $ takeWhileI (< t) ts scenicScore :: Tree -> Int scenicScore (t,n,e,s,w) = product $ map (viewingDistance t) [n,e,s,w] part2 :: String -> Int part2 = maximum . map scenicScore . toTrees . parseData