setgame-1.1: src/Set/Utils.hs
module Set.Utils where
import Data.List (tails)
import System.Random (newStdGen, RandomGen, randomR)
-------------------------------------------------------------------------------
-- List utilities--------------------------------------------------------------
-------------------------------------------------------------------------------
-- | 'groups' breaks a list into sublists of the given size. The final resulting
-- group may contain fewer elements than the given size.
-- Property: For all positive n. concat (groups n xs) == xs
groups :: Int -> [a] -> [[a]]
groups _ [] = []
groups n xs = as : groups n bs
where
(as,bs) = splitAt n xs
-- | 'delete1' returns a list with the first occurrence of @x removed. If there
-- is no occurrence 'Nothing' is returned.
delete1 :: Eq a => a -> [a] -> Maybe [a]
delete1 x (y:ys)
| x == y = Just ys
| otherwise = fmap (y:) (delete1 x ys)
delete1 _ [] = Nothing
-- | 'index' returns the element at the given 0-based index and returns
-- 'Nothing' on failure.
index :: Int -> [a] -> Maybe a
index 0 (x:_) = Just x
index n (_:xs) | n > 0 = index (n-1) xs
index _ _ = Nothing
-- | Extract an element from a list by index returning that element
-- and the remaining list.
select :: Int -> [a] -> (a,[a])
select _ [] = error "select: index too large"
select 0 (x:xs) = (x,xs)
select n (x:xs) = (y,x:ys)
where
(y,ys) = select (n-1) xs
-- | Drop last element of list if there is an element to drop.
init' :: [a] -> [a]
init' [] = []
init' xs = init xs
-------------------------------------------------------------------------------
-- Other utilities ------------------------------------------------------------
-------------------------------------------------------------------------------
-- | 'chooseTwo' returns all combinations of two elements.
chooseTwo :: [a] -> [(a,a)]
chooseTwo xs = [ (a,b) | (a:as) <- tails xs
, b <- as
]
-- | 'seconds' converts seconds to microseconds for use in 'threadDelay'.
seconds :: Int -> Int
seconds x = 1000000 * x
-------------------------------------------------------------------------------
-- List shuffling utilities ---------------------------------------------------
-------------------------------------------------------------------------------
-- | 'shuffleIO' calls shuffle using a generator from 'newStdGen'.
shuffleIO :: [a] -> IO [a]
shuffleIO xs = fmap (fst . shuffle xs) newStdGen
-- | 'shuffle' shuffles the elements of a list using the given random generator.
shuffle :: RandomGen g => [a] -> g -> ([a], g)
shuffle xs = shuffle' (length xs) xs
shuffle' :: RandomGen g => Int -> [a] -> g -> ([a], g)
shuffle' _ [] g = ([], g)
shuffle' n xs g = (x:xs'', g'')
where
n' = n - 1
(i, g') = randomR (0,n') g
(x, xs') = select i xs
(xs'', g'') = shuffle' n' xs' g'
-------------------------------------------------------------------------------
-- Text manipulation utilities ------------------------------------------------
-------------------------------------------------------------------------------
-- | 'centerText' centers the given string in a field of @width characters.
centerText :: Int -> String -> String
centerText width xs = replicate ((width - length xs) `div` 2 ) ' ' ++ xs
++ replicate ((width - length xs + 1) `div` 2 ) ' '
-- | 'centerText' right-aligns the given string in a field of @width characters.
leftPadText :: Int -> String -> String
leftPadText width xs = replicate (width - length xs) ' ' ++ xs
-- | 'centerText' left-aligns the given string in a field of @width characters.
rightPadText :: Int -> String -> String
rightPadText width xs = xs ++ replicate (width - length xs) ' '