4

Well I don't really know how to search for the thing I'm looking for. Google gives tons of results, but none which match my criteria.

So I'm asking it here: Is there any known piece of code that can create a number, that is predictable, looks random, and is based on a 'seed' (in my case it's the unix timestamp) and between a specified range?

I want to be able to create weather forecast in a script for a game I'm coding (but I need the C++ code which I can port, I don't think many people here are familiar with 'PAWN' [a.k.a. SMALL] scripting language? :) ). The weather id's vary from 0 to ~100, including some deprecated ID's (so my solution would be to make a array holding valid weather ID's so we don't need to worry about those BAD_ID's, let's not make the function too complicated).

I could possibly make such formula but the problem in the past I had was that the weather was changing too fast (like every second, though I lost the code somewhere :/ ) and for now I'm really out of ideas on how I'm going to make such a formula.

Any suggestions are really appreciated too!

  • Take a look at [Boost.Random](http://www.boost.org/libs/random/). – ildjarn Feb 13 '12 at 23:12
  • 1
    If your weather is changing too fast, the solution isn't to get a 'less' random generator - it's to choose a different pattern less often. It doesn't help if the ids for 'Sun' and 'Snowstorm' are right next to each other, either. – Clockwork-Muse Feb 13 '12 at 23:13
  • Is there any other random() function which wouldn't require me to port so much code? (PHP, PAWN, C++ <- yeah that's boost, but PAWN and PHP... Especially PAWN) –  Feb 13 '12 at 23:14
  • It's hard to make out what you mean. As other's have said 'random' and 'predictable' are mutually exclusive. Of course, PRNGs are perfectly predictable, and that's probably what you've been using. If X-Zero's suggestion of picking a random number less frequently isn't exactly what you need, then the topic you might be trying to ask about is 'noise'. With noise functions like perlin noise, you can construct a function that varies within a range of previous values and can simulate a lot of natural looking effects. – bames53 Feb 13 '12 at 23:25

7 Answers7

3

Look at the C implementation of the random number generator used by VB6. It's perfect for games because it generates fairly believable random seqeuences but uses a seed and the same seed always generates the same sequence. So in game data files you can save a set of seed values that will give you known (but random-looking) sequences that you can easily reproduce.

Here's an implementation that returns values in a range:

typedef int Int32;
typedef unsigned int UInt32;

class CRnd
{
    private:
        static const UInt32 INITIAL_VALUE = 0x50000;
        static const UInt32 INCREMENT = 0xC39EC3;
        static const UInt32 MULTIPLIER = 0x43FD43FD;

    private:
        UInt32 m_nRnd;

    public:
        CRnd () { m_nRnd = INITIAL_VALUE; };
        CRnd ( IN UInt32 nSeed ) { m_nRnd = nSeed; };
        virtual ~CRnd () {};

        Int32 Get ( IN Int32 nFrom, IN Int32 nTo )
        {
            if ( nTo < nFrom ) // nFrom should be less than nTo
            {
                Int32 nTmp = nTo;

                nTo = nFrom;
                nFrom = nTmp;
            }
            else if ( nTo == nFrom )
            {
                return ( nTo );
            }

            m_nRnd = ( m_nRnd * MULTIPLIER + INCREMENT ) & 0xFFFFFF;

            float fTmp = (float) m_nRnd / (float) 16777216.0;

            return ( (Int32) ( ( fTmp * ( nTo - nFrom + 1 ) ) + nFrom ) );
        };

        void SetSeed ( IN UInt32 nSeed ) { m_nRnd = nSeed; };
        UInt32 GetSeed () { return ( m_nRnd ); };
};
xxbbcc
  • 16,930
  • 5
  • 50
  • 83
  • Wow thanks, the results are really good, just take a look: http://pastebin.com/WvgTSv7g Code: http://pastebin.com/D4KrXpgf –  Feb 13 '12 at 23:51
  • You're welcome - hope it'll work well for you. I always liked this simple algorithm for its reproducability. One can generate huge star systems with this using very little input. – xxbbcc Feb 14 '12 at 02:50
  • It should be noted that this is a **very bad** random number generator (the statistical properties of this are explained ad nauseam on many websites). It furthermore uses a completely non-standard interface, which makes it hard to use with other libraries. It should not be used in new code. – Konrad Rudolph May 13 '15 at 12:14
  • @KonradRudolph Would you mind providing links to those sites you mention? – xxbbcc May 13 '15 at 16:33
  • The general problem of LCGs is explained [on Wikipedia](http://en.wikipedia.org/wiki/Linear_congruential_generator) or, if you prefer, [in numerous papers](https://www.random.org/analysis/Analysis2005.pdf). Additional problems with the above code are explained for instance by [Julienne Walker](http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx). – Konrad Rudolph May 14 '15 at 16:25
  • @KonradRudolph Thank you, I was aware of some of these. I don't see any problem with using this quick RNG for _games_. It's obviously not meant to be a high-quality RNG and it shouldn't be used in secure applications. – xxbbcc May 14 '15 at 18:16
2

Look into srand and rand for starters.

C++11 includes many more advanced algorithms as well, but for basic needs the above two are sufficient.

To keep the numbers within a range of 0 to n, use the % operator.

StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
  • Unfortunately, srand() and rand() tend to be slow at best or of poor randomness quality on many systems which can come out in unexpected ways, especially if you use ordered inputs as this question implies. – Kaganar Feb 13 '12 at 23:19
  • `rand` is usually good enough for a game. Certainly it's not very good if you are a statistician--it tends to be a roll, multiply and add, or something along those lines complexity-wise. Speed-wise I've never seen any cause for complaint; on what platforms have you seen an issue? – StilesCrisis Feb 13 '12 at 23:48
  • Saying that default rand is usually good enough for a game is a spurious notion. On Linux, usually true. On Windows, hit and miss -- they've got some pretty bad rand implementations. I've had problems with a multi-platform game that had strange behavior on one platform but not another because of overly-simplistic rand. And in graphics programming, it becomes even more exaggerated. – Kaganar Feb 14 '12 at 14:23
2

Obviously a number cannot be both "predictable" and "random" - those are directly contradictory terms.

I'm assuming what you mean is a number that is both deterministic and semirandom.

Luckily for you, this is what pseudorandom number generators (PRNGs) produce: when they are run with a consistent seed, they give you the same output.

So I would recommend setting your seed with srandom, then using random() % MAX_VALUE to get a number between 0 and MAX_VALUE. If you get a "bad value", just go again. Repeat sans reseeding for as many numbers as you like.

Borealid
  • 95,191
  • 9
  • 106
  • 122
1

If you need a slow changing value you can use a noise function, such as Perlin Noise.

rasmus
  • 3,136
  • 17
  • 22
1

What you really want is a hash function. To limit the range you can use one of the usual tricks (the dirtiest being the remainder operator).

Specifically, you want to hash integers into integers. You can pick up such a function here. I recommend the one titled "Robert Jenkins' 32 bit integer hash function" -- always worked well for me.

You'll end up with something like:

int time_index = 3;
int weather_state = integer_hash_function(time_index) % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE

If you want more interesting weather behavior, you can linearly interpolate between time values. You can use Perlin noise with linear combinations of such interpolated noise at differing frequencies and intensities to make some pretty nice behavior. (I've done this with multiplayer RPGs and it works well.)

Kaganar
  • 6,540
  • 2
  • 26
  • 59
0

The problem with srand and rand is that only their call signatures (and not the values they generate) are dictated by the C standard. If you need portable and deterministic pseudo-random numbers, you should implement it yourself. Here is a class, written in C++, which is based on one found in Numerical Recipes, and is completely portable. You may instantiate the random number stream with a seed if you'd like to. I hard-code this seed instead of using the time in case I want the same pseudo-random sequence again and again. You can also use the RandomInteger(a,b) method to get integers on the half-open interval [a,b).

class RandomNumberStream
{
private:
  unsigned long long u,v,w;

public:
  RandomNumberStream(int n=1);
  double RandomDouble();
  double RandomDouble(double a, double b);
  unsigned long long RandomInteger();
  unsigned long long RandomInteger(int a, int b);
private:
  unsigned long long int64();
} ;



RandomNumberStream::RandomNumberStream(int n)
{
  v = 4101842887655102017LL;
  w = 1;

  u = n^v; int64();
  v =   u; int64();
  w =   v; int64();
}
double RandomNumberStream::RandomDouble()
{
  return int64() * 5.42101086242752217E-20f;
}
double RandomNumberStream::RandomDouble(double a, double b)
{
  return int64() * 5.42101086242752217E-20f * (b-a) + a;
}
unsigned long long RandomNumberStream::RandomInteger()
{
  return int64();
}
unsigned long long RandomNumberStream::RandomInteger(int a, int b)
{
  return a + int64() % (b-a);
}
unsigned long long RandomNumberStream::int64()
{
  u  = u * 2862933555777941757LL + 7046029254386353087LL;
  v ^= v>>17; v ^= v<<31; v ^= v>>8;
  w  = 4294957665U*(w & 0xffffffff) + (w>>32);
  unsigned long long x = u^(u<<21); x ^= x>>35; x ^= x<<4;
  return (x+v)^w;
}
Jonathan Zrake
  • 603
  • 6
  • 9
0

I think you can use rand for generating random numbers. However, you can give the same value to srand like say 99 so that your numbers will be random but predictable every time.

int iSecret = 0;

/* initialize random seed: */
srand ( 99 );

/* generate secret number: */
iSecret = rand();
Ajit Vaze
  • 2,686
  • 2
  • 20
  • 24