2012-02-13 19 views
3

私は探しているものを探す方法を本当に知りません。 Googleは数多くの検索結果を表示しますが、検索条件に一致するものはありません。 予測可能で、ランダムに見え、 'シード'(私の場合はUNIXのタイムスタンプ)に基づいた数字を作成できる既知のコードがありますか?指定された範囲の間?ランダムであるが予測可能な番号ジェネレータ? [C++]

私はコーディングしているゲームのスクリプトで天気予報を作成できるようにしたいと思います(しかし、移植できるC++コードが必要です。ここでは多くの人が 'PAWN'別名SMALL]スクリプト言語?:))。 天気予報のIDは0から〜100までの範囲で、いくつかの廃止予定IDを含みます(私の解決策は有効な気象IDを持つ配列を作成することですので、BAD_IDについて心配する必要はありません。

私はこのような公式を作ることができましたが、過去の問題は天気が急激に変化していたことです(毎秒のようにコードが失われましたが)。私はそのような公式を作るつもりです。

どのような提案も本当に感謝しています!

+0

[Boost.Random](http://www.boost.org/libs/random/)をご覧ください。 – ildjarn

+1

あなたの天気が急激に変化している場合、解決策はランダムなジェネレータを取得することではなく、別のパターンをあまり頻繁に選択しないことです。 「Sun」と「Snowstorm」のIDが互いに隣り合っていれば、それは役に立ちません。 –

+0

多くのコードを移植する必要のないrandom()関数がありますか? (PHP、PAWN、C++ < - それはブーストですが、PAWNとPHP ...特にPAWN) –

答えて

2

random number generator used by 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); }; 
}; 
+0

うわー、ありがとう、結果は本当に良いです、ちょうど見てください: http://pastebin.com/WvgTSv7g コード: http://pastebin.com/D4KrXpgf –

+0

あなたは歓迎です - うまくいくことを望みますあなたのために。私はいつもこの単純なアルゴリズムが再現性の点で好きでした。非常に小さな入力を使用して、これで巨大なスターシステムを生成することができます。 – xxbbcc

+0

これは**非常に悪い**乱数生成器であることに注意してください(これの統計的性質は多くのウェブサイトでは広告不備として説明されています)。さらに、完全に非標準のインターフェイスを使用しているため、他のライブラリとの使用が難しくなっています。新しいコードでは使用しないでください。 –

2

srandrandを参照してください。

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

数値を0〜nの範囲内に維持するには、%演算子を使用します。

+0

srand()とrand()は、予期せぬ方法で出現する可能性のある多くのシステムでは、特にこの質問が示すように順序付けられた入力を使用する場合、最高で遅くなる傾向があります。 – Kaganar

+0

'rand'は通常ゲームには十分です。あなたが統計家であれば確かにそれほど良いことではありません。それは、ロール、掛け算、追加、またはそれらの線に沿った複雑さに左右される傾向があります。スピードあふれる私は苦情の原因を見たことがありません。どのプラットフォームで問題を見たことがありますか? – StilesCrisis

+0

デフォルトのrandは通常、ゲームには十分だと言っているのは偽の考えです。 Linuxでは、通常trueです。 Windowsでは、ヒットとミスがあります。かなり悪いrand実装があります。私は、1つのプラットフォーム上で奇妙な動作をしたマルチプラットフォームゲームで問題を抱えていましたが、過度に単純化されたランドのために別のプラットフォームでは動作しませんでした。グラフィックスプログラミングでは、さらに誇張されてしまいます。 – Kaganar

2

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

私は、確定的と半角数字の両方を意味すると仮定しています。

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

srandomでシードを設定し、次にrandom() % MAX_VALUEを使用して0とMAX_VALUEの間の数値を取得することをおすすめします。あなたが「悪い価値」を得たら、ちょうど再度行きなさい。あなたが好きなだけ多くの数字のためにリサイズを繰り返す。

1

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

0

本当に必要なのはハッシュ関数です。範囲を制限するために、通常のトリックの1つを使用することができます(最も厄介なのは残りの演算子です)。

特に、整数を整数にハッシュしたいとします。あなたはそのような関数hereを拾うことができます。私は「Robert Jenkinsの32ビット整数ハッシュ関数」というタイトルのものを勧めます。いつもうまくいきました。

次のようなものになってしまいます:あなたがより興味深い天候の挙動をしたい場合は、直線的に時間の値の間を補間することができます

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

。Perlinノイズは、異なる周波数と強度で補間されたノイズを線形に組み合わせて使用​​して、かなり良い動作をさせることができます。 (私はマルチプレイヤーRPGでこれを行いました。それはうまくいきます)

0

srandrandに問題が唯一そのコール署名(およびいない、彼らは発生値)C規格によって決定されることです。移植性のある確定擬似乱数が必要な場合は、自分で実装する必要があります。 C++で書かれたクラスは、数値レシピにあるクラスに基づいており、完全に移植可能です。必要に応じて乱数ストリームをシードでインスタンス化することができます。同じ擬似ランダムシーケンスを何度も繰り返す必要がある場合に備えて、このシードをハードコードします。 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; 
} 
0

乱数を生成するためにrandを使用することができます。しかし、あなたは99のようにsrandに同じ値を与えることができるので、あなたの数値は毎回ランダムであるが予測可能になる。

int iSecret = 0; 

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

/* generate secret number: */ 
iSecret = rand(); 
関連する問題