CodinGame/MarsLander/MarsLander.orig.hs

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