幸运抽奖大转盘-算法解析

中奖池

1
2
3
4
5
6
7
8
9
10
$prize_arr = array( 
'0' => array('id'=>1,'min'=>1,'max'=>29,'prize'=>'一等奖','v'=>1),
'1' => array('id'=>2,'min'=>302,'max'=>328,'prize'=>'二等奖','v'=>2),
'2' => array('id'=>3,'min'=>242,'max'=>268,'prize'=>'三等奖','v'=>5),
'3' => array('id'=>4,'min'=>182,'max'=>208,'prize'=>'四等奖','v'=>7),
'4' => array('id'=>5,'min'=>122,'max'=>148,'prize'=>'五等奖','v'=>10),
'5' => array('id'=>6,'min'=>62,'max'=>88,'prize'=>'六等奖','v'=>25),
'6' => array('id'=>7,'min'=>array(32,92,152,212,272,332),
'max'=>array(58,118,178,238,298,358),'prize'=>'七等奖','v'=>50)
);

定义一个数组$prize_arr,id用来标识不同的奖项,
min表示圆盘中各奖项区间对应的最小角度,max表示最大角度,
如一等奖对应的最小角度:0,最大角度30,这里我们设置max值为1、max值为29,
是为了避免抽奖后指针指向两个相邻奖项的中线。
由于圆盘中设置了多个七等奖,所以我们在数组中设置每个七等奖对应的角度范围。

prize表示奖项内容,v表示中奖几率,我们会发现,
数组中七个奖项的v的总和为100,如果v的值为1,则代表中奖几率为1%,依此类推。

中奖概率算法

先来看概率计算函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function getRand($proArr) { 
$result = '';

//概率数组的总概率精度
$proSum = array_sum($proArr);

//概率数组循环
foreach ($proArr as $key => $proCur) {
$randNum = mt_rand(1, $proSum);
if ($randNum <= $proCur) {
$result = $key;
break;
} else {
$proSum -= $proCur;
}
}
unset ($proArr);

return $result;
}

上述代码是一段经典的概率算法,$proArr是一个预先设置的数组,
假设数组为:array(100,200,300,400),
开始是从1,1000这个概率范围内筛选第一个数是否在他的出现概率范围之内,
如果不在,则将概率空间,也就是k的值减去刚刚的那个数字的概率空间,
在本例当中就是减去100,也就是说第二个数是在1,900这个范围内筛选的。
这样筛选到最终,总会有一个数满足要求。
就相当于去一个箱子里摸东西,第一个不是,第二个不是,第三个还不是,那最后一个一定是。

这个算法简单,而且效率非常高,关键是这个算法已在我们以前的项目中有应用,尤其是大数据量的项目中效率非常棒。

函数getRand()会根据数组中设置的几率计算出符合条件的id,我们可以接着调用getRand()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
foreach ($prize_arr as $key => $val) { 
$arr[$val['id']] = $val['v'];
}

$rid = getRand($arr); //根据概率获取奖项id

$res = $prize_arr[$rid-1]; //中奖项
$min = $res['min'];
$max = $res['max'];
if($res['id']==7){ //七等奖
$i = mt_rand(0,5);
$result['angle'] = mt_rand($min[$i],$max[$i]);
}else{
$result['angle'] = mt_rand($min,$max); //随机生成一个角度
}
$result['prize'] = $res['prize'];

echo json_encode($result);

代码中,我们调用getRand(),获得通过概率运算后得到的奖项,然后根据奖项中配置的角度范围,
在最小角度和最大角度间生成一个角度值,并构建数组,包含角度angle和奖项prize,最终以json格式输出。

为什么我抽不到大奖?

在很多类似的抽奖活动中,参与者往往抽不到大奖,笔者从程序的角度举个例给你看,
假如我是抽奖活动的主办方,我设置了6个奖项,每个奖项不同的中奖概率,假如一等奖是一台高级轿车,
可是我设置了其中奖概率为0,
这意味着什么?这意味着参与抽奖者无论怎么抽,
永远也得不到这台高级轿车。
而当主办方每次翻动剩下的方块时,参与者会发现一等奖也许就在刚刚抽奖的方块旁边的一个数字下,
都怪自己运气差。真的是运气差吗?其实在参与者翻动那个方块时程序已经决定了中奖项,
而翻动查看其他方块看到的奖项只是一个烟雾弹,迷惑了观众和参与者。
我想看完这篇文章后,您或许会知道电视节目中的翻板抽奖猫腻了,您也许大概再不会去机选双色球了。

热评文章