content: module MountainCar where
  
  minPosition :: Double
  minPosition = -1.2
  
  maxPosition :: Double
  maxPosition = 0.6
  
  minInitPos :: Double
  minInitPos = -0.6
  
  maxInitPos :: Double
  maxInitPos = -0.4
  
  maxSpeed :: Double
  maxSpeed = 0.07
  
  goalPosition :: Double
  goalPosition = 0.5
  
  force :: Double
  force = 0.001
  
  gravity :: Double
  gravity = 0.0025
  
  data Action = ActionLeft | ActionNothing | ActionRight
  
  instance Show Action where
      show ActionLeft = "<"
      show ActionRight = ">"
      show ActionNothing = "="
  
  data Observation = Observation
      { _position :: Double
      , _velocity :: Double }
  
  initObs :: Double -> Observation
  initObs xi = Observation (minInitPos + xi * (maxInitPos - minInitPos)) 0
  
  goalObs :: Observation -> Bool
  goalObs obs = _position obs >= goalPosition
  
  heightObs :: Double -> Double
  heightObs x = 0.55 + 0.45 * sin (3 * x)
  
  stepObs :: Action -> Observation -> Observation
  stepObs action obs = obs { _position = p2, _velocity = v3 }
      where dv = case action of ActionNothing -> 0
                                ActionLeft -> -force
                                ActionRight -> force
            v1 = _velocity obs + dv - gravity * cos (3 * _position obs)
            v2 = max (-maxSpeed) $ min maxSpeed v1
            p1 = _position obs + v2
            p2 = max minPosition $ min maxPosition p1
            v3 = if p2 == minPosition && v2 < 0 then 0 else v2
  
  