104 lines
4.7 KiB
Haskell
104 lines
4.7 KiB
Haskell
import System.IO
|
|
import Control.Monad
|
|
import Data.Function
|
|
import Data.List
|
|
import Data.IORef
|
|
|
|
infinity :: Floating a => a
|
|
infinity = 1.0/0.0
|
|
|
|
main :: IO ()
|
|
main = do
|
|
hSetBuffering stdout NoBuffering -- DO NOT REMOVE
|
|
|
|
-- Auto-generated code below aims at helping you parse
|
|
-- the standard input according to the problem statement.
|
|
|
|
input_line <- getLine
|
|
let n = read input_line :: Int -- the number of points used to draw the surface of Mars.
|
|
|
|
pts <- replicateM n $ do
|
|
input_line <- getLine
|
|
let input = words input_line
|
|
let land_x = read (input!!0) :: Int -- X coordinate of a surface point. (0 to 6999)
|
|
let land_y = read (input!!1) :: Int -- Y coordinate of a surface point. By linking all the points together in a sequential fashion, you form the surface of Mars.
|
|
return (land_x, land_y)
|
|
let flats = [ ((x0, x1, y0), x1-x0) | ((x0,y0),(x1,y1)) <- zip pts (tail pts), y1 == y0 ]
|
|
let ((lzX0, lzX1, lzY), _) = maximumBy (compare `on` snd) flats
|
|
|
|
lostPower <- newIORef (0.0, 0.0)
|
|
|
|
fix $ \loop -> do
|
|
input_line <- getLine
|
|
let input = words input_line
|
|
let x = read (input!!0) :: Int
|
|
let y = read (input!!1) :: Int
|
|
let hs = read (input!!2) :: Int -- the horizontal speed (in m/s), can be negative.
|
|
let vs = read (input!!3) :: Int -- the vertical speed (in m/s), can be negative.
|
|
let f = read (input!!4) :: Int -- the quantity of remaining fuel in liters.
|
|
let r = read (input!!5) :: Int -- the rotation angle in degrees (-90 to 90).
|
|
let p = read (input!!6) :: Int -- the thrust power (0 to 4).
|
|
|
|
-- hPutStrLn stderr "Debug messages..."
|
|
|
|
let currentX = fromIntegral x
|
|
let currentY = fromIntegral y
|
|
let targetX = fromIntegral (lzX0 + lzX1) / 2.0
|
|
let targetY = fromIntegral lzY + 50
|
|
let veloX = fromIntegral hs
|
|
let veloY = fromIntegral vs
|
|
let accelX = fromIntegral p * sin (pi * fromIntegral (-r) / 180)
|
|
let accelY = fromIntegral p * cos (pi * fromIntegral (-r) / 180)
|
|
|
|
let maxAccelY = 0.1
|
|
let decelTimeY = if veloY >= 0 then 0
|
|
else (-veloY) / maxAccelY
|
|
let decelDistY = (-veloY) * decelTimeY - 0.5 * maxAccelY * decelTimeY^2
|
|
|
|
let descend = currentY - targetY > decelDistY
|
|
|| (currentX >= fromIntegral lzX0 + 100
|
|
&& currentX <= fromIntegral lzX1 - 100
|
|
&& abs veloX <= 40)
|
|
let targetVeloY = if currentY > targetY + 300 then -60
|
|
else if descend then -30
|
|
else if currentY < targetY then 4
|
|
else 0
|
|
|
|
let projectedY = currentY + veloY * (2 * (targetX - currentX) / veloX)
|
|
|
|
let minAccelY = 3.711 + (38^2 + 38 * veloY) / (targetY - projectedY)
|
|
|
|
let accelY' = min 3.95 $ max minAccelY $
|
|
if targetVeloY < veloY then 0
|
|
else 3.711 + min maxAccelY (0.04 * (targetVeloY - veloY))
|
|
|
|
let rangeX = if accelY' >= 4 then 0.0 else sqrt (4^2 - accelY'^2)
|
|
let decelTimeX = if rangeX < 0.001 then infinity else abs veloX / rangeX
|
|
let projectedX = currentX + veloX * decelTimeX
|
|
- 0.5 * (signum veloX * rangeX) * decelTimeX^2
|
|
|
|
let accelX' = if projectedX > fromIntegral lzX1 - 200 then -rangeX
|
|
else if projectedX < fromIntegral lzX0 + 200 then rangeX
|
|
else max (-rangeX) $ min rangeX $ 0.2 * (-veloX)
|
|
|
|
(lpX, lpY) <- readIORef lostPower
|
|
|
|
let landing = currentX >= fromIntegral lzX0
|
|
&& currentY <= fromIntegral lzX1
|
|
&& currentY <= fromIntegral lzY + 100
|
|
let angle' = if landing then 0 else (atan2 (accelY'+lpY) (accelX'+lpX) * (180.0/pi)) - 90
|
|
let rightDirection = max 0 $ cos (pi / 180 * (fromIntegral r - angle'))
|
|
|
|
let power' = rightDirection * sqrt ((accelX'+lpX)^2 + (accelY'+lpY)^2)
|
|
let p' = max 0 $ min 4 $ round power'
|
|
let r' = max (-90) $ min 90 $ truncate $ angle'
|
|
|
|
let accelX'' = fromIntegral p' * sin (pi * fromIntegral (-r') / 180)
|
|
let accelY'' = fromIntegral p' * cos (pi * fromIntegral (-r') / 180)
|
|
|
|
writeIORef lostPower (0.8*(accelX'-accelX''), 0.8*(accelY'-accelY''))
|
|
|
|
-- R P. R is the desired rotation angle. P is the desired thrust power.
|
|
putStrLn $ show r' ++ " " ++ show p'
|
|
|
|
loop |