3

探しているものを検索する方法がよくわかりません。Google は大量の結果を提供しますが、私の基準に一致するものはありません。

だから私はここでそれを尋ねています:予測可能で、ランダムに見え、「シード」(私の場合はUNIXタイムスタンプ)に基づいており、指定された範囲の間にある数値を作成できる既知のコードはありますか? ?

コーディングしているゲームのスクリプトで天気予報を作成できるようにしたい (ただし、移植できる C++ コードが必要です。「PAWN」[別名 SMALL] スクリプトに慣れている人はあまりいないと思います)言語? :) )。天気 ID は、非推奨の ID を含めて 0 から ~100 までさまざまです (したがって、私の解決策は、有効な天気 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

手始めに調べsrandてください。rand

C++11 にはさらに多くの高度なアルゴリズムも含まれていますが、基本的なニーズには上記の 2 つで十分です。

数値を 0 から n の範囲内に保つには、%演算子を使用します。

于 2012-02-13T23:12:43.273 に答える
2

明らかに、数値は「予測可能」と「ランダム」の両方になることはできません。これらは直接矛盾する用語です。

あなたが意味するのは、決定論的かつ半ランダムな数値であると想定しています。

幸いなことに、これが疑似乱数ジェネレーター (PRNG) が生成するものです。一貫したシードで実行すると、同じ出力が得られます。

したがって、シードを で設定しsrandom、 を使用random() % MAX_VALUEして 0 から までの数値を取得することをお勧めしますMAX_VALUE。「悪い値」を取得した場合は、もう一度行ってください。好きな数だけ再シードを行わずに繰り返します。

于 2012-02-13T23:13:24.350 に答える
1

ゆっくり変化する値が必要な場合は、Perlin Noiseなどのノイズ関数を使用できます。

于 2012-02-13T23:14:54.830 に答える
1

本当に欲しいのはハッシュ関数です。範囲を制限するには、通常のトリックの 1 つを使用できます (最も汚いのは剰余演算子です)。

具体的には、整数を整数にハッシュする必要があります。そのような機能をここでピックアップできます。「Robert Jenkins の 32 ビット整数ハッシュ関数」というタイトルのものをお勧めします。これは常にうまくいきました。

次のような結果になります。

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

より興味深い気象現象が必要な場合は、時間値間を線形補間できます。さまざまな周波数と強度で補間されたノイズの線形結合でパーリン ノイズを使用して、非常に優れた動作を作成できます。(私はマルチプレイヤー RPG でこれを行いましたが、うまく機能します。)

于 2012-02-13T23:18:17.620 に答える
0

との問題はsrandrandそれらの呼び出しシグネチャのみ(およびそれらが生成する値ではない)が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

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();
于 2012-02-14T05:49:54.543 に答える