More Randomness in Elm

I found my first real bug in the game recently. When looking at my random forage results I realised that they were always getting the same results every time the action completes, unless I restarted forage.

It’s a pretty stupid mistake really – because the random forage results are generated in advance, of course they’ll be the same until they’re regenerated. The problem is, I can’t just ask for more random numbers in the middle of the update. I need to flag up that I need to get new random numbers, and then run a command after my model update to get them.

What I’ve ended up with is a random cache structure that stores values that can be used later. The cache stores

  • The random generator
  • A list of cached values
  • The expected capacity
  • A count of how many were used since the last update
  • A flag to say if it needs updating

When my forage requires some random number, it asks the cache for a bunch of random values and uses them. The cache then marks itself as needing new numbers.

getRandomFromCache : Int -> RandomCache x -> (List x, RandomCache x)
getRandomFromCache count cache =
  let
    (list, rest) = splitList count cache.values
  in 
    (list, { cache | values = rest, used = cache.used + count, update = True })

After the update cycle we check the caches. If we need updates, we fetch a list of new random values and add to our list of random values. It also checks that the capacity was sufficient and if we used more than 1/3 of our capacity, increases it. This ensures that we should have enough random numbers even if something unusual happens.

addToRandomCache : List x -> RandomCache x -> RandomCache x
addToRandomCache list cache =
  let 
    newCapacity = max (cache.used * 3) cache.capacity
    newValues = List.append cache.values list
    newUpdate = newCapacity < List.length newValues
  in
  { cache 
  | values = newValues
  , used = 0
  , update = newUpdate
  , capacity = newCapacity
  }

Strictly speaking the update flag isn’t necessary, it really is just a cache of capacity < value list length. That might be a premature optimisation. Note It is not the same as update != 0 as if we increase our buffer size we’d still have an used count of 0.

One benefit to this is that it allows me to tidy up my forage action – now it is a forage plus the number of random items, rather than storing exactly what it will get. I’m quite happy about that.

All of this works and I now have properly random forages. However, I feel like I’ve got something wrong here. This feels like a massively overengineered solution to a simple problem. Perhaps something will present itself in the future.


Leave a Reply

Your email address will not be published. Required fields are marked *