2013-02-26 1 views
6

다른 프로젝트에서 작업 중이므로 숫자를 임의로 생성하려면 mt19937을 사용해야합니다. 우리는 그리드의 섹션을 기반으로 무작위로 x와 y 좌표를 선택해야합니다. 예를 들어, 내 함수는 minX, maxX, minY, maxY을 함수에 전달합니다. 내 x 좌표가 잘 작동합니다. 테스트가 끝나면 무작위로 오류가 발생했습니다. 때로는 문제없이 10 번 실행되고 오류가 발생합니다. mt 생성기가 실제로 생성하는 것을 표시하기 위해 일부 자체 디버그 라인을 넣었습니다. 내가 말했듯이, x는 잘 작동하고 y는 때로는 그렇습니다. 그것은 무작위로 나에게 줄거야 -3437892 또는 9743903.왜 내 mt19937 무작위 발전기가 우스운 결과를 내고 있습니까? C++

여기 내 코드입니다 :

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] = '.'; 
        } 

      } 
    } 

} 
+0

왜 iStartY에서만 발생하는지 혼란 스럽습니다. X는 잘 작동합니다. – ModdedLife

+2

'mt19937'는 [C++ 11 난수 엔진] (http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine)이거나 일부 사용자 정의 유형입니까? –

+0

그런 경우 매개 변수 (minX, maxX 등)에 어떤 값이 있습니까? – Slava

답변

0

@haatschii의 도움으로 만든 아마추어 실수를 알아 냈습니다.

이제는 많은 의미가 있습니다. iStartY와 iStartX는 0보다 작거나 같은 숫자로 설정하는 데 아무런 제한이 없었습니다. 나는 그 LOL을 잡지 못해서 너무 바보 같아요. 값이 0보다 큰지 확인하기 위해 루프를 추가했습니다. iStartX 및 iStartY 값을 maxX + 1 및 maxY + 1로 시작하여 자동으로 루프를 입력하여 0보다 큰 솔루션을 생성했습니다.

을 Heres 솔루션 코드 : 팁들에 대한

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] = '.'; 
        } 

      } 
    } 

} 

감사합니다!

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의 답변도 참조하십시오.

+0

바로이 부분. OP의 코드에서 오류가 어디에 있는지 알 수는 없지만 '% n'까지는 'n'까지의 난수 생성에 많은 문제가 있으며, 배포판을 사용하면 코드가 ** 많이 ** 깨끗해집니다. – us2012

+0

필자는 권장 사항에 동의하지만'uint32_t' 배포를 사용하여'(signed) int' 변수에 값을 할당하는 이유는 무엇입니까? – jogojapan

+0

@jogojapan : 분포로 생성 된 모든 값이'> = 0'이므로'uint32_t'를 선택했습니다. 그러나'int32_t' 또는'int'도 마찬가지로 좋을 것입니다. 암시 적 캐스트를 서명 된 int에 저장하는 것조차도 중요하다고 생각하지 않습니까? – Haatschii

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; 
} 

이 첫 번째 서명 된 하나에 해당하는 것보다 약간 더 큰 부호없는 정수를 생성합니다. mt19937은 부호가없고, 위의 코드에서 i과 같은 값을 제공하기도합니다. 다음

상기 코드의 출력 (on liveworkspace 참조) 인 :

2 
2147484647 
-2147482649 

번째 행 음수와 모듈의 결과를 나타낸다 (iRandomHeight 언젠가 것 등), 부호인가 대응하는 부호 첨부 정수보다 큰 정수. 세 번째 줄은 부호있는 정수로 변환 할 때 일어나는 일을 보여줍니다 (부호있는 정수 변수에 할당 할 때 암시 적으로 수행).

당신이 인생을 편하게하기 위해 std::uniform_int_distribution을 사용해야한다는 Haatschii에 동의하지만, 서명 된 서명과 서명되지 않은 서명도 적절하게 사용하는 것이 중요합니다.

+0

이것은 실제 답변 IMO입니다. 'std :: uniform_int_distribution'은 언제나 올바른 선택이 아니지만 바람직하지 않은 속성이 있습니다. –

관련 문제