Getting a Random Seed From A Path
Home -->
Programming Projects -->
Fractal Block Engine -->
Procedural World Generation -->
Getting a Random Seed From A Path
Getting a Seed From Several Integers
Suppose we have two integers x and y and we want to generate
an (integer) seed for pseudo random generation from these numbers.
A natural way is to use a linear combination using prime numbers.
That is, let p1 and p2 be two prime numbers.
We can set the seed to be
x * p1 + y * p2.
In a non-fractal block game,
we could use the x,y,z coordinates of a chunk to set the
seed for procedural world generation of that chunk.
In Fractal Block World,
life is more complex.
We need a way to get a seed from the block path
of the chunk being generated.
That is what this page is about.
Table of Primes
//The first 81 primes after one million.
int prime_table[] = {
1000003, 1000033, 1000037, 1000039, 1000081, 1000099, 1000117, 1000121, 1000133,
1000151, 1000159, 1000171, 1000183, 1000187, 1000193, 1000199, 1000211, 1000213,
1000231, 1000249, 1000253, 1000273, 1000289, 1000291, 1000303, 1000313, 1000333,
1000357, 1000367, 1000381, 1000393, 1000397, 1000403, 1000409, 1000423, 1000427,
1000429, 1000453, 1000457, 1000507, 1000537, 1000541, 1000547, 1000577, 1000579,
1000589, 1000609, 1000619, 1000621, 1000639, 1000651, 1000667, 1000669, 1000679,
1000691, 1000697, 1000721, 1000723, 1000763, 1000777, 1000793, 1000829, 1000847,
1000849, 1000859, 1000861, 1000889, 1000907, 1000919, 1000921, 1000931, 1000969,
1000973, 1000981, 1000999, 1001003, 1001017, 1001023, 1001027, 1001041, 1001069};
int GetPrime(int n) {
int total = 79; //Away from 81.
while( n > total ) n -= total;
if( n < 0 ) n = 0;
return prime_table[n];
}
Seed from a Block Path
Here is code to get an (integer) seed from
a BlockPath:
int GenerateSeedFromPathXYZ(
const BlockPath & block_path,
{
int total = 0;
int n = 0;
total += GetPrime(n++) * bp.path.size();
for(int i = 0; i < bp.path.size(); ++i) {
const LocalBlockPos & lbp = block_path.path[i];
total += GetPrime(n++) * (int)lbp.x;
total += GetPrime(n++) * (int)lbp.y;
total += GetPrime(n++) * (int)lbp.z;
}
return total;
}
Fractal Block World also has an integer seed
associated to each world
(the player can choose a seed when they
start a new game).
The code in the function above can be modified
to take this
world_seed
into account.
Seed from an adjacent Block Path
Suppose we are generating a chunk C.
Sometimes we need to get the pseudo random seed
for a nearby chunk.
This is done by computing the nearby path
and then computing the seed of that path.
See here for how to compute
an adjacent block path.
int GenerateSeedFromNearbyPathXYZ(
const BlockPath & block_path,
int dx, int dy, int dz
{
BlockPath adj_path;
bool valid = ComputeNearbyPath(
block_path, dx, dy, dz adj_path);
if( !valid ) return 0; //Edge of world!
return GenerateSeedFromPathXYZ(adj_path);
}
XY Seed from a Block Path
Sometimes we want to generate a seed for a chunk
that only depends on the x,y position of the chunk
and ignores its z position.
This is accomplished by the following function:
int GenerateSeedFromPathXY(
const BlockPath & block_path,
{
int total = 0;
int n = 0;
total += GetPrime(n++) * bp.path.size();
for(int i = 0; i < bp.path.size(); ++i) {
const LocalBlockPos & lbp = block_path.path[i];
total += GetPrime(n++) * (int)lbp.x;
total += GetPrime(n++) * (int)lbp.y;
//We ignore "lbp.z".
}
return total;
}
There is a similar function for getting an XY seed
for a chunk adjacent to a given chunk.
Too Slow
Everything in this section is all well and good but
there is one problem: it is slow.
If a chunk is a thousand levels deep,
then it can be a little slow to compute
the seed from the chunk's path.
One solution is to generate a seed using only
the last few elements of the chunk's path
(to get what we call the "tail path").
This is discussed
here.