-- Copyright (c) 2011, Colin Hill


-- | A simple implementation of a pure linear congruential psuedo-random number generator.

--

-- Example of use:

--

-- @

--main = do

--    let seed = 1

--    let (r, seed') = randomInt seed

--    putStrLn (\"Random number 1: \" ++ show r)

--    let (r', seed'') = randomInt seed'

--    putStrLn (\"Random number 2: \" ++ show r')

--    putStrLn (\"Random int list: \" ++ show (randomInts 10 seed))

--    putStrLn (\"Shuffled list: \" ++ show (shuffle [1..10] seed))

-- @

module Numeric.Noise.Random (
    randomInt,
    randomInts,
    shuffle
) where

import Numeric.Noise

import Data.Bits

-- | Returns a random 'Int' and the next seed given a seed.

randomInt :: Seed -> (Int, Seed)
randomInt :: Int -> (Int, Int)
randomInt Int
seed = Int -> Int -> Int -> (Int, Int)
randomInt' Int
seed Int
0 Int
16

-- | Helper for 'randomInt'.

randomInt' :: Int -> Seed -> Int -> (Int, Seed)
randomInt' :: Int -> Int -> Int -> (Int, Int)
randomInt' Int
r Int
seed Int
0 = (Int
r, Int
seed)
randomInt' Int
r Int
seed Int
n = Int -> Int -> Int -> (Int, Int)
randomInt' Int
r' Int
seed' (Int
n forall a. Num a => a -> a -> a
- Int
1)
    where seed' :: Int
seed' = Int
3039177861 forall a. Num a => a -> a -> a
* Int
seed forall a. Num a => a -> a -> a
+ Int
1
          r' :: Int
r'    = forall a. Bits a => a -> Int -> a
shiftL Int
r Int
2 forall a. Num a => a -> a -> a
+ forall a. Bits a => a -> Int -> a
shiftR Int
seed' Int
30

-- | Returns a random sequence of 'Int's given a seed and the number of 'Int's to generate.

randomInts :: Seed -> Int -> [Int]
randomInts :: Int -> Int -> [Int]
randomInts Int
_    Int
0 = []
randomInts Int
seed Int
n = Int
r forall a. a -> [a] -> [a]
: Int -> Int -> [Int]
randomInts Int
seed' (Int
n forall a. Num a => a -> a -> a
- Int
1)
    where (Int
r, Int
seed') = Int -> (Int, Int)
randomInt Int
seed

-- | Returns a shuffled list containing the same elements as the given list given a seed.

shuffle :: [a] -> Seed -> [a]
shuffle :: forall a. [a] -> Int -> [a]
shuffle [a]
xs Int
seed = forall a b. (a, b) -> a
fst (forall a. [a] -> [a] -> Int -> ([a], Int)
shuffle' [a]
xs [] Int
seed)

-- | Helper function for 'shuffle'.

shuffle' :: [a] -> [a] -> Seed -> ([a], Seed)
shuffle' :: forall a. [a] -> [a] -> Int -> ([a], Int)
shuffle' [] [a]
acc Int
seed = ([a]
acc, Int
seed)
shuffle' [a]
xs [a]
acc Int
seed = forall a. [a] -> [a] -> Int -> ([a], Int)
shuffle' ([a]
h forall a. [a] -> [a] -> [a]
++ [a]
ys) (a
yforall a. a -> [a] -> [a]
:[a]
acc) Int
seed'
    where (Int
seed', Int
r) = Int -> (Int, Int)
randomInt Int
seed
          ([a]
h, a
y:[a]
ys)  = forall a. Int -> [a] -> ([a], [a])
splitAt (Int
r forall a. Integral a => a -> a -> a
`mod` forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs) [a]
xs