module Utils where import System.IO import Data.List hiding (foldl') import Data.Foldable import Data.Char import Control.Monad import System.Random import Control.Monad.State import Collision getOneChar :: IO Char getOneChar = do b <- hGetBuffering stdin hSetBuffering stdin NoBuffering c <- getChar putStrLn "" hSetBuffering stdin b return c readInt :: String -> Maybe Int readInt = safeRead safeRead :: (Read a) => String -> Maybe a safeRead s = case reads s of [(n, _)] -> Just n _ -> Nothing putStrGetDigit :: String -> IO Int putStrGetDigit s = do when (not (null s)) $ putStrLn s n <- getOneChar case readInt [n] of Just p -> return p Nothing -> putStrGetDigit s getDigit :: IO Int getDigit = putStrGetDigit "" putStrGetNumber :: String -> IO Int putStrGetNumber s = do when (not (null s)) $ putStrLn s n <- getLine if null n then putStrGetNumber s else case readInt n of Just p -> return p Nothing -> putStrGetNumber s getNumber :: IO Int getNumber = putStrGetNumber "" pick :: [(a -> Bool, b)] -> a -> Maybe b pick [] _ = Nothing pick ((f, s):ns) x = if f x then Just s else pick ns x getFromTable :: String -> [(String, a)] -> Maybe a getFromTable _ [] = Nothing getFromTable c ((d, h):ds) = if c `isPrefixOf` d then Just h else getFromTable c ds type RndS = State Rnd type Rnd = StdGen randomThingR :: (Random t, RandomGen s, MonadState s m) => (t, t) -> m t randomThingR range = do r <- get let (a, g) = randomR range r put g return a randomPair :: (Random t, RandomGen s, MonadState s m) => (t, t) -> m (t, t) randomPair range = do a <- randomThingR range a' <- randomThingR range return (a, a') capitalize [] = [] capitalize (h:hs) = toUpper h : hs untilDoneR :: (Monad m) => m (Maybe a) -> m a untilDoneR f = do done <- f case done of Nothing -> untilDoneR f Just x -> return x boolToMaybe :: Bool -> Maybe () boolToMaybe True = Just () boolToMaybe False = Nothing untilDone :: (Monad m) => m Bool -> m () untilDone f = untilDoneR (f >>= return . boolToMaybe) while :: (Monad m) => m Bool -> m () -> m () while n m = do r <- n if r then m >> while n m else return () until :: (Monad m) => m Bool -> m () -> m () until n m = while (liftM not n) m radToDeg :: (Floating a) => a -> a radToDeg r = r * 180 / pi degToRad :: (Floating a) => a -> a degToRad d = d * pi / 180 lengthF :: (Foldable f) => f a -> Int lengthF = foldl' (\acc _ -> acc + 1) 0 wrap :: (Num a, Ord a) => a -> a -> a -> a wrap mn mx v = if v < mn then wrap mn mx (v + diff) else if v > mx then wrap mn mx (v - diff) else v where diff = mx - mn wrapDegrees :: (Num a, Ord a) => a -> a wrapDegrees = wrap (-180) 180 clamp :: (Ord a) => a -> a -> a -> a clamp mn mx n = if mn > n then mn else if mx < n then mx else n insertRev :: (Ord a) => a -> [a] -> [a] insertRev x xs = insertBy f x xs where f a b = case compare a b of LT -> GT EQ -> EQ GT -> LT modFst :: (a -> a) -> (a, b) -> (a, b) modFst f (a, b) = (f a, b) modSnd :: (b -> b) -> (a, b) -> (a, b) modSnd f (a, b) = (a, f b) safeIndex :: [a] -> Int -> Maybe a safeIndex [] _ = Nothing safeIndex (x:xs) n | n < 0 = Nothing | n == 0 = Just x | otherwise = safeIndex xs (n - 1) allEnums :: (Enum a, Bounded a) => [a] allEnums = [minBound..maxBound] boxThatIncludes :: (Ord a, Floating a) => (a, a) -- ^ coords of first pos -> (a, a) -- ^ coords of second pos -> a -- ^ size of first box -> a -- ^ size of second box -> a -- ^ width -> a -- ^ height -> ((a, a), (a, a)) -- ^ box that includes both first and second box boxThatIncludes (x1, x2) (y1, y2) inc1 inc2 w h = let ((minx1, maxx1), (miny1, maxy1)) = boxArea (x1, y1) inc1 ((minx2, maxx2), (miny2, maxy2)) = boxArea (x2, y2) inc2 minx = min minx1 minx2 maxx = max maxx1 maxx2 miny = min miny1 miny2 maxy = max maxy1 maxy2 ratio = w / h (midx, midy) = ((maxx + minx) / 2, (maxy + miny) / 2) dx = midx - minx dy = midy - miny dx' = max dx (dy * ratio) dy' = max dy (dx * (1/ratio)) minx' = midx - dx' miny' = midy - dy' maxx' = midx + dx' maxy' = midy + dy' in ((minx', maxx'), (miny', maxy')) {- randomThing :: (Random t, RandomGen s, MonadState s m) => m t randomThing = do r <- get let (a, g) = random r put g return a -}