-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day19.hs
66 lines (58 loc) · 2.19 KB
/
Day19.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
module Day19
( part1
, part2
) where
import Intcode (Intcode, initialise, outputIntcode, sendMultInput)
findBeam :: String -> [[Int]]
findBeam intcode =
filter
((== 1) . head . outputIntcode . flip sendMultInput machine)
[[x, y] | x <- [0 .. 49], y <- [0 .. 49]]
where
machine = initialise intcode
findLargeBeam :: String -> Int
findLargeBeam intcode = findXY machine (floor refinedX) (floor refinedY)
where
shortBeam = map (\[a, b] -> (a, b)) . findBeam $ intcode
beamLine = map snd . filter ((== 35) . fst) $ shortBeam
appLowSlope = (fromIntegral . minimum $ beamLine) / 35 :: Rational
appUpSlope = (fromIntegral . maximum $ beamLine) / 35 :: Rational
firstX = 99 * (1 + appLowSlope) / (appUpSlope - appLowSlope)
minY = appLowSlope * firstX
maxY = appUpSlope * firstX
newLine =
[ y
| y <- [floor minY - 50 .. ceiling maxY + 50]
, (== 1) . head . outputIntcode . sendMultInput [floor firstX, y] $
machine
]
newLowSlope = (fromIntegral . minimum $ newLine) / firstX
newUpSlope = (fromIntegral . maximum $ newLine) / firstX
refinedX = 99 * (1 + newLowSlope) / (newUpSlope - newLowSlope)
refinedY = refinedX * newUpSlope
machine = initialise intcode
makeBeamLine :: Intcode -> Int -> Int -> [Int]
makeBeamLine machine locX locY =
[ y
| y <- [locY - 5 .. locY + 5]
, (== 1) . head . outputIntcode . sendMultInput [locX, y] $ machine
]
findXY :: Intcode -> Int -> Int -> Int
findXY machine appX appY
| isWideEnough machine appX appY &&
not (isWideEnough machine (appX - 1) maxY) &&
not (isWideEnough machine (appX - 2) maxY) &&
not (isWideEnough machine (appX - 3) maxY) = appX * 10000 + (maxY - 99)
| otherwise = findXY machine (appX - 1) maxY
where
localLine = makeBeamLine machine appX appY
maxY = maximum localLine
isWideEnough :: Intcode -> Int -> Int -> Bool
isWideEnough machine appX appY =
(== 1) . head . outputIntcode . sendMultInput [appX + 99, maxY - 99] $ machine
where
maxY = maximum . makeBeamLine machine appX $ appY
part1 :: Bool -> String -> String
part1 _ = show . length . findBeam
part2 :: Bool -> String -> String
part2 _ = show . findLargeBeam