60 lines
2.4 KiB
Haskell
60 lines
2.4 KiB
Haskell
module Main (main) where
|
|
|
|
import Data.List (groupBy, nub, sort, sortBy, subsequences)
|
|
import Data.Maybe (catMaybes)
|
|
|
|
-- | Part 1
|
|
data Antenna = Antenna Char (Int, Int) deriving (Show, Eq)
|
|
|
|
coords :: Antenna -> (Int, Int)
|
|
coords (Antenna _ (x, y)) = (x, y)
|
|
|
|
findAntennas :: [[Char]] -> [Antenna]
|
|
findAntennas grid =
|
|
let possibilities = [maybeAntenna (row, col) | row <- [0 .. length grid - 1], col <- [0 .. length (grid !! row) - 1]]
|
|
in catMaybes possibilities
|
|
where
|
|
maybeAntenna :: (Int, Int) -> Maybe Antenna
|
|
maybeAntenna (row, col)
|
|
| (grid !! row) !! col == '.' = Nothing
|
|
| otherwise = Just (Antenna ((grid !! row) !! col) (row, col))
|
|
|
|
calculateAntiNodes :: (Int, Int) -> (Int, Int) -> [(Int, Int)]
|
|
calculateAntiNodes (xa, ya) (xb, yb) =
|
|
let (dx, dy) = (xb - xa, yb - ya)
|
|
in [(xa - dx, ya - dy), (xb + dx, yb + dy)]
|
|
|
|
allAntiNodes :: [(Int, Int)] -> [(Int, Int)]
|
|
allAntiNodes antennas = concatMap (uncurry calculateAntiNodes . (\[a, b] -> (a, b))) $ filter ((2 ==) . length) $ subsequences antennas
|
|
|
|
outOfBounds :: [[a]] -> (Int, Int) -> Bool
|
|
outOfBounds g (row, col) = row < 0 || row >= length g || col < 0 || col >= length (g !! row)
|
|
|
|
part1 :: String -> IO ()
|
|
part1 s =
|
|
let grid = lines s
|
|
antennas = findAntennas grid
|
|
groupedAntennas = (groupBy (\(Antenna a _) (Antenna b _) -> a == b) . sortBy (\(Antenna a _) (Antenna b _) -> compare a b)) antennas
|
|
antiNodes = concatMap (filter (not . outOfBounds grid) . allAntiNodes . map coords) groupedAntennas
|
|
in print $ length $ nub antiNodes
|
|
|
|
-- | Part 2
|
|
multiplesAN :: [[a]] -> (Int, Int) -> (Int, Int) -> [(Int, Int)]
|
|
multiplesAN grid (xa, ya) (xb, yb) =
|
|
let (dx, dy) = (xb - xa, yb - ya)
|
|
in (takeWhile (not . outOfBounds grid) [(xa - dx * i, ya - dy * i) | i <- [0 ..]]) ++ takeWhile (not . outOfBounds grid) [(xb + dx * i, yb + dy * i) | i <- [0 ..]]
|
|
|
|
allMultiplesAN :: [[a]] -> [(Int, Int)] -> [(Int, Int)]
|
|
allMultiplesAN grid antennas = foldr (\[a, b] l -> multiplesAN grid a b ++ l) [] $ filter ((2 ==) . length) $ subsequences antennas
|
|
|
|
part2 :: String -> IO ()
|
|
part2 s =
|
|
let grid = lines s
|
|
antennas = findAntennas grid
|
|
groupedAntennas = (groupBy (\(Antenna a _) (Antenna b _) -> a == b) . sortBy (\(Antenna a _) (Antenna b _) -> compare a b)) antennas
|
|
antiNodes = concatMap (allMultiplesAN grid . map coords) groupedAntennas
|
|
in print $ length $ nub antiNodes
|
|
|
|
-- | Main
|
|
main :: IO ()
|
|
main = readFile "resources/day8.txt" >>= part2
|