Search code examples
randomelm

How do I get random numbers in Elm 0.13 without a signal?


I'm making a game where I need to draw random lines on the screen. Now it seems like Random needs a signal to work in 0.13 (and we are forced to work in 0.13). So how do I obtain those random number?

I started from the game skeleton provided at the elm-lang website and got to this:

type UserInput = { space : Bool, keys : [KeyCode] }
type Input = { timeDelta : Float, userInput : UserInput }

userInput : Signal UserInput
userInput = lift2 UserInput Keyboard.space Keyboard.keysDown

framesPerSecond = 30

delta : Signal Float
delta = lift (\t -> t / framesPerSecond) (Time.fps framesPerSecond)

input : Signal Input
input = Signal.sampleOn delta (Signal.lift2 Input delta userInput)

gameState : Signal GameState
gameState = Signal.foldp stepGame defaultGame input

stepGame : Input -> GameState -> GameState
stepGame i g =
  if g.state == Start then *Get random floats*

Now in stepGame, I want to draw random lines. The problem is that I can only get random floats by providing a signal in 0.13. I have the Input signal close by the step function, but when I change the header to lets say stepGame : Signal Input -> GameState -> GameState it doesn't compile. So how do I get a signal in that function to get some random numbers... I can't seem to find the solution, it's driving me crazy.


Solution

  • There are two ways to do this. It really depends on whether the amount of random numbers you need is static or not.

    Static number of random numbers

    Extend your input with random numbers from Random.floatList:

    type Input = { timeDelta : Float, userInput : UserInput, randoms : [Float] }
    
    staticNoOfFloats = 42
    
    input : Signal Input
    input = Signal.sampleOn delta (Signal.lift3 Input delta userInput (Random.floatList (always staticNoOfFloats <~ delta)))
    

    Dynamic number of random numbers

    Use a community library (also outlined in this SO answer) called generator. You can use a random seed by using Random.range in much the same way as outlined above. The library is a pure pseudo-random number generator based on generating a random number and a new Generator that will produce the next random number.

    Why not use Random.floatList in the dynamic case?

    Usually if you need a dynamic number of random numbers that number is dependent on the current state of the program. Because that state is captured inside the foldp, where you're also doing your updating based on those random numbers, this makes it impossible to use a "signal function", i.e. something of type Signal a -> Signal b.