Starver, about the cascading seeds, do you think they are taken from the result of a first prng then run through a second? I dont understand how the cascade (or butterfly effect, as I understand it) would occur.
That is my surmising, but I could be wrong.
As a simple example, imagine we had a (totally awful) 'randomising' function that takes a number, adds three and makes it modulo 10 at each stage. We seed it with the number five and start to populate a four-by-four master-grid with the results. First request for a number is
10|
5+3| = 8. The next request for a number is
10|
8+3| = 1. The next is
10|
1+3| = 4, etc, giving large-grid values of:
(The next number that would pop out would have been 6, but it won't ever be required, in our example.)
In the context of DF, I'd actually assume that we wouldn't be left with the bare-numbers, but would use those bare-numbers to generate a 'weathered' (and otherwise manipulated) terrain map, and if it ends up getting rejected
then another base-map would be generated (starting with the '6', as we request more numbers from the function that we had previously thought had gone into retirement), until that does not reject. And as long as we seed with the same seed, we'll get the same map (after the same number of rejections!) every time we start from scratch.
But, assuming we're working with the above grid (easily re-calculated, on demand, rather than having to load in from a save-file the final 'master layout' map composed of daughter data, granddaughter data, or great
n-granddaughter data), then let's say that the player is embarking/adventuring in a location so that the game needs to investigate more thoroughly the finer details of the '8' square in the lower-right of the middle, to populate it with a 'finer', 2x2 grid. The '8' is taken as a grid to produce:
Of course, '1' at this level of grid need not (will not!) mean the same thing as the '1' at the top-level of grid. It's just a number, from which local qualities are obtained. And I also only made it a 2x2 sub-grid because it fit best when replacing the larger number.
It fits within the 'major' grid, as follows:
But note that
every tile (under this simple scheme) that is given the value '8' at the top level of resolution would resolve down to the same lower pattern...
(A similar thing happening to every
other number that can be found more than once on that grid.)
But, of course, with a large enough pool of numbers in a PRNG output (0..2
16?), which also happens to be far better at having results that 'leap around' the number-line, you'd be have more than enough numbers to prevent either two spots on the same top-level map having the same number, or make it
too obvious that any particular spot on one map (through one seed) is essentially the same as any particular spot on another map (via a different seed).
Also, note that the macro-level square to the right of the '8's is always '1', and below the '8's is always a '0', but that's in part because I chose numbers with factors in common for my modulo-arithmetic and grid-sizes (choosing (different!) prime numbers in all directions would have been a good start, but I wanted to leave this arbitrary example 'leaky' with such problems, without being overly so, e.g. with
16|
n+4| chosen as the PRNG method). In this event, if an '8' somehow signified a particular kind of terrain, then such rules such as "when abutting an '8' with a '0', paint that side in a particular way", and repeated for all other combinations (including a rule for "when a '0' abuts an '8'" that compliments the melding on the other side of the boundary), would give the same appearance as well. But if all the '8's are surrounded by different numbers, then this should influenced the end result differently and thus a loam-river-plain (if that's what the top-level '8' means, in this simple example) that in one case has a desert bordering it and in another a marsh might well be given details that are different to each other. And not just at the edge, although that's where the primary procedural melding occurs. If the number assigned to any area is combined (in whatever way you care) with the numbers of adjacent areas, for some seeding purposes, then you might be able to hide the formulaic nature of the tiling even better...
I'm not saying this is how DF does it (and, in various ways, I know it does not!). But it's how
I might do it. In fact, in a couple of toy applications of my own design, I
have done something similar, but the results were mixed. One was particularly good at what it was supposed to do, while another obviously just wasn't right for this particular method. I have no doubt that Toady has spent a
lot of time refining the geography/geology-generating algorithms (as has Notch, the Minecraft guy, who has the same sort of problem and
may have used the same family of solution to it[1]), so whatever method used is undoubtedly
far better than a simple scaling-up of the one I've just demonstrated.
Then you can keep it running until you reach the 2^19937-1 iteration, but by then you would need a new seed to keep churning out numbers. And for the twister to work best you need the 19937 bit long seed to be perfectly random...
I'm wondering how much more understanding might be conveyed if we can swap the phrase "perfectly random" to being "goshdarn ineffable"? Randomness from algorithms is an illusion. I'd even hesitate to try to replace it with the word 'unpredictable' (as, obviously, one could repeat the exercise and know that the numbers one is going to retrieve are the same numbers one already has). But the bigger that the internal state being operated with is (in some ways proportional to how big that Mersene prime is) the more different points upon the roller-coaster that is the PRNG output, you could be at, and the longer it takes to get to the point where you're getting a rehash of old values. To quote Thief^, "...such an insanely long time that it might as well never repeat." Note "
might as well never repeat". It still
does, but I wonder if you know how frequently you're going to need to grab a number in order that you can spot a repeat within the age of the Universe?
[...]will it be running the twister all the time from start just in case the need arises or would it run it only to get enough bits to have an hexadecimal number in 0-64 range?
I don't think you understand the principle at all. The number 'jumps around' enough between each
single invocation ('randomly', you might say, although that's wrong) that you only need to ask if for a 'random' number
when you need it. You don't 'set it running' and tap it. You'd get no more a 'random' set of results (although a different one!) to consult a background process that's 'ticking' out random numbers (whether required or not). And at each and every time you asked for a number, you'd be best to take the output number and
make it become a number in the 0..64 (or do you mean 0..63?) range. Typically, the PRNG functions are capable of returning a number that is a fraction that is 0<=n<1 (or whatever inequality it is, check your language/library spec, like I really ought to check mine!). Something like "int(n*64)" applied to that function would give you a (very roughly!) equal chance of getting each of the numbers 0..63. Although there's usually also a method to call "rand(x)" to get either 0..x-1 or 1..x or 0..x or something (again, check your documentation) from the function, which does the messy work for you in a bit of code that easier for a human like ourselves to both write and read.
You almost certainly
wouldn't be asking a randomising function for a random number that's (say) 0..255, and then if n>63 rejecting it and asking again. If it
is giving you something like 0..255, use that number integer divided by four. If you get one 0..65535 then similarly divide it by 1024 to bring it down to 0..63. Whatever is needed.
And if you're writing your own MT function (don't know why you would, to be honest, but don't let me stop you) you should be able to build in the "rand(x)" functionality, and/or the 0..1 fraction one, based upon the potential magnitude (bit-depth) that you know the 'presentable' random number from the MT-functionality is going to be.
[1] From what I understand, he has a near-infinitely extending Perlin-noise-like 'macro' geography-generator, in place of Toady's simulated rainfall/etc situation, but
if I'm correct that Toady then creates the specific local geography with a cascaded seed (and influences from adjacent tiles) forming the minutiae of the local geography, then I might also be right in imagining that Notch has a similar generational system for his own volumetric macro-regions. And if I'm wrong with one, I may still be right with the other.