2017-04-18 3 views
-1

敵にプリセット難易度に基づいてランダムなセットを与えると思われるコードセクションに問題があります。私はBjorneのランダム関数の修正版テンプレートを使用しています。私は彼の元のバージョンを使用する場合、私はまだ問題を抱えていた:スイッチステートメントのケース内で乱数を使用する

Random number generator code from Stroustrup:それ常に

template<class T> 
T rand_num(const T & low, const T & high) 
{ 
    static std::default_random_engine re{}; 
    using Dist = std::uniform_int_distribution<T>; 
    static Dist uid{}; 
    return uid(re, Dist::param_type{ low,high }); 
} 

私はOffensiveEntityと言う、に難易度を設定し、1をカプセル化するEnemyAIオブジェクトを作成することにより、セクションをテストし、乱数を1に設定し、この場合は常に健康を選択します。 2番目のifステートメントをif (tempRandom == 1)の条件に設定すると、スティックが選択されます。

void EnemyAI::Equip() 
{ 
    m_offensiveEntity->ClearItems(); 

    std::vector<std::shared_ptr<Item>> tempItems; 

    int tempRandom = 0; 

    switch (m_difficultyLevel) 
    { 
    case 0: 
    case 1: 
    { 
     tempRandom = rand_num<int>(1, 4); 
     if ((tempRandom == 1) || (tempRandom == 2) || (tempRandom == 3) || (tempRandom == 4)) 
      tempItems.push_back(CreateTempItem("Health Potion : HP", 3, 3, 
-10, Result::Effect::nothing)); 
     if (tempRandom == 3) 
      tempItems.push_back(CreateTempItem("Wooden Stick : DMG", 5, 2, 10, Result::Effect::nothing, 3, 13, Result::Effect::nothing)); 
     break; 
    } 
    case 2: ... etc 

この問題の原因は何ですか。出力は次のとおりです。

Health Potion : HP name 
3 durability 
-10 total damage 
3 energy cost 
0 effect 

この中で入力する場合:

int main() 
{ 
    std::shared_ptr<EnemyAI> offensiveEntityInterface = 
     std::make_shared<EnemyAI>(EnemyAI("Dank Memerson", 50, 1)); 

    offensiveEntityInterface->Equip(); 
    for (auto & i : offensiveEntityInterface->GetEquiped()) 
    { 
     std::cout << i->GetName() << " name \n"; 
     std::cout << i->GetHP() << " durability \n"; 
     std::shared_ptr<const Result> tempResult = i->Use(); 
     std::cout << tempResult->m_totalDamage << " total damage \n"; 
     std::cout << tempResult->m_energyCost << " energy cost \n"; 
     std::cout << tempResult->m_effect << " effect \n"; 
    } 
    std::cin.get(); 
    return 0; 
} 

をHERESにペーストビン https://pastebin.com/F4Q74Gc6

答えて

1

でソースコードをあなたのエンジンが非シードであり、したがって、あるデフォルト値を使用していますプログラムを実行するたびに同じです。それぞれの実行でそれが異なることを確認するには、それをシードする必要があります。

現在のシステムクロックを整数として使用し、それをシードとして使用することをお勧めしますが、C++ 11では具体的にはstd::random_deviceを使用することをお勧めします。これは温度センサーを読み取って真に乱数を取得しようとします。 CPUまたは何らかの同様の手段によって実行され、擬似ランダムメソッド(システムクロックまたはその他のメソッドを取得するなど)にフォールバックして実行できない場合

template<class T> 
T rand_num(const T & low, const T & high) 
{ 
    static std::default_random_engine re{std::random_device{}()}; 
    using Dist = std::uniform_int_distribution<T>; 
    static Dist uid{}; 
    return uid(re, Dist::param_type{ low,high }); 
} 

また、コードでは、数値を生成するために使用する各タイプの新しいエンジンを作成します。同様に、rand_num<int32_t>rand_num<int64_t>rand_num<int16_t>を呼び出すと、実行時にスタックに割り当てられ、管理される3つの異なるエンジンです。

template<class T> 
T rand_num(std::default_random_engine & re, const T & low, const T & high) 
{ 
    using Dist = std::uniform_int_distribution<T>; 
    static Dist uid{}; 
    return uid(re, Dist::param_type{ low,high }); 
} 

int main() { 
    std::default_random_engine engine{std::random_device{}()}; 
    /*...*/ 
    int val = rand_num<int>(engine, 1, 4); 
    /*...*/ 
} 

多くのC++の実装は多くの状態からなる、かなり重いものをあるstd::mt19937std::default_random_engineを、マップ:あなたは間違いなくそれを行う必要があると感じていない限り、あなたはこのようなコードを書く方がいいでしょう作成されるたびに割り当てられて生成される必要があります。常にエンジンを再使用していることを確認すると、時間を節約できます。

+0

最初の例のように、デフォルトのランダムエンジンを静的として宣言すると、2番目の例は不要ですか?として、2番目の関数でstd :: random_device std :: default_random_engineエンジンオブジェクトで関数を呼び出すと、静的なstd :: default_random_engineエンジンオブジェクトを関数で初期化し、その関数を呼び出すのと全く同じ結果が生成されます。 – Chopdops

+0

@Chopdops 2つのバージョン間の出力は、「行う」という意味では意味がありません。つまり、指定された範囲内で乱数を生成します。違いは、最初のバージョンは、関数が呼び出される一意の型ごとに 'std :: default_random_engine'の新しいインスタンスを作成するのに対して、2番目のバージョンは手動で作成しない限り、使用する型の数に関係なく、より多くのエンジン)。 – Xirema

+0

@Chopdops特に、 'std :: default_random_engine'が' std :: mt19937'にマップされている場合、 'engine'オブジェクトは非常に高価です。なぜなら、多くのC++実装では標準です。 'rand_num 'のみを起動し、その関数の他のバージョンを呼び出さないことがわかっている場合、その違いは問題ではなく、最初のバージョンをうまく使うことができます。しかし、そうでなければ、毎回タイプが使用されるときにパフォーマンス違反が発生します。 – Xirema

関連する問題