elm / random

Generate random values in Elm
https://package.elm-lang.org/packages/elm/random/latest/
BSD 3-Clause "New" or "Revised" License
46 stars 23 forks source link

How can I encode a seed as JSON? #17

Open ChrisPenner opened 4 years ago

ChrisPenner commented 4 years ago

Hey there! Hope you're doing well! I'm building a browser game where many clients are synced up and I need to share seeds amongst clients;

I can get a Random.Seed into elm no problem by using Random.initialSeed; but once I have a seed I can't serialize it back into JSON; Is there any way to encode a Seed? I simply need either a Random.Seed -> Int or a Random.Seed -> Json.Encode.Value

Does this exist; or would it be possible to add? I'm a bit stuck on this one 😬

Thanks for your help!

rlefevre commented 4 years ago

If you used Random.initialSeed, you used an Int to call this function. So why not encode this Int instead of the resulting seed?

ChrisPenner commented 4 years ago

Hi @rlefevre 😄 The seed changes along as I run my program using Random.step; I need to serialize the Seed after some amount of steps, and therefore the Int and the Seed will no longer match.

rlefevre commented 4 years ago

@ChrisPenner Maybe you could generate an Int from the current seed, and reuse that as a new initial seed on all clients?

Another way would be to keep the number of steps run to re-run them all at once, but this may be difficult if you use several complex Random generators.

ChrisPenner commented 4 years ago

Generating an int from the current seed and using that would still mean the clients are out of sync. It may seem like a weird thing to want, but I'm actually experimenting with different methods of syncing distributed clients using CRDTs and it's important I can sync up their "randomness".

Another way would be to keep the number of steps run to re-run them all at once, but this may be difficult if you use several complex Random generators.

This sounds absurdly complex (and nonperformant) to keep track of across distributed clients 😬

You haven't mentioned why the hesitation to provide a Seed -> Int or Seed -> Value function; is there a particular reason you're so hesitant? I'd love to hear your opinion on it 😄

rlefevre commented 4 years ago

Generating an int from the current seed and using that would still mean the clients are out of sync.

Why? If the one generating it also uses it as a new initial seed, they would all be synchonized, wouldn't they?

You haven't mentioned why the hesitation to provide a Seed -> Int or Seed -> Value function; is there a particular reason you're so hesitant? I'd love to hear your opinion on it.

Because I'm not convinced by the need yet, so I prefer to help finding a solution that could work now. If none works, this also helps illustrating why it would be useful.

cynic commented 4 years ago

Apologies for jumping in, but I could definitely use the same functionality that is being requested. My use-case is a SPA that initially takes its random seed from the time, and then proceeds deterministically using a PRNG seeded with that. It'd be useful to have a Seed -> (Int, Int) and an (Int, Int) -> Seed so that I could save the (trivial) model in a URL fragment or something, making it easy to pick up exactly where a user left off.

As a workaround, it's pretty easy to just clone the repo, create these trivial functions ("backupSeed" and "restoreSeed"), and move on with life, so I don't particularly mind whether it's in the "official" repository or not. But it seemed useful to me to point out that there are other use-cases, and perhaps (more contentiously) that adding a couple of functions isn't such a terrible idea, and really won't break anything at all.

lucdoebereiner commented 3 years ago

I concur with the others, Seed -> Int is necessary. We are developing an SPA that displays texts and images from a large set of articles and besides filtering and sorting the data in various ways, random sorting can be quite interesting. Now, we want the seed in the URL so a particular random sorting can be referenced. For the moment, we are doing what @cynic does, i.e. fork the package, but I don't find it ideal. The function really seems to be missing.

tankorsmash commented 2 years ago

I've got a usecase for Seed -> Int as well; I'm making a web-game and I need to be able to let the player save and load the game, and in order to have players have a consistent experience. It's important that the Seed is able to be restored, otherwise they could just save and re-load each time they don't like the random outcome.

The seed would have been stepped through thousands of times, depending on how long the player has been playing, so it's not feasible to track the steps and re-run them on load.

I think I'll have to hack around this by taking each new seed from step, generating a new number from it, then saving that number, along with the Seed, and serialize that number.

Being able to serialize and load the seed would be great for my case.

7hoenix commented 2 years ago

I have the same issue. . . I want to store a game seed and then be able to get declarative random without needing to track the entire game state with each step taken (the only workaround I can think of with the current implementation).

As a workaround, it's pretty easy to just clone the repo, create these trivial functions ("backupSeed" and "restoreSeed")

^^ this doesn't work with this Elm compiler since elm/random is an effect module. So if you try to copy it you will get the following:

It is not possible to declare an `effect module` outside the @elm organization

So the workaround is actually to fork the elm compiler and flip the flag that disallows effect modules back to false. And then to copy it as above.

May we just have the fromIntPair and toIntPair functions please? 🤞

mitchellwrosen commented 2 years ago

Hey! Just putting myself down as someone who's interested in this issue.

Any more word from a maintainer on whether or not this function ought to exist? Thanks :+1: