Open EthanSteinberg opened 7 months ago
well god damn
Got damn
Actually, you can optimize this even further, reducing the runtime by half at the cost of doubling the size of the HashMap.
Instead of a HashMap that only contains entries for (x 1063476645096 >> 16) mod 2 ^ 32 => x, we can also add entries for (x 1063476645096 >> 16) + 1 mod 2 ^ 32 => x.
We are lucky that in this case there are still no collisions even with those duplicative entries.
Now there is only one possible x value after doing a lookup in the HashMap, so there is only one possible z value to check.
bunch of nerds fr
A key part of your algorithm is decoding the seed to find an x and z coordinate for a woodland region.
In other words, we have the equation:
and we need to find x and z (both between -23440 and 23440).
You do this with a very large lookup table of size 2^32. A lookup table of that size is strictly not necessary and we can actually just use a HashMap with 46,881 entries, a reduction of about 5 orders of magnitude. This should also improve your speed quite tremendously, as you can do everything within cache (either CPU or GPU cache).
First, let us make x and z strictly positive by adding an offset of 23440 to each.
If you simplify this out you get
Important point: x and z are now always less than 16 bits
We can now do a bit more simplification, using the fact that 132897987541 is invertible mod 2^48
First, we subtract from both sides
Then, we multiply each side by 211541297333629
Finally, we simplify
For the sake of simplicity, let seed = (seed - 7471016896829 ) 211541297333629 mod 2 ^ 48
Now we can make a key insight. z is at most 16 bits, so the upper bits of x * 1063476645096 should be mostly preserved.
Let >> be the bitwise shift operator.
The key is to think about addition in terms of binary representation. There are two possibilities: the lower 16 bits of x * 1063476645096 and z sum to a number greater than 2^16 (aka there is a carry bit) or they sum to a number less than 2^16 (aka there is no carry bit).
All we have to do is create a lookup table that maps (x 1063476645096 >> 16) mod 2 ^ 32 to x for all possible x values (which is from 0 to 46880). This table will only have 46881 entries. It turns out that (x 1063476645096 >> 16) mod 2 ^ 32 => x is a unique mapping, so you can deterministically find the x given (x * 1063476645096 >> 16) mod 2 ^ 32. Note that the overall approach will still work even if it's not a unique mapping, it will just be more inefficient as you will have more values of x to check.
Now you can find x by simply looking at the table entries for (seed >> 16) mod 2^ 32 and (seed >> 16) - 1 mod 2^32.
That will get you two possible x values. You can then find two possible z values using the below formula:
Check both possible z's and you have your solution.