import Data.List type Vec = (Int, Int) type Ant = (Int, Int, Char) type Map = (Vec, [Ant]) consume2 :: [Ant] -> Int -> Int -> [Char] -> [Ant] consume2 acc _ _ [] = acc consume2 acc r c ('.':t) = consume2 acc r (c+1) t consume2 acc r c (h:t) = consume2 ((r, c, h):acc) r (c+1) t consume1 :: [Ant] -> Int -> [[Char]] -> [Ant] consume1 acc _ [] = acc consume1 acc r (h:t) = consume1 (acc ++ (consume2 [] r 0 h)) (r+1) t consume :: [Char] -> Map consume file = ((length grid, length $ head grid), consume1 [] 0 grid) where grid = lines file neg :: Vec -> Vec neg (r, c) = (-r, -c) add :: Vec -> Vec -> Vec add (fr, fc) (dr, dc) = (fr + dr, fc + dc) scale :: Int -> Vec -> Vec scale m (r, c) = (r * m, c * m) path :: (Vec, Vec) -> Vec path (f, t) = add t $ neg f inside :: Vec -> Vec -> Bool inside (mr, mc) (r, c) = r >= 0 && r < mr && c >= 0 && c < mc simplify :: Vec -> Vec simplify (r, c) = (r `div` d, c `div` d) where d = gcd r c antiNodes :: Map -> Char -> [Vec] antiNodes (size, ants) freq = filter (inside size) $ map (\p@(f, _) -> add f $ scale 2 $ path p) pairs where fants = filter (\(_, _, f) -> f == freq) ants coos = map (\(r, c, _) -> (r, c)) fants pairs = [(a1, a2) | a1 <- coos, a2 <- coos, a1 /= a2] antiNodes22 :: [Vec] -> Vec -> Vec -> Vec -> [Vec] antiNodes22 acc size from del | inside size nxt = antiNodes22 (nxt:acc) size nxt del | otherwise = acc where nxt = add from del antiNodes21 :: Vec -> (Vec, Vec) -> [Vec] antiNodes21 s p@(f, t) = antiNodes22 [] s f d ++ [f] ++ antiNodes22 [] s f (neg d) where d = simplify $ path p antiNodes2 :: Map -> Char -> [Vec] antiNodes2 (size, ants) freq = nub $ concat $ map (antiNodes21 size) pairs where fants = filter (\(_, _, f) -> f == freq) ants coos = map (\(r, c, _) -> (r, c)) fants pairs = [(a1, a2) | a1 <- coos, a2 <- coos, a1 /= a2] part1 mp@(_, ants) = length $ nub $ concat $ map (antiNodes mp) freqs where freqs = nub $ map (\(_, _, f) -> f) ants part2 mp@(_, ants) = length $ nub $ concat $ map (antiNodes2 mp) freqs where freqs = nub $ map (\(_, _, f) -> f) ants main = do file <- readFile "day08.input" let mp = consume file putStrLn ("Part 1: " ++ (show $ part1 mp)) putStrLn ("Part 2: " ++ (show $ part2 mp))