3

嗯,我真的不知道如何搜索我正在寻找的东西。谷歌提供了大量的结果,但没有一个符合我的标准。

所以我在这里问它:是否有任何已知的代码可以创建一个数字,这是可预测的,看起来是随机的,并且基于“种子”(在我的情况下是 unix 时间戳)并且在指定范围之间?

我希望能够在我正在编写的游戏的脚本中创建天气预报(但我需要可以移植的 C++ 代码,我认为这里的很多人都不熟悉 'PAWN' [aka SMALL] 脚本语言? :) )。天气 ID 从 0 到 ~100 不等,包括一些不推荐使用的 ID(所以我的解决方案是制作一个包含有效天气 ID 的数组,这样我们就不必担心那些 BAD_ID,我们不要让函数太复杂)。

我可能会制定这样的公式,但过去我遇到的问题是天气变化太快(就像每一秒一样,虽然我在某处丢失了代码:/),现在我真的不知道我是怎么做的我打算做这样一个公式。

任何建议也非常感谢!

4

7 回答 7

3

查看VB6 使用的随机数生成器的 C 实现。它非常适合游戏,因为它生成相当可信的随机序列,但使用种子,并且相同的种子总是生成相同的序列。因此,在游戏数据文件中,您可以保存一组种子值,这些值将为您提供已知(但外观随机)的序列,您可以轻松地重现这些序列。

这是一个返回范围内的值的实现:

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 ); };
};
于 2012-02-13T23:18:43.613 回答
2

寻找srandrand寻找初学者。

C++11 还包括许多更高级的算法,但对于基本需求,以上两个就足够了。

要将数字保持在 0 到 n 的范围内,请使用%运算符。

于 2012-02-13T23:12:43.273 回答
2

显然,一个数字不能既是“可预测的”又是“随机的”——这些是直接矛盾的术语。

我假设您的意思是一个既具有确定性又具有半随机性的数字。

幸运的是,这就是伪随机数生成器 (PRNG) 产生的结果:当它们使用一致的种子运行时,它们会为您提供相同的输出。

因此,我建议您使用 设置种子srandom,然后使用random() % MAX_VALUE获取 0 到 之间的数字MAX_VALUE。如果你得到一个“坏值”,那就再去一次。重复 sans 重新播种任意数量的数字。

于 2012-02-13T23:13:24.350 回答
1

如果您需要一个缓慢变化的值,您可以使用噪声函数,例如Perlin Noise

于 2012-02-13T23:14:54.830 回答
1

你真正想要的是一个散列函数。要限制范围,您可以使用一种常用技巧(最脏的是余数运算符)。

具体来说,您希望将整数散列为整数。您可以在此处获取这样的功能。我推荐标题为“Robert Jenkins 的 32 位整数散列函数”的文章——对我来说总是很有效。

你最终会得到类似的东西:

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

如果您想要更有趣的天气行为,您可以在时间值之间进行线性插值。您可以将 Perlin 噪声与此类插值噪声在不同频率和强度下的线性组合一起使用,以产生一些非常好的行为。(我已经用多人角色扮演游戏做到了这一点,而且效果很好。)

于 2012-02-13T23:18:17.620 回答
0

srand和的问题rand在于,只有它们的调用签名(而不是它们生成的值)是由 C 标准规定的。如果您需要可移植确定性的伪随机数,您应该自己实现它。这是一个用 C++ 编写的类,它基于 Numerical Recipes 中的类,并且是完全可移植的。如果您愿意,可以使用种子实例化随机数流。我对这个种子进行硬编码,而不是使用时间,以防我一次又一次地想要相同的伪随机序列。您还可以使用该RandomInteger(a,b)方法获取半开区间 [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;
}
于 2012-02-13T23:27:24.213 回答
0

我认为您可以使用 rand 生成随机数。但是,您可以为 srand 赋予相同的值,例如 99,这样您的数字将是随机的,但每次都是可预测的。

int iSecret = 0;

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

/* generate secret number: */
iSecret = rand();
于 2012-02-14T05:49:54.543 回答