php 抽奖思路,PHP抽奖算法思路?

本文介绍了一种抽奖算法的设计思路,通过确定随机数范围和奖品号码区间来确保每次抽奖都能准确匹配奖品,同时讨论了算法的优化可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上有个烂大街的算法,具体请看链接

大概原理是:

1,生成一个随机数;

2,循环对比第N个奖品的概率;

3,确定奖品;

如果按照这个算法,主观上是抽一次奖,但客观上,把每个奖品都循环抽了一遍,其实是抽了N次,不知道我的理解对不对。

下面是我写的算法,具体原理是:

1,先确定随机数(幸运号码)的范围;

2,确定每个奖品的号码区间,确保只抽一次奖能对应到某个奖品;

3,根据范围生成一个幸运号码;

4,根据范围确定奖品;

请教各路大神,有没有更优的算法或思路?

$goods = [

0 => [

'id' => 1,

'name' => '苹果电脑',

'odds' => '0.01' //概率

],

1 => [

'id' => 2,

'name' => 'Iphone',

'odds' => '10.99'

],

2 => [

'id' => 3,

'name' => '200元红包',

'odds' => '19'

],

3 => [

'id' => 4,

'name' => '安慰奖',

'odds' => '30'

],

4 => [

'id' => 5,

'name' => '什么都没抽到',

'odds' => '40'

],

];

$baseOdds = 100; //抽奖概率基数,默认100%

$maxBase = 1; //抽奖概率基数倍数,默认1,如果奖品概率有小数位,该倍数为10的小数位数平方,具体看下面

foreach ($goods as $good) {

$decimal = strpbrk($good['odds'], '.'); //获取小数点后面的内容

if ($decimal !== false) {

$decimalCount = strlen($decimal) - 1;//获取小数点后面的位数

$newMaxBase = pow(10, $decimalCount); //例如概率如果是0.01,则全局的抽奖概率基数需要以10的平方倍数上涨

if ($newMaxBase > $maxBase) {

$maxBase = $newMaxBase; //更新基数倍数

}

}

}

$baseOdds = $maxBase ? $baseOdds * $maxBase : $baseOdds; //更新概率基数

$start = 1;

$end = 0;

$luckyCompare = $tickets = [];

//为每个奖品生成一个幸运数区间

foreach ($goods as $key => $good) {

$newOdds = $good['odds'] * $maxBase;

$end = $end + $newOdds;

$luckyCompare[$good['id']] = [$start, $end];

$tick = mt_rand($start, $end);

$start = $start + $newOdds;

$tickets[$good['id']] = $tick;

}

$luckyNumber = mt_rand(1, $baseOdds);

var_dump($luckyNumber);

var_dump($luckyCompare);

foreach ($luckyCompare as $goodId => $compare) {

if ($compare[0] <= $luckyNumber && $compare[1] >= $luckyNumber) {

$luckyGood = $goodId; //最终的奖品

break;

}

}

var_dump($luckyGood);

回复内容:

网上有个烂大街的算法,具体请看链接

大概原理是:

1,生成一个随机数;

2,循环对比第N个奖品的概率;

3,确定奖品;

如果按照这个算法,主观上是抽一次奖,但客观上,把每个奖品都循环抽了一遍,其实是抽了N次,不知道我的理解对不对。

下面是我写的算法,具体原理是:

1,先确定随机数(幸运号码)的范围;

2,确定每个奖品的号码区间,确保只抽一次奖能对应到某个奖品;

3,根据范围生成一个幸运号码;

4,根据范围确定奖品;

请教各路大神,有没有更优的算法或思路?

$goods = [

0 => [

'id' => 1,

'name' => '苹果电脑',

'odds' => '0.01' //概率

],

1 => [

'id' => 2,

'name' => 'Iphone',

'odds' => '10.99'

],

2 => [

'id' => 3,

'name' => '200元红包',

'odds' => '19'

],

3 => [

'id' => 4,

'name' => '安慰奖',

'odds' => '30'

],

4 => [

'id' => 5,

'name' => '什么都没抽到',

'odds' => '40'

],

];

$baseOdds = 100; //抽奖概率基数,默认100%

$maxBase = 1; //抽奖概率基数倍数,默认1,如果奖品概率有小数位,该倍数为10的小数位数平方,具体看下面

foreach ($goods as $good) {

$decimal = strpbrk($good['odds'], '.'); //获取小数点后面的内容

if ($decimal !== false) {

$decimalCount = strlen($decimal) - 1;//获取小数点后面的位数

$newMaxBase = pow(10, $decimalCount); //例如概率如果是0.01,则全局的抽奖概率基数需要以10的平方倍数上涨

if ($newMaxBase > $maxBase) {

$maxBase = $newMaxBase; //更新基数倍数

}

}

}

$baseOdds = $maxBase ? $baseOdds * $maxBase : $baseOdds; //更新概率基数

$start = 1;

$end = 0;

$luckyCompare = $tickets = [];

//为每个奖品生成一个幸运数区间

foreach ($goods as $key => $good) {

$newOdds = $good['odds'] * $maxBase;

$end = $end + $newOdds;

$luckyCompare[$good['id']] = [$start, $end];

$tick = mt_rand($start, $end);

$start = $start + $newOdds;

$tickets[$good['id']] = $tick;

}

$luckyNumber = mt_rand(1, $baseOdds);

var_dump($luckyNumber);

var_dump($luckyCompare);

foreach ($luckyCompare as $goodId => $compare) {

if ($compare[0] <= $luckyNumber && $compare[1] >= $luckyNumber) {

$luckyGood = $goodId; //最终的奖品

break;

}

}

var_dump($luckyGood);

只能说 呵呵 了。抽奖的算法的决定权不在程序员,这才是重点。

通常抽奖活动是由营销部门发起、策划、评估、运作的,程序员的作用只是做实现而已。该营销行为策划案应该包含奖品设置、活动时长、推广策略、冷/热场时间、奖品投放批次等等东西,简单来说,这是营销部门导演的一场戏,开发人员是现场指挥,程序负责调度,抽奖者就是演员了。

所以,抽奖算法根本没用,只要你放出去的奖品不要超出奖池就行了,别的都不重要。

可能有人会说了,那怎么体现抽奖的公平公正?其实几乎不需要考虑这个问题,因为程序写好之后是自动执行的,这个时候对所有参与者来说已经是一个同等环境了,不存在不公平的问题。

典型的伪算法如下:

雨露奖:消费抵扣券5元,中奖率100%;

水坑奖:消费抵扣券10元,中奖率50%;

奔雷奖:消费抵扣券100元,中奖率5%;

雷劈奖:iPad一个,共6个。

活动时间12小时,彩票无上限。

算法:抽奖时间戳微秒部分是20的倍数=奔雷,是单数=水坑,否则为雨露。每两个小时为一个周期,下一周期开始时的第一个抽奖人获得上一个周期的雷劈奖,整个活动在持续时间截止后收到第一个彩票则完全结束。

有不公平的问题吗?所以,呵呵。最后还是要根据需求写程序。

$arr = array(10000,1000,100,10,1);

for ($i=0;$i<5;$i++){

if(rand(1,$arr[$i])==1){

echo "恭喜你中了".$i."奖";//这个描述自己写

}

}

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值