6

別のプロジェクトに取り組んでおりmt19937、ランダムに数字を生成するために を使用する必要があります。グリッドのセクションに基づいて x 座標と y 座標をランダムに選択することになっています。たとえば、私の関数は、、、を関数minXmaxX渡しminYますmaxY。私のx座標は正常に動作します。テストの実行時にランダムにエラーが発生し続けました。問題なく 10 回実行された後、エラーが発生することがあります。mt ジェネレーターが実際に生成しているものを表示するために、いくつかの自己デバッグ行を挿入しました。私が言ったように、x は正常に動作し、y は時々動作します。-3437892 または 9743903 がランダムに表示されます。

これが私のコードです:

void DungeonLevel::generateRoom(int minX,int maxX,int minY, int maxY){
    mt19937 mt;
    mt.seed( time(NULL) );


    // Calculate random width and height; these both range
    // from 4-13
    int iRandomWidth = 4 + (mt() % 10);
    int iRandomHeight = 4 + (mt() % 10);

    // Calculate the start points in both X and Y directions

    int iStartX;
    iStartX = mt() % (maxX - iRandomWidth);
    cout << "xStart: " << iStartX<<endl; //cout flag
    while ((iStartX > maxX) && (iStartX >= 0)){
            cout << "xStart: " << iStartX<<endl;//cout flag
            iStartX = mt() % (maxX - iRandomWidth);
    }
    int iStartY = 0;
    iStartY = mt() % (maxY - iRandomHeight);
    cout<<"yStart: " <<iStartY<<endl; //cout flag
    while ((iStartY > maxY)){
            cout<<"yStart: " <<iStartY<<endl;//cout flag
            iStartY = (mt() % (maxY - iRandomHeight));
    }

    // Iterate through both x and y coordinates, and
    // set the tiles to room tiles
    // SINGLE ROOM
    for( int x = iStartX; x <= iStartX + iRandomWidth; x++ ){
            for( int y = iStartY; y <= iStartY + iRandomHeight; y++ ){
                    if (y == iStartY){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (iStartX == x){
                            dungeonGrid[y][x] = '|';
                    }
                    else if (y == (iStartY+iRandomHeight)){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (x == (iStartX+iRandomWidth)){
                            dungeonGrid[y][x] = '|';
                    }
                    else {
                            dungeonGrid[y][x] = '.';
                    }

            }
    }

}
4

3 に答える 3

16

mt19937にはランダムな分布を使用する必要があると思います。だからそれを一緒に使う

mt19937 mt;
mt.seed( time(nullptr) );
std::uniform_int_distribution<int> dist(4, 13);

int iRandomWidth = dist(mt);
int iRandomHeight = dist(mt);

このようにして、4から13の間の乱数を取得することが保証されます。

更新 私の答えは元の問題を解決し、コードの可読性が向上したと思いますが、実際には元のコードの問題に対処していません。これについては、jogojapanの回答も参照してください。

于 2013-02-26T03:10:42.060 に答える
5

この問題の最終的な原因は、コード内で必要な予防策を講じずに (そしてその必要もなく) 符号付き整数と符号なし整数を混在させていることです。

具体的には、minYが 13 未満の場合があり、それが時々発生しiRandomHeightてマイナスになります。次に得られるものは、以下に示す効果に似ています。

#include <limits>
#include <iostream>

using namespace std;

int main()
{
  /* Unsigned integer larger than would fit into a signed one.
     This is the kind of thing mt199737 returns sometimes. */
  unsigned int i = ((unsigned int)std::numeric_limits<int>::max()) + 1000;
  cout << (i % 3) << endl;
  cout << (i % -3) << endl;
  cout << (signed)(i % -3) << endl;
  return 0;
}

これは最初に、符号付き整数よりわずかに大きい符号なし整数を生成します。unsigned を返し、上記のコードのmt19937ような値を返すことがあります。i

上記のコードの出力 ( liveworkspaceを参照) は次のとおりです。

2
2147484647
-2147482649

2 行目は、対応する符号付き整数よりも大きい符号なし整数に適用された負の数 (iRandomHeightいつかそうなるような) を使用したモジュロの結果を示しています。3 行目は、それを符号付き整数に戻すとどうなるかを示しています (これは、符号付き整数変数の 1 つに割り当てるときに暗黙的に行います)。

人生を楽にするためにHaatschiiを使うべきだという意見には賛成ですが、その場合std::uniform_int_distributionでもsignedとunsignedを適切に使うことも重要です。

于 2013-02-26T03:34:38.353 に答える
0

@haatschii の助けを借りて、私が犯したアマチュアの間違いを理解しました。

今ではとても理にかなっています。iStartY と iStartX には、ゼロ以下の数値を設定するための制限はありませんでした。値が 0 より大きいことを確認するために別のループを追加しました。また、iStartX と iStartY の値を maxX+1 と maxY+1 として開始し、自動的にループに入って 0 より大きい解を生成するようにしました。

ソリューションコードは次のとおりです。

void DungeonLevel::generateRoom(int minX,int maxX,int minY, int maxY){
    mt19937 mt;
    mt.seed( time(NULL) );

    // Calculate random width and height; these both range
    // from 4-13
    int iRandomWidth = 4 + (mt() % 10);
    int iRandomHeight = 4 + (mt() % 10);

    int iStartX = maxX+1; //automatically has to enter the second while loop        
    while ((iStartX > maxX) && (iStartX >= 0)){
            while ((maxX - iRandomWidth) <= 0){
                    iRandomHeight = 4 + (mt() % 10); //makes value > 0
            }
            iStartX = mt() % (maxX - iRandomWidth);
    }

    int iStartY = maxY+1; //automatically has to enter the second loop
    while ((iStartY > maxY)){
            while ((maxY - iRandomHeight) <= 0){
                    iRandomHeight = 4 + (mt() % 10); //sets to valid value
            }
            iStartY = mt() % (maxY - iRandomHeight);
    }
    // Iterate through both x and y coordinates, and
    // set the tiles to room tiles
    // SINGLE ROOM
    for( int x = iStartX; x <= iStartX + iRandomWidth; x++ ){
            for( int y = iStartY; y <= iStartY + iRandomHeight; y++ ){
                    if (y == iStartY){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (iStartX == x){
                            dungeonGrid[y][x] = '|';
                    }
                    else if (y == (iStartY+iRandomHeight)){
                            dungeonGrid[y][x] = '-';
                    }
                    else if (x == (iStartX+iRandomWidth)){
                            dungeonGrid[y][x] = '|';
                    }
                    else {
                            dungeonGrid[y][x] = '.';
                    }

            }
    }

}

ヒントをありがとう!

于 2013-02-27T03:06:54.130 に答える