处理另一个项目,我们需要使用mt19937
随机生成数字。我们应该让它根据网格的部分随机选择一个x和y坐标。例如,我的函数将minX
,maxX
,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] = '.';
}
}
}
}
答案 0 :(得分: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的答案。
答案 1 :(得分: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
),应用于大于适合相应的有符号整数的无符号整数。第三行显示当您将其转换回有符号整数时会发生什么(当您将其分配给您的一个有符号整数变量时,它会隐式执行)。
虽然我同意Haatschii你应该使用std::uniform_int_distribution
来让你的生活更轻松,但即使在那时使用签名和未签名也很重要。
答案 2 :(得分:0)
弄清楚我在@haatschii的帮助下犯下的业余错误。
现在非常有意义。 iStartY和iStartX对于被设置为低于或等于零的数字没有限制。我觉得因为没有抓住那个哈哈而感到愚蠢。我添加了另一个循环以确保该值大于0.我还使iStartX和iStartY值以maxX + 1和maxY + 1开始,以便它们自动进入循环以生成大于0的解。 / p>
继承解决方案代码:
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] = '.';
}
}
}
}
感谢小伙伴们!