Skip to content
This repository was archived by the owner on Nov 17, 2024. It is now read-only.

Commit d315f56

Browse files
committed
implement tight bounding box for day 17
1 parent 8d3caa8 commit d315f56

File tree

1 file changed

+59
-34
lines changed

1 file changed

+59
-34
lines changed

src/AOC/Challenge/Day17.hs

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,37 +43,64 @@ import qualified Data.Vector as V
4343
import qualified Linear as L
4444
import Safe
4545
import qualified Text.Megaparsec as P
46+
import Data.Complex
4647
import qualified Text.Megaparsec.Char as P
4748
import qualified Text.Megaparsec.Char.Lexer as PP
4849

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 :~> _
5085
day17a = MkSol
51-
{ sParse = traverse readMaybe . words . clearOut (\k -> not (isDigit k || k == '-'))
86+
{ sParse = parseBox
5287
, 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+
]
7198
}
7299

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)
75102
where
76-
p (V2 _ y, _) = y >= ymin
103+
p (V2 x y, _) = y >= ymin && x <= xmax
77104

78105
simStep :: (Point, Point) -> (Point, Point)
79106
simStep (pos, vel@(V2 vx vy)) = (pos + vel, vel')
@@ -82,17 +109,15 @@ simStep (pos, vel@(V2 vx vy)) = (pos + vel, vel')
82109

83110
-- target area: x=248..285, y=-85..-56
84111

85-
day17b :: _ :~> _
112+
day17b :: V2 Point :~> _
86113
day17b = MkSol
87114
{ 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+
]
98123
}

0 commit comments

Comments
 (0)