游戏开发——随机数和概率在游戏中的使用

转载至  【Visual C++】游戏开发笔记十七 游戏基础算法(一) 游戏随机系统初步

计算机中一般不能产生绝对随机的随机数。计算机产生随机数的过程,是根据一个数(我们可以称它为种子)为基准以某个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的值是确定的,除非你对系统进行了更改。即计算机一般情况下只能生成相对的随机数,即伪随机数。

在很多时候,我们会使用rand()函数与srand()配合来达到产生随机数的效果,srand初始化随机种子,rand产生随机数。

一、随机数发生器rand()函数的用法

函数名: rand
功 能: 随机数发生器
用 法: int rand(void);
所在头文件: stdlib.h
函数说明 :
▲rand()的内部实现是用的线性同余法,它不是真的随机数,因其周期特别长,故在一定的范围里可看成是随机的。
▲这种伪随机数是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子。(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了。)
▲目前,计算机中用来产生随机数的算法基本上都是“线性同余”法。rand()返回一随机数值的范围在0至RAND_MAX 间。RAND_MAX的范围最少是在32767之间(int)。
▲用unsigned int 双字节是65535,四字节是4294967295的整数范围。0~RAND_MAX每个数字被选中的机率是相同的。
▲用户未设定随机数种子时,系统默认的随机数种子为1。
▲rand( )产生的是伪随机数字,每次执行时是相同的;若要不同,用函数srand()初始化它。

//MyRand01.cpp
#include   
using namespace std;  
#include         
#include      
#define MIN 1    //随机数产生的范围      
#define MAX 10  

int main()     
{   
    int i;   
    srand((unsigned)time(0));  
    cout<<"10个随机数从 "<

二、初始化随机数发生器srand( )函数的用法

函数名: srand
功 能: 初始化随机数发生器
用 法: void srand(unsigned int seed);
所在头文件: stdlib.h
函数说明:
▲srand()用来设置rand()产生随机数时的随机数种子。
▲参数seed必须是个整数,通常可以利用time(0)的返回值或NULL来当做seed。
▲如果每次seed都设相同值,rand()所产生的随机数值每次就会一样。

三、rand( )和srand( )的联系

rand( )和srand( )要一起使用,其中srand( )用来初始化随机数种子,rand( )用来产生随机数。
因为默认情况下随机数种子为1,而相同的随机数种子产生的随机数是一样的,失去了随机性的意义,所以为使每次得到的随机数不一样,用函数srand()初始化随机数种子。srand()的参数,用time函数值(即当前时间),因为两次调用rand()函数的时间通常是不同的,这样就可以保证随机性了。

四、产生相同的随机数的原因

计算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子。(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了。)
我们知道rand()函数可以用来产生随机数,这里我再啰嗦一遍。计算机中一般不能产生绝对随机的随机数。计算机产生随机数的过程,是根据一个数(我们可以称它为种子)为基准以某个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的值是确定的,除非你对系统进行了更改。

五、产生一定范围随机数的通用算法公式


▲要取得[a,b)的随机整数,使用(rand() % (b-a))+ a (结果值含a不含b)。
▲要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a (结果值含a和b)。
▲要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1 (结果值不含a含b)。
▲即(通用公式:a + rand() % n;取得[a,a+n) 的随机整数,其中的a是起始值,n是整数的范围。)
▲要取得[a,b) 的随机整数,另一种表示:a + (int)(b-a) * rand() / (RAND_MAX + 1)。
▲要取得[a,b] 的随机整数 另一种表示:a + (int)(b-a) * rand() / (RAND_MAX )。
▲要取得[0,1] 之间的浮点数 ,可以使用rand() / double(RAND_MAX)。

1.产生一个范围内的随机数
一般地,我们可用j=1+(int)(n*rand()/(RAND_MAX+1.0))来生成一个0到n之间的随机数。
若用int x = rand() % 101;来生成 0 到 100 之间的随机数这种方法是不可取的,比较好的做法是:
j=(int)(100.0*rand()/(RAND_MAX+1.0))
当然,如果是在gcc,vc之外的编译器,我们也可以使用random(100)。下面的例子都是用了random(n)(VC无法识别random这个函数,VC下我们还是采用 j=(int)(100.0*rand()/(RAND_MAX+1.0)).
2、筛选型随机数 如希望取0-99的随机数,但不能是6。
解决方法:
x = random(100);
while (x==6) {
x = random(100);
}
又如希望取0-99的随机数,但不要5的倍数 解决方法:
x = random(100);
while ((x % 5)==0) {
x = random(100);
}
3、从连续的一段范围内取随机数。
如从40--50的范围内取随机数。 解决方法: x=random(11)+40
4、从一组乱数中取随机数。 如:从 67, 87, 34, 78, 12, 5, 9, 108, 999, 378十个数中随机取数。 解决方法:可以用数组将些十个数存贮,然后把0--9中取出的随机数作为序号,实现随机取数。
a = new Array(67, 87, 34, 78, 12, 5, 9, 108, 999, 378);
j = random(10);
x = a[j];

六、随机数在游戏中的应用

有了概率之后,我们只需要在 0~99 之间随机出数值:

例如 25% ,如果数字在 25~50 之间就表示命中。

装备强化的成功率,副本里装备的掉落率,通关奖励翻牌的掉落率,攻击暴击的概率,攻击MISS的几率,梦幻西游里碰到变异宝宝的概率等等都可以这样实现。



你可能感兴趣的:(游戏开发)