php算法抽荣耀水晶,还在抱怨王者荣耀水晶难抽?PHP一文带你搞懂游戏中的抽奖算法...

本文介绍了抽奖算法的实现过程,包括初始化奖品信息、过滤条件、重组概率、进行抽奖及结果过滤等步骤。通过代码展示了如何根据用户充值条件、奖品总数及每日限制进行动态过滤,确保抽奖的公平性和系统稳定性。最后,将抽奖功能封装为一个类,方便复用。
摘要由CSDN通过智能技术生成

前言: 没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。

希望:所以说,树倒了,没有一片雪花是无辜的,抽奖都是假的,只有人家想让你中和不想让你中,如果大家觉得文章有帮助,请给博主一波关注和评论。

目录

一、初始化奖品

id 奖品的id

pid 奖品的自定义id

type 奖品类型,1、虚拟奖品 2、实物奖品 3、礼包码 待扩充

name奖品名称

total奖品总数

chance获奖概率/抽奖基数10000

daynum 每日数量限制

pay 充值限制

$prize = [

['id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],

['id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],

['id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],

['id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]

];

奖品详情应该从数据库中读出来

奖品详情应该加入缓存,避免数据库的压力

二、谢谢参与

$thanks_prize = [

'id' => 0,

'pid' => 0,

'type' => 1,

'name' => '谢谢参与'

];

为填充剩余概率的奖品

三、过滤抽奖、如充值条件

$pay_total = 7000;

foreach ($prize as $key => $value) {

if($value['pay'] > $pay_total) unset($prize[$key]);

}

初步过滤一些必要因素,比如充值,角色创建时间等

四、重组概率

$now_chance = array_sum(array_column($prize, 'chance'));

$remain_chance = 10000 - $now_chance;

$prize[] = ['id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];

$award = [];

$num = 0;

foreach ($prize as $_v) {

$num += $_v['chance'];

$award[] = ['id' => $_v['id'], 'pid' => $_v['pid'], 'type' => $_v['type'], 'name' => $_v['name'], 'total' => $_v['total'], 'chance' => $num, 'daynum' => $_v['daynum'], 'pay' => $_v['pay']];

}

初步过滤后,重构新的抽奖信息,加入谢谢参与

第二步重组概率

五、进行抽奖

$rand = mt_rand(1, 10000);

$result = [];

foreach ($award as $_k => $_v) {

if ($_k == 0) {

if ($rand > 0 && $rand <= $_v['chance']) {

$result = $_v;

break;

}

} else {

if ($rand > $award[$_k - 1]['chance'] && $rand <= $_v['chance']) {

$result = $_v;

break;

}

}

}

开始抽奖,并返回抽中的结果

六、过滤回调

//此处应该查询数据库,查看该奖品已经抽中的数量

$yet_num = 50;

if($result['pid'] != 0 && $yet_num > $result['total']) {

$result = $thanks_prize;

}

//此处应该查询数据库,查看该奖品今日已经抽中的数量

$yet_today_num = 50;

if($result['pid'] != 0 && $yet_today_num > $result['daynum']) {

$result = $thanks_prize;

}

二次过滤,奖品总数的限制以及奖品的每日限制等

七、最终抽奖结果

//删除敏感字段

unset($result['total'],$result['chance'],$result['daynum'],$result['pay']);

//返回最终抽奖结果

echo json_encode([

'prize' => $award,

'rand' => $rand,

'result' => $result

]);

八、抽奖封装成类

/**

* Created by PhpStorm.

* User: autofelix

* Date: 2020/10/30

* Time: 13:14

* Desc: 抽奖算法

*/

class Lottery

{

/**

* 概率基数

* @var int

*/

private $total_chance = 10000;

/**

* 谢谢参与奖励

* @var array

*/

private $thanks_prize = [

'id' => 0,

'pid' => 0,

'type' => 1,

'name' => '谢谢参与'

];

/**

* 奖池

* @var array

*/

private $prize = [

['id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],

['id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],

['id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],

['id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]

];

/**

* Lottery constructor.

*/

public function __construct()

{

}

/**

* @return int

*/

private function get_user_pay()

{

//这里应该调用接口,返回用户正确的充值信息

return 3000;

}

/**

* 重构奖池、重组概率

* @return array

*/

private function init_lottery_pond()

{

$award = [];

//充值限制

$user_pay = $this->get_user_pay();

foreach ($this->prize as $key => $value) {

if($value['pay'] <= $user_pay) unset($this->prize[$key]);

}

//加入谢谢惠顾

$now_chance = array_sum(array_column($this->prize, 'chance'));

$remain_chance = $this->total_chance - $now_chance;

$this->prize[] = ['id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];

//重组概率

$num = 0;

foreach ($this->prize as $_v) {

$num += $_v['chance'];

$award[] = ['id' => $_v['id'], 'pid' => $_v['pid'], 'type' => $_v['type'], 'name' => $_v['name'], 'total' => $_v['total'], 'chance' => $num, 'daynum' => $_v['daynum'], 'pay' => $_v['pay']];

}

return $award;

}

/**

* 获取抽奖结果

* @return array

*/

public function get_prize()

{

$award = $this->init_lottery_pond();

$rand = mt_rand(1, $this->total_chance);

$result = [];

foreach ($award as $_k => $_v) {

if ($_k == 0) {

if ($rand > 0 && $rand <= $_v['chance']) {

$result = $_v;

break;

}

} else {

if ($rand > $award[$_k - 1]['chance'] && $rand <= $_v['chance']) {

$result = $_v;

break;

}

}

}

$result = $this->filter($result);

return $result;

}

/**

* 抽奖过滤回调函数

* @param $result

* @return array

*/

public function filter($result)

{

//奖品总数限制,此处应该查数据库

$yet_num = 50;

if($result['pid'] != 0 && $yet_num > $result['total']) {

$result = $this->thanks_prize;

}

//奖品每日数量限制,此处应该查数据库

$yet_today_num = 50;

if($result['pid'] != 0 && $yet_today_num > $result['daynum']) {

$result = $this->thanks_prize;

}

//不暴露敏感信息

unset($result['total'], $result['chance'], $result['daynum'], $result['pay'] );

return $result;

}

private function __clone()

{

}

}

echo json_encode((new Lottery())->get_prize());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值