在软件开发过程中,尤其是APP或者或者游戏中,经常会涉及到这样一种问题:为了刺激用户消费,需要设置一种抽奖功能,用户点击抽奖按钮,会随机获取其中一种奖励,但是问题来了,不能让一等奖太容易抽到,那样的话,岂不是亏大发了,所以,一般来说,会有这样的需求,越大的奖项,抽中的概率越小,越小的奖项,抽中的概率越大,因此,要对不同的奖项设置权重,例如,3等奖抽中的概率是70%,2等奖是20%,1等奖是10%,这样,大部分人都只能中3等奖,小部分人是二等奖,而只有特别少的人才可能拿到一等奖。
但是,对于这样的问题,怎样才能实现这样的随机效果呢?直接使用random函数,是不可能做到的。其实相信好多人都已经有实现的思路了,就是产生0-100之间的随机数,当随机数在0-70时,就获得3等奖,70-90是2等奖,90-100是一等奖。一般情况下,这种随机概率,是通过读取表格或文件来获取的,然后保存在数组之类的容器中,这里只使用数组来模拟这些数据。下面,我们就来用C++实现这个功能:
由于在C/C++中没有random函数,这里先自己定义一个。这里使用C语言自带的rand函数,但直接使用rand函数会产生一个问题,就是每次产生的随机数都是同一个随机数,所以,这里使用时间来产生随机种子,这样,产生的数就是随机的了。根据时间产生随机种子要用到time.h,使用rand函数要用到stdlib.h,这里引入两个头文件和基本的头文件:
#include
#include
#include
创建自己的random函数:
int random(int x){
srand((int)time(0));
return rand()%x;
}
int main(){
//设置各种奖励的权重,这里不一定总和是100,多少都可以
int a[5] = {5,10,15,25,45};
int length = sizeof(a)/sizeof(int);
int sum = 0;
for (int i = 0; i < length; i++)
{
sum += a[i];
}
int randVal = random(sum);
printf("%d\n",randVal);
int grade = 0;
for (int i = 0;i < length; i++)
{
if (randVal <= a[i])
{
grade = i+1;
break;
}
randVal -= a[i];
}
printf("%d等奖\n",grade);
system("pause");
return 0;
}
下面,要加深程序难度了。
由于笔者是游戏开发者,这里就以游戏来说事儿吧(貌似只有游戏会有这么多的要求)。在游戏中通常会有VIP机制,也就是说,玩家需要充钱,来提升自己的VIP等级,然后,在抽奖过程中,部分奖励的概率也会相应的大一些,VIP等级越高,抽取高级奖励的概率会越大。那么,我们只需要将上面的数组a变成二位数组,来模拟这种情况即可。相比你已经想到了该怎么做,现在上代码:
int main(){
int a[4][5] = {{1,5,10,35,49},
{2,6,12,32,48},
{3,8,15,29,45},
{5,10,15,30,40}};
int length = sizeof(a[0])/sizeof(int);
//设置VIP等级
int vip = 3;
int sum = 0;
for (int i = 0; i < length; i++)
{
sum += a[vip][i];
}
int randVal = random(sum);
printf("%d\n",randVal);
int grade = 0;
for (int i = 0;i < length; i++)
{
if (randVal <= a[vip][i])
{
grade = i+1;
break;
}
randVal -= a[vip][i];
}
printf("%d等奖\n",grade);
system("pause");
return 0;
}
这还只是简单的问题,还有更难的。大家都知道,随机函数会产生一个范围的数,例如,0-100,也就是说会产生边界值0和100,不仅如此,而且,概率也不小。0-100总共101个数,这两个数的概率都是1/101,举个例子,当VIP0的时候,如果权重是这样的:{0,5,10,35,50},也就是说,在设计的时候,不是VIP的话,抽不到1等奖,但是从上面的方法来说,如果随机的数randVal的值为0,randVal<=a[0][0],也就是0,等于条件满足了,也就是抽到了1等奖,但是,按照策划的要求,不应该有0,程序设计的结果和策划要求不匹配,而且,概率还很大,有人会想,如果将权重同时乘以100,产生0-10000的随机数,这样概率就小很多了,但实际上,还是不可行,还是有概率,因此,要想方法将为0的值过滤掉,这样,就不会产生权重为0的奖励了。所以,这里要对0进行判断,当a[vip][i] == 0时,就直接退出当前循环,进入下次的循环,这样就避免了这样的问题。代码上,只需要在上面的for循环中,先判断是否为0即可。代码如下:
for (int i = 0;i < length; i++)
{
if (a[vip][i] == 0)
{
continue;
}
if (randVal <= a[vip][i])
{
grade = i+1;
break;
}
randVal -= a[vip][i];
}