1

プレイヤーが行うミニミッションを生成するコードがあります。それは簡単で、2 つの異なるポイント (出発地と目的地) を取得するために、次のようなアルゴリズムがあります。

    std::vector<std::string> missions;

    missions.push_back("Location_One");
    missions.push_back("Location_Two");
    missions.push_back("Location_Three");

    //make sure our data has at least 2 elements (so we can actually pick two)
    if(missions.size() > 1)
    {
        //Rand(inclusive min, exlusive max)
        int mission_start_location = Rand(0,missions.size());
        int mission_end_location = Rand(0,missions.size());

        if(mission_start_location == mission_end_location)
        {
            //avoid possile infinite loop of calling "Rand" by Add/Decrement-if-equal algorithm
            //basicly if mission_start_location == 0
            if(!mission_start_location)
                ++mission_end_location;//or = 1, we have at least two elements so index 1 is valid
            else
                --mission_end_location;//so we won't got out of range
        }
        //do mission
    }
    else
    {
        //error
    }

これはうまくいきますが、私が望むものを達成するためのより良い方法、「C++の方法」があるかどうか疑問に思っていました。

私の質問は次のとおりです。

  • これはコンテナから 2 つの異なる値を取得する最良の方法ですか?
  • 非整数インデックス コンテナ (例: std::map<std::string,std::string>) はどうですか?
    • そこから2つの異なるランダムな値を取得するにはどうすればよいですか?

注:私はそのdo { } while(rand1 == rand2)方法をよく知っています。無限ループに陥る可能性があるため、これを避けたいと思います (運が良ければ、運用コードでそうなることがわかっています)。

4

4 に答える 4

3

はい、別の方法でそれを行うことができます。

  if(missions.size() > 1)
  {
    size_t const m_size = missions.size();
    // get random number in the full range
    int const m_start = Rand(0, m_size);
    // get another number in a range reduced by 1
    int m_end = Rand(0, m_size-1);
    // if we are equal or above start we shift by 1 up
    if (m_end >= m_start) ++m_end;
  }
| | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |

最初の選択で 4 が選択された場合、範囲 1 に 2 番目の乱数を設定することで事実上それを削除します。

| | 0 | 1 | 2 | 3 | 4(以前は 5) | 5 (だった 6) | 6(以前は7) |

2 番目の乱数を元のインデックスにマップするには、最初のインデックスが「削除」されたためにインデックスが 1 シフトされたため、最初の乱数より上にある場合は 1 を追加します。


このように、最初の呼び出しで選択されなかった各インデックスは、Rand()への 2 回目の呼び出しで同じ確率で選択されRand()ます。(Rand()実装が乱数のそのような適切な分布を提供する場合。)

于 2013-07-15T02:59:17.020 に答える
0

まず第一に、あなたが今やっていることは C++ を使用する 1 つの方法ですが、必ずしも最良の方法ではありません。最初に、ほとんどのロジックが含まれている以下のコードを調べてみましょう。

    ...
    int mission_start_location = Rand(0,missions.size());
    int mission_end_location = Rand(0,missions.size());
    if(mission_start_location == mission_end_location)
    {
        if(!mission_start_location)
            ++mission_end_location;
        else
            --mission_end_location;
    }
    ...

あなたのRand()関数は最初の引数を包括的下限として使用し、2 番目の引数を可能な生成数の包括的上限として使用すると仮定します。

これを行うと、ベクトルの末尾を超えて読み取るRand(0,missions.size());リスクが生じます。のインデックスは 0 から始まることに注意してください。 が に等しい値を返す場合、ベクトルの末尾の 1 つ後ろの要素を読み取ることになります。やったほうがいいstd::vectorRand(0,missions.size());missions.size()

Rand(0,missions.size() - 1);
//                     ^^^ THIS

代わりは。

もう1つはコードのこの部分にあります

    if(mission_start_location == mission_end_location)
    {
        if(!mission_start_location)
            ++mission_end_location;
        else
            --mission_end_location;
    }

繰り返しますが、ベクターの末尾だけでなく、開始要素の前も読み取るリスクがあります++mission_end_location;--mission_end_location;

あなたがやろうとしていることを行う正しい方法の1つは、

if(missions.size() > 1)
{
    int mission_start_location;
    int mission_end_location;

    while(true) {
        mission_start_location = Rand(0,missions.size());
        mission_end_location = Rand(0,missions.size());

        if(mission_start_location == mission_end_location) continue;
        else break;
    }

    //do mission
}

mission_start_locationこのコードは、 とmission_end_locationが異なるまでループします。

于 2013-07-15T02:40:08.207 に答える