目录
前言
没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。
希望:所以说,树倒了,没有一片雪花是无辜的,抽奖都是假的,只有人家想让你中和不想让你中,如果大家觉得文章有帮助,欢迎点赞。
一、初始化奖品
- id 奖品的id
- pid 奖品的自定义id
- type 奖品类型,1、虚拟奖品 2、实物奖品 3、礼包码 待扩充
- name 奖品名称
- total 奖品总数
- chance 获奖概率/抽奖基数10000
- daynum 每日数量限制
- pay 充值限制
<?php $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 ] ];
奖品详情应该从数据库中读出来
奖品详情应该加入缓存,避免数据库的压力
二、谢谢参与
<?php $thanks_prize = [ \'id\' => 0, \'pid\' => 0, \'type\' => 1, \'name\' => \'谢谢参与\' ];
为填充剩余概率的奖品
三、过滤抽奖、如充值条件
<?php $pay_total = 7000; foreach ($prize as $key => $value) { if($value[\'pay\'] > $pay_total) unset($prize[$key]); }
初步过滤一些必要因素,比如充值,角色创建时间等
四、重组概率
<?php $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\']]; }
初步过滤后,重构新的抽奖信息,加入谢谢参与
第二步重组概率
五、进行抽奖
<?php $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; } } }
开始抽奖,并返回抽中的结果
六、过滤回调
<?php //此处应该查询数据库,查看该奖品已经抽中的数量 $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; }
二次过滤,奖品总数的限制以及奖品的每日限制等
七、最终抽奖结果
<?php //删除敏感字段 unset($result[\'total\'],$result[\'chance\'],$result[\'daynum\'],$result[\'pay\']); //返回最终抽奖结果 echo json_encode([ \'prize\' => $award, \'rand\' => $rand, \'result\' => $result ]);
八、抽奖封装成类
<?php /** * 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());
以上就是PHP一文带你搞懂游戏中的抽奖算法的详细内容,更多关于PHP抽奖算法的资料请关注其它相关文章!
© 版权声明
THE END
暂无评论内容