游戏中伪随机数的产生
在游戏编程,随机数的应用无所不在,例如扑克类游戏中的随机发牌,俄罗斯方块的随机生成,拼图游戏中单元图片的散化,道具的摆放等等,我们希望所产生的数字随机,而且在我们预先设计的范围之内,同时又不希望有重复的两个数字出现,
对于一般的作法:
对于一般的作法:
srand( (unsigned)time( NULL ) ); // 使用时间产生随机数.
int number=rand()%mRange;
int number=rand()%mRange;
很有可能会产生相同的数字,以致让游戏失去的随机性,趣味性。下面给出通过随机交换产生随机数的程序:
#include <stdio.H>
#include <stdlib.H>
#include <time.H>
#include <stdlib.H>
#include <time.H>
// 随机数产生类
class clRandom
...{
protected:
int mRange; // 随机数的值域
int mIndex; // 取出索引
int *mTable; // 随机数表
bool mAutoGenerate; // 是否自动产生随机数
class clRandom
...{
protected:
int mRange; // 随机数的值域
int mIndex; // 取出索引
int *mTable; // 随机数表
bool mAutoGenerate; // 是否自动产生随机数
public:
// 建构
clRandom( unsigned int Range, bool AutoGen = false ) : mRange(Range),
mTable(NULL),
mIndex(0),
mAutoGenerate(AutoGen)
// 建构
clRandom( unsigned int Range, bool AutoGen = false ) : mRange(Range),
mTable(NULL),
mIndex(0),
mAutoGenerate(AutoGen)
...{
srand( (unsigned)time( NULL ) ); // 使用时间产生随机数.
mRange = Range;
mTable = new int [ mRange ];
Generate(); // 产生随机数.
}
srand( (unsigned)time( NULL ) ); // 使用时间产生随机数.
mRange = Range;
mTable = new int [ mRange ];
Generate(); // 产生随机数.
}
// 析构
virtual ~clRandom()
...{
if ( mTable != NULL )...{
delete [] mTable;
mTable = NULL;
}
mRange = 0;
}
virtual ~clRandom()
...{
if ( mTable != NULL )...{
delete [] mTable;
mTable = NULL;
}
mRange = 0;
}
// 取出随机数
int GetNumber ( void )
...{
int Number = -1;
int GetNumber ( void )
...{
int Number = -1;
if ( mRange > 0 )
...{
Number = mTable[ mIndex ]; // 取出随机数.
++mIndex; // 偏移取出随机数的指针.
if ( mIndex >= mRange )...{
mIndex = 0;
if ( mAutoGenerate )...{ // 是否重新产生随机数?
Generate(); // 产生随机数.
}
}
}
return Number;
}
...{
Number = mTable[ mIndex ]; // 取出随机数.
++mIndex; // 偏移取出随机数的指针.
if ( mIndex >= mRange )...{
mIndex = 0;
if ( mAutoGenerate )...{ // 是否重新产生随机数?
Generate(); // 产生随机数.
}
}
}
return Number;
}
// 随机数重整
void Generate ( void )
...{
int loop, Offset;
// 建立连续数字.
for ( loop=0 ; loop<mRange ; loop++ )
...{
mTable[ loop ] = loop;
}
// 依照随机数变更数字的位置.
for ( loop=0 ; loop<mRange ; loop++ )
...{
int Temp;
// 使用随机数选择要变换的数字.
Offset = (rand()%mRange)+loop;
if ( Offset >= mRange )...{
Offset -= mRange;
}
void Generate ( void )
...{
int loop, Offset;
// 建立连续数字.
for ( loop=0 ; loop<mRange ; loop++ )
...{
mTable[ loop ] = loop;
}
// 依照随机数变更数字的位置.
for ( loop=0 ; loop<mRange ; loop++ )
...{
int Temp;
// 使用随机数选择要变换的数字.
Offset = (rand()%mRange)+loop;
if ( Offset >= mRange )...{
Offset -= mRange;
}
// 将数字对调.
Temp = mTable[ loop ];
mTable[ loop ] = mTable[ Offset ];
mTable[ Offset ] = Temp;
}
Temp = mTable[ loop ];
mTable[ loop ] = mTable[ Offset ];
mTable[ Offset ] = Temp;
}
mIndex = 0;
}
};
}
};
//测试程序:
int main()
...{
Random *RandomMaker;
int loop, range = 20;
RandomMaker = new Random(range);
for(int time = 0; time < range; time++)
...{
std::cout << "第" << time << "组. ";
for(loop = 0; loop < range; loop++)
...{
std::cout << " " << RandomMaker->GetNumber();
}
std::cout << std::endl << std::endl;
RandomMaker->Generate();
}
return 0;
}
...{
Random *RandomMaker;
int loop, range = 20;
RandomMaker = new Random(range);
for(int time = 0; time < range; time++)
...{
std::cout << "第" << time << "组. ";
for(loop = 0; loop < range; loop++)
...{
std::cout << " " << RandomMaker->GetNumber();
}
std::cout << std::endl << std::endl;
RandomMaker->Generate();
}
return 0;
}
值得一提的是这种方法产生的随机数是可逆的,举个例子:拼图游戏中如果图片打乱的过于随机,以致玩者根本不可能完成游戏任务,但用这种方法是绝对没有问题的。