2
\$\begingroup\$

I am attempting to create a game where there is a universe of two 16-bit addresses ranging from (-32768, -32768) to (32767, 32767), or in hexadecimal, each value can run from $8000 to $FFFF then 0 to $7FFF, although the universe is probably not going to use the whole 4 billion possible addresses.

What I want is for any location, given the two values, to return a value from 0 to around 15 or 20. Where:

  • 0 is empty space.
  • 1 to 9 are planet technology levels, with a level 1 planet being less developed than 2, which means a level 5 planet can build up to a level 5 hull, warp drive or shield, but to upgrade to level 6 requires going to a level 6 or higher planet, or possibly paying a horribly high price.
  • 10 and above are for anomalies, e.g. black holes, suns and other things which have an effect such as random movement or increase in power.

While the most common value will be zero, the universe should have some minimum non-zero locations, e.g. 10% or 20% or some reasonable number of the locations are planets or anomalies.

Note the alignment factors are not random, the value should be calculated so that -60,12 returns the same planetary value any time it's called. I've seen this done in a simple formula amounting to less than 5 lines of code but that was 30 years ago, and I don't have the math to do the calculations myself.

Any help would be appreciated.

\$\endgroup\$
  • \$\begingroup\$ It's not clear what you mean by "alignment". Also, I believe the original Elite did what you describe with innumerable hashed configurations planetary systems. \$\endgroup\$ – Seth Battin Oct 31 '14 at 4:39
  • \$\begingroup\$ I updated the answer with a code example that does exactly what you describe by using md5 to generate a pseudo random sparsely occupied 2d area. \$\endgroup\$ – wolfdawn Oct 31 '14 at 10:38
  • \$\begingroup\$ If you use a hash function, you get reproducible results. \$\endgroup\$ – wolfdawn Nov 2 '14 at 18:42
2
\$\begingroup\$

I would suggest Perlin Noise to do this.

Basically, generate N perlin noise values for each different factor, or, if you prefer 1 perlin noise value that gets hashed to a class (like planet, or emptiness):

int x, y; // coordinates
float scale; // The scale of the universe. Adjust this number to affect smoothness.
float value = Perlin(x * scale, y * scale);
float threshold; // The likelihood of an object, between 0 and 1

// If the value is less than a threshold, we have some kind of object
if (value < threshold)
{
   // This hashes to a number between 0 and 10
   int class = (int)(10.0f * (1.0f - threshold) * value);
   return class;
} else return 0; // Otherwise we have emptiness

This will give you:

  • Consistency. The same result every time you sample an X, Y
  • Local smoothness. You can, for instance, make stars appear in clusters.
  • Apparent randomness.
\$\endgroup\$
0
\$\begingroup\$

tl;dr code example with md5 (you can run it here):

   function getHashTail($pair)
   {
     $res = hexdec(substr(md5($pair), -4)) % 1024;
     return $res < 100? dechex($res % 16) : ' ';
   }

Usage example:

<html>
<head>
<title>Hash space</title>
  <style>
    div {
      text-align:center;
      vertical-align:top;
      display:inline-block;
      border: 1px solid black;
      width:32px; height:32px;
    }
  </style>
</head>
<body>
<?php
   function getHashTail($pair)
   {
     $res = hexdec(substr(md5($pair), -4)) % 1024;
     return $res < 100? dechex($res % 16) : ' ';
   }

   // Sample usage
   $seed = "ABCD";
   for ($i = 10; $i; $i--)
   {
     echo "<br>";
     for($j = 10; $j; $j--)
     {
       echo '<div>' . getHashTail("$i $j $seed") . '</div>';
     }
   }
?>
</body>
</html>

Explanation:

To get the same results for each pair without storing the results in memory you need to use a random seed or simply put a hash function (like md5 for instace). You can then manipulate the input or output from the hash with a seed to get different results.

\$\endgroup\$
0
\$\begingroup\$

What you're describing is procedural generation (of some kind of universe in this example).

This is actually rather trivial to do. Basically you'll just have to calculate everything on basis of your coordinates. This can either be done by simple math or by using the coordinates as the seed for your random number generator.

In your example, you want 20 % of your universe to contain something. So all you have to do is something like this:

$not_empty = ($x + $y << 1) % 100 < 20;

Now that you've determined that the space is not empty, you're able to do the next step, the technology level/anomaly type you've described:

$type = ($x + $y << 1) % $number_of_types;

Of course you can do more complicated things than just adding $x and $y (like calculating some hash). Just keep in mind that the result should be different, even if you change $x or $y only.


If you'd like to use random numbers, you could do something like this:

// Init the seed based on the coordinates
srand($x + $y << 1);

$not_empty = rand(0, 100) < 20;

$type = rand(0, $number_of_types);

Here's a short example on Ideone.com that will show you "scan results" of a given number of systems. They should always return the same results, no matter how often or where you retrieve them (at least as long as the host running the script is the same).

\$\endgroup\$
  • \$\begingroup\$ I appreciate your help, but please note what I said in the third paragraph of my question, "Note the alignment factors are not random ... -60,12 returns the same planetary value..." so using a random value is not going to work (I want the universe's locations to be consistent, so that the game is stable rather than random or chaotic. When you visit a store, in general it retains "ontological inertia" and is still there a week later absent someone tearing it down or an earthquake or other natural disaster changes things.) \$\endgroup\$ – Paul Robinson Nov 2 '14 at 14:50
  • \$\begingroup\$ @PaulRobinson You misunderstood me (or the concept of RNGs). Random number generators are actually pseudo random number generators. They're predictable in the way that the same seed will always result in the same sequence of random numbers being generated. So let's assume you call srand(42); at the start of your program, then the very first call to rand() will always return the same result. \$\endgroup\$ – Mario Nov 2 '14 at 17:08
  • \$\begingroup\$ @PaulRobinson I've added/linked an online example you can try online. \$\endgroup\$ – Mario Nov 2 '14 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.