Done day 18
[advent-of-code-21.git] / advent17 / Main.hs
1 -- Writeup at https://work.njae.me.uk/2021/12/19/advent-of-code-2021-day-17/
2
3 import Data.Text ()
4 import qualified Data.Text.IO as TIO
5 import Data.Attoparsec.Text hiding (take, takeWhile)
6
7 import Control.Lens
8 import Linear (V2(..), (^+^), _x, _y)
9 import Data.Ix
10
11 type Coord = V2 Int
12 type Bounds = (Coord, Coord)
13
14 data Probe = Probe {_pos :: Coord, _vel :: Coord}
15 deriving (Show, Eq)
16 makeLenses ''Probe
17
18
19
20 main :: IO ()
21 main =
22 do text <- TIO.readFile "data/advent17.txt"
23 let target = successfulParse text
24 print $ part1 target
25 print $ part2 target
26
27 part1 :: Bounds -> Int
28 part1 = findYMax
29
30 part2 :: Bounds -> Int
31 part2 target@(V2 _minXT minYT, V2 maxXT _maxYT) =
32 length $ filter (hits target) trajectories
33 where yMax = findYMax target
34 viable = (V2 0 minYT, V2 maxXT yMax)
35 launches = [Probe {_pos = V2 0 0, _vel = V2 x y}
36 | x <- [1..maxXT], y <- [minYT..(abs minYT)]
37 ]
38 trajectories = map (simulate viable) launches
39
40 findYMax :: Bounds -> Int
41 findYMax (V2 _ y, _) = y' * (y' - 1) `div` 2
42 where y' = abs y
43
44 step :: Probe -> Probe
45 step probe = probe & pos .~ (probe ^. pos ^+^ probe ^. vel) & vel .~ vel'
46 where vel' = V2 (max 0 (vx - 1)) (vy - 1)
47 V2 vx vy = probe ^. vel
48 -- v = probe ^. vel
49 -- vel' = v & _x .~ (max 0 ((v ^. _x) - 1)) & _y .~ ((v ^. _y) - 1)
50
51 simulate :: Bounds -> Probe -> [Probe]
52 simulate viable = takeWhile (within viable) . iterate step
53
54 within :: Bounds -> Probe -> Bool
55 within limits probe = inRange limits (probe ^. pos)
56
57 hits :: Bounds -> [Probe] -> Bool
58 hits target = any (within target)
59
60
61 -- Parse the input file
62
63 targetP = boundify <$> ("target area: x=" *> regionP) <*> (", y=" *> regionP)
64 where boundify (x1, x2) (y1, y2) = (V2 x1 y1, V2 x2 y2)
65
66 regionP = (,) <$> (signed decimal <* "..") <*> signed decimal
67
68 -- successfulParse :: Text -> (Integer, [Maybe Integer])
69 successfulParse input =
70 case parseOnly targetP input of
71 Left _err -> (V2 0 0, V2 0 0) -- TIO.putStr $ T.pack $ parseErrorPretty err
72 Right target -> target