You could try generating the world in a deterministic way. A random number generator requires a seed to start, you could trying having a global seed for that instance of the world and then using the grid location of each tile along with that global seed to set some tile properties.
One method I thought about was creating a bit stream with the seed and grid coordinates of each tile and hashing them using CRC32 to get some deterministic number that I could use to generate properties for that tile. So something like:
| int dataToBeHashed[3] = { GlobalSeed, GridX, GridY };
u32 hash = CRC32( (u8*)dataToBeHashed, sizeof( dataToBeHashed ) );
|
You could then use 'hash' any way you like to generate a specific tile. Two methods I have thought of are using specific bits to control specific properties (i.e. the first 5 bits determine terrain type, etc). The other method is using that hash as a seed local to an instance of a rng for that tile. Both are deterministic and fairly easy to compute.
For how tiles can be visually blended, you could generate the hash of 2 tiles next to each other and combine them somehow (maybe XOR or CRC again) and use the result of that to determine how they should blend. It being deterministic can be very important for reproduction of certain level configurations you are trying to debug/test too.
As a side note, you don't have to CRC32. I only choose it because it is one that I know and have using in the past for various things. There are other hashing algorithms that are faster and more random.