import Control.Lens import Data.List.Split import Linear.V2 type Sensor = (V2 Int, V2 Int) main :: IO () main = do input <- map (splitOneOf "=,:") . lines <$> readFile "input" let sensors = map parse input print $ "Cave from to: " ++ show (caveMinMaxX sensors) print $ part1 (caveMinMaxX sensors) sensors print $ part2 sensors getBorder :: [Sensor] -> [V2 Int] getBorder (s:ss) = map (+ fst s) xs ++ getBorder ss where xs = concat $ take 4 $ iterate (map perp) [V2 x (d - x) | x <- [0 .. pred d]] d = succ $ dist s getBorder [] = [] caveMinMaxX :: [Sensor] -> (Int, Int) caveMinMaxX sensors = (minimum k, maximum l) where d = map dist sensors s = map (view _y . fst) sensors k = zipWith (-) s d l = zipWith (+) s d part1 :: (Int, Int) -> [Sensor] -> Int part1 (a, b) sensors = length $ filter (== '#') $ map (checkPoint sensors) xs where xs = [V2 x 2000000 | x <- [a .. b]] --y=10 for testinput part2 :: [Sensor] -> Int part2 sensors = f $ head $ filter (\x -> checkPoint sensors x == ' ') $ filter (\(V2 x y) -> x >= 0 && x <= 4000000 && y >= 0 && y <= 4000000) $ getBorder sensors -- <=20 for testinput where f = (+) <$> view _y <*> ((*) 4000000 . view _x) parse :: [String] -> Sensor parse [_, a, _, b, _, c, _, d] = (V2 (read a) (read b), V2 (read c) (read d)) checkPoint :: [Sensor] -> V2 Int -> Char checkPoint sensors point | point `elem` map fst sensors = 'S' | point `elem` map snd sensors = 'B' | otherwise = checkPoint' sensors point where checkPoint' (s:ss) p = if dist (fst s, p) <= dist s then '#' else checkPoint' ss p checkPoint' [] _ = ' ' dist :: Sensor -> Int dist (a, b) = sum $ abs $ a - b