0

So I have been working on a game that utilizes procedural terrain & structure generation. Right now, I am tackling structure generation - which I used Poisson-Disc sampling, which I plan to implement on chunks in my world. However, my sampling relies on one single seed. Is there a way to accept 3 or more numbers to output a random number somehow related to those numbers?

On another note, the random number doesn't have to be within the possible ranges of the inputs.

If it is not possible, are there any other paradigms to implement Poisson Disc sampling (or alternatives thereof) on an infinite procedurally-generated world to create structures? I am kinda stuck.

Example:

Random x = new Random(138013, 28282, 37920)
x.nextInt() = 38309
Random y = new Random(138012, 28282, 37920)
y.nextInt() = 28323
Random z = new Random(138013, 28282, 37920)
z.nextInt() = 38309
//new Random(a,b,c).nextInt() does not have to be within ranges [a,b], [a,c], [b,c]
  • It's not at all clear what you're seeking here. If you're planning on using Java's builtin PRNG, the state is 48 bits. Any seeding you do will be collapsed to 48 bits, so there's no benefit to be gained by adding more numbers to the pile, since they wil just have to be collapsed to one of the 2^48 states. If you use a third party generator such as MT19937 or WELL, it uses a larger state and can be seeded accordingly. If you're planning on creating your own PRNG, don't -- however hard you may think it is to create a good one, I guarantee it's much harder than that. – pjs Mar 31 '21 at 13:11
  • Please note that `nextInt()` should never be on the left-hand side of an assignment expression. – pjs Mar 31 '21 at 13:12

2 Answers2

1

You could create the seed by joining these three values:

new Random(138013, 28282, 37920) => new Random("138013" + "28282" + "37920")

It's not valid code, but I hope you get the principle. The string should be then converted to long. If the number is too large for long, maybe you could apply a ceratain modulo. Like 138013 % 10000 and do that for every value. Or you could sum these three values.

  • 1
    Anything involving more than 48 bits is wasted effort for `java.util.Random`. – pjs Mar 31 '21 at 13:18
  • I don't really know any java, @SamMason has the better answer here. – Ondřej Baštař Mar 31 '21 at 13:53
  • 1
    I'm not convinced there is any good answer given the ambiguity about what OP is trying to accomplish. – pjs Mar 31 '21 at 14:17
  • I think he has positions defined by x,y,z and he wants to determine if something should be there using a random value, which is seeded by x,y,z. But it's just a wild guess. – Ondřej Baštař Mar 31 '21 at 14:25
  • Perhaps, but if you need to make wild guesses about the author's intent then it's premature to try and answer the question. Also, the question sounds to me like OP has the (common) misconception that the quality of PRNG's outcomes is a function of the seeding. It's not. The quality is determined by the algorithm being used. Seeding controls reproducibility by determining the entry point to a PRNG's cycle. – pjs Mar 31 '21 at 14:32
1

Using a cryptographic hash of some values is often used to cause the result to be less deterministic. In your case, something like:

    public Random fromCoords(long x, long y, long z) throws Exception {
        var buf = ByteBuffer.allocate(4 * 8);

        buf.putLong(world_seed);
        buf.putLong(x);
        buf.putLong(y);
        buf.putLong(z);

        buf.flip();

        var md = MessageDigest.getInstance("SHA-256");
        md.update(buf);

        var seed = ByteBuffer.wrap(md.digest()).getLong();

        return new Random(seed);
    }

might be enough, but isn't particularly efficient. You could use some bit twiddling inplace of the ByteBuffer to avoid most of the unnecessary heap allocations if this is a problem.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60