4 | import Data.List.Lazy
5 | import Control.Monad.State
10 | data Cell : Type where
12 | Antenna : (freq : Char) -> Cell
14 | charToCell : Char -> Cell
15 | charToCell '.' = Empty
16 | charToCell c = Antenna c
18 | cellToChar : Cell -> Char
19 | cellToChar Empty = '.'
20 | cellToChar (Antenna freq) = freq
22 | cellToAntenna : Cell -> Maybe Char
23 | cellToAntenna Empty = Nothing
24 | cellToAntenna (Antenna freq) = Just freq
29 | grid : Grid rows cols Cell
30 | antinodes : Grid rows cols Bool
33 | isAntenna : Coord rows cols -> Grid rows cols Cell -> Bool
35 | case x `index` xs of
39 | antinodePositions : (input : Input) -> LazyList (Coord input.rows input.cols)
40 | antinodePositions (MkInput rows cols grid antinodes) =
41 | map fst . filter snd . flat $
antinodes
43 | markAntinode : (input : Input) -> Coord input.rows input.cols -> Input
44 | markAntinode (MkInput rows cols grid antinodes) x =
45 | let antinodes = replaceAt x True antinodes
46 | in MkInput rows cols grid antinodes
50 | let char_grid = mapGrid cellToChar input.grid
51 | (char_grid, _) = runState char_grid (markAntinodes (antinodePositions input))
52 | in gridToString char_grid
54 | markAntinodes : LazyList (Coord input.rows input.cols)
55 | -> State (Grid input.rows input.cols Char) ()
56 | markAntinodes [] = pure ()
57 | markAntinodes (x :: xs) = do
58 | unless (isAntenna x input.grid) (modify $
replaceAt x '#')
61 | uniqueAntennas : Input -> List Char
62 | uniqueAntennas input =
63 | nub . toList . mapMaybe cellToAntenna . map snd . flat $
input.grid
66 | locateAntennas : (freq : Char) -> (input : Input) -> LazyList (Coord input.rows input.cols)
67 | locateAntennas freq input =
68 | map fst . filter ((== Just freq) . cellToAntenna . snd) . flat $
input.grid
70 | coordToIntegers : Coord rows cols -> (Integer, Integer)
71 | coordToIntegers (x, y) = (finToInteger x, finToInteger y)
73 | integersToCoords : {rows, cols : Nat} -> (Integer, Integer) -> Maybe (Coord rows cols)
74 | integersToCoords (x, y) = do
75 | x <- integerToFin x (S rows)
76 | y <- integerToFin y (S cols)
79 | addVector : (Integer, Integer) -> (Integer, Integer) -> (Integer, Integer)
80 | addVector (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
82 | subVector : (Integer, Integer) -> (Integer, Integer) -> (Integer, Integer)
83 | subVector (x1, y1) (x2, y2) = (x1 - x2, y1 - y2)
85 | negVector : (Integer, Integer) -> (Integer, Integer)
86 | negVector (x, y) = (-
1 * x, -
1 * y)
89 | markLocation : (Integer, Integer) -> State Input ()
92 | case integersToCoords x of
94 | Just x => put $
markAntinode input x
97 | markLocation' : (loc, offset : (Integer, Integer)) -> State Input ()
98 | markLocation' loc offset = do
100 | case integersToCoords loc of
103 | put $
markAntinode input x
104 | markLocation' (loc `addVector` offset) offset
108 | markPair : (a1, a2 : (Integer, Integer)) -> State Input ()
110 | let diff = a1 `subVector` a2
111 | node1 = a1 `addVector` diff
112 | node2 = a2 `subVector` diff
117 | markPair' : (a1, a2 : (Integer, Integer)) -> State Input ()
119 | let offset = a1 `subVector` a2
121 | markLocation' a1 offset
122 | markLocation' a1 (negVector offset)
125 | markFrequency : (freq : Char) -> State Input ()
126 | markFrequency freq = do
128 | let antennas = map coordToIntegers $
locateAntennas freq input
129 | let pairs = allPairs antennas
132 | markPairs : LazyList ((Integer, Integer), (Integer, Integer)) -> State Input ()
133 | markPairs [] = pure ()
134 | markPairs ((x, y) :: xs) = do
138 | markFrequency' : (freq : Char) -> State Input ()
139 | markFrequency' freq = do
141 | let antennas = map coordToIntegers $
locateAntennas freq input
142 | let pairs = allPairs antennas
145 | markPairs : LazyList ((Integer, Integer), (Integer, Integer)) -> State Input ()
146 | markPairs [] = pure ()
147 | markPairs ((x, y) :: xs) = do
152 | markAll : State Input ()
155 | let frequencies = uniqueAntennas input
156 | traverse_ markFrequency frequencies
158 | markAll' : State Input ()
161 | let frequencies = uniqueAntennas input
162 | traverse_ markFrequency' frequencies
164 | parseInput : String -> Maybe Input
165 | parseInput str = do
166 | (
rows ** cols ** grid)
<- stringTo2D str
167 | let grid = mapGrid charToCell grid
168 | Just $
MkInput rows cols grid (const False)
171 | part1 : String -> IO (String, Input)
173 | Just input <- pure $
parseInput str
175 | putStrLn "Failed parsing input"
177 | let (stepped, _) = runState input markAll
178 | pure $
(show . count (const True) $
(antinodePositions stepped), input)
181 | part2 : Input -> String -> IO String
183 | let (stepped, _) = runState input markAll'
184 | pure . show . count (const True) $
antinodePositions stepped