@@ -43,37 +43,64 @@ import qualified Data.Vector as V
43
43
import qualified Linear as L
44
44
import Safe
45
45
import qualified Text.Megaparsec as P
46
+ import Data.Complex
46
47
import qualified Text.Megaparsec.Char as P
47
48
import qualified Text.Megaparsec.Char.Lexer as PP
48
49
49
- day17a :: [Int ] :~> _
50
+ parseBox :: String -> Maybe (V2 Point )
51
+ parseBox = getBounds <=< traverse readMaybe . words . clearOut valid
52
+ where
53
+ valid k = not (isDigit k || k == ' -' )
54
+ getBounds = \ case
55
+ [x1,x2,y1,y2] -> do
56
+ [xMin, xMax] <- pure $ sort [x1,x2]
57
+ [yMin, yMax] <- pure $ sort [y1,y2]
58
+ pure $ V2 (V2 xMin yMin) (V2 xMax yMax)
59
+ _ -> Nothing
60
+
61
+ -- | Independent tight bounds for each axis
62
+ velBounds :: V2 Point -> V2 Point
63
+ velBounds (V2 (V2 x1 y1) (V2 x2 _)) = V2 (V2 vx1 y1) (V2 x2 (abs y1))
64
+ where
65
+ vx1 = case quadraticEq (- fromIntegral x1) 0.5 0.5 of
66
+ QReal a b -> ceiling (max a b)
67
+ QSimul a -> ceiling a
68
+ QComplex _ _ -> error " invalid box"
69
+
70
+ data QuadraticSol = QReal Double Double
71
+ | QSimul Double
72
+ | QComplex (Complex Double ) (Complex Double )
73
+
74
+ quadraticEq :: Double -> Double -> Double -> QuadraticSol
75
+ quadraticEq a b c = case compare discr 0 of
76
+ LT -> QComplex (term1 :+ term2) (term1 :+ (- term2))
77
+ EQ -> QSimul term1
78
+ GT -> QReal (term1 + term2) (term1 - term2)
79
+ where
80
+ discr = b* b - 4 * a * c
81
+ term1 = - 0.5 * b/ a
82
+ term2 = 0.5 * sqrt (abs discr) / a
83
+
84
+ day17a :: V2 Point :~> _
50
85
day17a = MkSol
51
- { sParse = traverse readMaybe . words . clearOut ( \ k -> not (isDigit k || k == ' - ' ))
86
+ { sParse = parseBox
52
87
, sShow = show
53
- , sSolve = \ [x1,x2,y1,y2] -> maximumMay
54
- [ mx
55
- | x <- [- 100 .. 100 ]
56
- , y <- [- 100 .. 100 ]
57
- , let steps = stepUntilTooDeep (min y1 y2) (V2 x y)
58
- , any (inBoundingBox (V2 (V2 (min x1 x2) (min y1 y2)) (V2 (max x1 x2) (max y1 y2))))
59
- steps
60
- , Just mx <- [maximumMay (map (view _y) steps)]
61
- ]
62
- -- exponentialSearch
63
- -- inBoundingBox
64
- -- :: (Applicative g, Foldable g, Ord a)
65
- -- => V2 (g a)
66
- -- -> g a
67
- -- -> Bool
68
- -- :: (Int -> Ordering) -- LT: Too small, GT: Too big
69
- -- -> Int
70
- -- -> Maybe Int
88
+ , sSolve = \ (bbox@ (V2 (V2 _ y1) (V2 x2 _))) ->
89
+ let V2 (V2 vx1 vy1) (V2 vx2 vy2) = velBounds bbox
90
+ in maximumMay
91
+ [ mx
92
+ | x <- [vx1.. vx2]
93
+ , y <- [vy1.. vy2]
94
+ , let steps = stepUntilTooDeep x2 y1 (V2 x y)
95
+ , any (inBoundingBox bbox) steps
96
+ , Just mx <- [maximumMay (map (view _y) steps)]
97
+ ]
71
98
}
72
99
73
- stepUntilTooDeep :: Int -> Point -> [Point ]
74
- stepUntilTooDeep ymin v0 = map fst . takeWhile p $ iterate simStep (0 , v0)
100
+ stepUntilTooDeep :: Int -> Int -> Point -> [Point ]
101
+ stepUntilTooDeep xmax ymin v0 = map fst . takeWhile p $ iterate simStep (0 , v0)
75
102
where
76
- p (V2 _ y, _) = y >= ymin
103
+ p (V2 x y, _) = y >= ymin && x <= xmax
77
104
78
105
simStep :: (Point , Point ) -> (Point , Point )
79
106
simStep (pos, vel@ (V2 vx vy)) = (pos + vel, vel')
@@ -82,17 +109,15 @@ simStep (pos, vel@(V2 vx vy)) = (pos + vel, vel')
82
109
83
110
-- target area: x=248..285, y=-85..-56
84
111
85
- day17b :: _ :~> _
112
+ day17b :: V2 Point :~> _
86
113
day17b = MkSol
87
114
{ sParse = sParse day17a
88
- , sShow = show
89
- , sSolve = \ [x1,x2,y1,y2] -> Just $ length
90
- [ mx
91
- | x <- [- 500 .. 500 ]
92
- , y <- [- 500 .. 500 ]
93
- , let steps = stepUntilTooDeep (min y1 y2) (V2 x y)
94
- , any (inBoundingBox (V2 (V2 (min x1 x2) (min y1 y2)) (V2 (max x1 x2) (max y1 y2))))
95
- steps
96
- , Just mx <- [maximumMay (map (view _y) steps)]
97
- ]
115
+ , sShow = show
116
+ , sSolve = \ (bbox@ (V2 (V2 _ y1) (V2 x2 _))) ->
117
+ let V2 (V2 vx1 vy1) (V2 vx2 vy2) = velBounds bbox
118
+ in Just $ countTrue (any (inBoundingBox bbox))
119
+ [ stepUntilTooDeep x2 y1 (V2 x y)
120
+ | x <- [vx1.. vx2]
121
+ , y <- [vy1.. vy2]
122
+ ]
98
123
}
0 commit comments