82 lines
3.3 KiB
Haskell
82 lines
3.3 KiB
Haskell
import System.IO
|
|
import Control.Monad
|
|
import Data.Function
|
|
import Data.List
|
|
|
|
main :: IO ()
|
|
main = do
|
|
hSetBuffering stdout NoBuffering -- DO NOT REMOVE
|
|
|
|
n <- liftM read getLine :: IO Int -- the number of points used to draw the surface of Mars.
|
|
|
|
pts <- replicateM n $ do
|
|
-- land_x - X coordinate of a surface point. (0 to 6999)
|
|
-- land_y - Y coordinate of a surface point.
|
|
-- By linking all the points together in a sequential fashion, you form the surface of Mars.
|
|
(land_x:land_y:_) <- liftM (map read . words) getLine :: IO [Double]
|
|
return (land_x, land_y)
|
|
|
|
let flats = [ ((x0, x1), y0) | ((x0,y0),(x1,y1)) <- zip pts (tail pts), y1 == y0 ]
|
|
let ((lzX0, lzX1), lzY) = maximumBy (compare `on` (uncurry (-) . fst)) flats
|
|
|
|
interact $ unlines . map (unwords . map show)
|
|
. calculateOutput (lzX0, lzX1, lzY)
|
|
. map (map read . words) . lines
|
|
|
|
calculateOutput :: (Double, Double, Double) -> [[Double]] -> [[Int]]
|
|
calculateOutput (lzX0, lzX1, lzY) = snd . refoldl step (0, 0)
|
|
where
|
|
targetX = (lzX0 + lzX1) / 2.0
|
|
targetY = lzY + 50
|
|
|
|
step :: (Double, Double) -> [Double] -> ((Double, Double), Maybe [Int])
|
|
step (lostX, lostY) (x:y:hs:vs:f:r:p:_) = ((lostX', lostY'), Just [r', p'])
|
|
-- x - the current horizontal position (0 to 6999).
|
|
-- y - the current vertical position.
|
|
-- hs - the horizontal speed (in m/s), can be negative.
|
|
-- vs - the vertical speed (in m/s), can be negative.
|
|
-- f - the quantity of remaining fuel in liters.
|
|
-- r - the rotation angle in degrees (-90 to 90).
|
|
-- p - the thrust power (0 to 4).
|
|
where
|
|
angle = (r + 90) * (pi/180)
|
|
(accelX, accelY) = fromPolar (p, angle)
|
|
|
|
targetVS = (-38)
|
|
accelY' = max 0 $
|
|
if y < targetY then 4
|
|
else if abs (targetX - x) > (y - targetY) then 3.711 - 0.2*vs
|
|
else if vs > targetVS then 3
|
|
else 3.711 + 0.5*(targetVS^2 - vs^2)/(targetY - y)
|
|
|
|
rangeX = if accelY' >= 4 then 0 else sqrt (4^2 - accelY'^2)
|
|
decelTimeX = (abs hs + 0.0001) / rangeX
|
|
projectedX = x + hs * decelTimeX - 0.5 * (signum hs * rangeX) * decelTimeX^2
|
|
accelX' = max (-rangeX) $ min rangeX $ 0.2 * (-hs) + 0.02 * (targetX - projectedX)
|
|
|
|
(power', angle') = toPolar (accelX' + lostX, accelY' + lostY)
|
|
|
|
landing = (x >= lzX0 && x <= lzX1) && (y <= lzY + 100)
|
|
rightDirection = max 0 $ cos (angle - angle')
|
|
|
|
p' = max 0 $ min 4 $ round (rightDirection * power')
|
|
r' = if landing then 0 else max (-90) $ min 90 $ truncate $ ((angle' * (180/pi)) - 90)
|
|
|
|
(accelX'', accelY'') = fromPolar (fromIntegral p', fromIntegral (r'+90) * (pi/180))
|
|
|
|
lostX' = 0.8*(accelX'-accelX'')
|
|
lostY' = 0.8*(accelY'-accelY'')
|
|
|
|
fromPolar :: Floating a => (a, a) -> (a, a)
|
|
fromPolar (r, th) = (r * cos th, r * sin th)
|
|
|
|
toPolar :: RealFloat a => (a, a) -> (a, a)
|
|
toPolar (x, y) = (sqrt (x^2 + y^2), atan2 y x)
|
|
|
|
-- Like `unfoldl` combined with `foldl`, or a stateful `map`.
|
|
refoldl :: (a -> b -> (a, Maybe c)) -> a -> [b] -> (a, [c])
|
|
refoldl _ a [] = (a, [])
|
|
refoldl f a (b:bs) = case f a b of
|
|
(a', Nothing) -> (a', [])
|
|
(a', Just c ) -> let ~(a'', cs) = refoldl f a' bs in (a'', c:cs)
|