请选择 进入手机版 | 继续访问电脑版
查看: 190|回复: 0

PHP一文带你搞懂游戏中的抽奖算法

[复制链接]

2066

主题

2066

帖子

6594

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
6594
发表于 2022-10-9 01:03:19 | 显示全部楼层 |阅读模式
前言

没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才华显得毫不费力。
希望:所以说,树倒了,没有一片雪花是无辜的,抽奖都是假的,只有人家想让你中和不想让你中,如果大家觉得文章有资助,欢迎点赞。

一、初始化奖品


  • id 奖品的id
  • pid 奖品的自定义id
  • type 奖品类型,1、虚拟奖品 2、实物奖品 3、礼包码 待扩充
  • name 奖品名称
  • total 奖品总数
  • chance 获奖概率/抽奖基数10000
  • daynum 每日数量限制
  • pay 充值限制
  1. <?php
  2. $prize = [
  3.     ['id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],
  4.     ['id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  5.     ['id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  6.     ['id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]
  7. ];
复制代码
奖品详情应该从数据库中读出来
奖品详情应该加入缓存,制止数据库的压力

二、谢谢到场
  1. <?php
  2. $thanks_prize = [
  3.     'id' => 0,
  4.     'pid' => 0,
  5.     'type' => 1,
  6.     'name' => '谢谢参与'
  7. ];
复制代码
为填充剩余概率的奖品

三、过滤抽奖、如充值条件
  1. <?php
  2. $pay_total = 7000;
  3. foreach ($prize as $key => $value) {
  4.     if($value['pay'] > $pay_total) unset($prize[$key]);
  5. }
复制代码
开端过滤一些须要因素,好比充值,角色创建时间等

四、重组概率
  1. <?php
  2. $now_chance = array_sum(array_column($prize, 'chance'));
  3. $remain_chance = 10000 - $now_chance;
  4. $prize[] = ['id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];

  5. $award = [];
  6. $num = 0;
  7. foreach ($prize as $_v) {
  8.     $num += $_v['chance'];
  9.     $award[] = ['id' => $_v['id'], 'pid' => $_v['pid'], 'type' => $_v['type'], 'name' => $_v['name'], 'total' => $_v['total'], 'chance' => $num, 'daynum' => $_v['daynum'], 'pay' => $_v['pay']];
  10. }
复制代码
开端过滤后,重构新的抽奖信息,加入谢谢到场
第二步重组概率

五、进行抽奖
  1. <?php
  2. $rand = mt_rand(1, 10000);
  3. $result = [];
  4. foreach ($award as $_k => $_v) {
  5.     if ($_k == 0) {
  6.         if ($rand > 0 && $rand <= $_v['chance']) {
  7.             $result = $_v;
  8.             break;
  9.         }
  10.     } else {
  11.         if ($rand > $award[$_k - 1]['chance'] && $rand <= $_v['chance']) {
  12.             $result = $_v;
  13.             break;
  14.         }
  15.     }
  16. }
复制代码
开始抽奖,并返回抽中的结果

六、过滤回调
  1. <?php
  2. //此处应该查询数据库,查看该奖品已经抽中的数量
  3. $yet_num = 50;
  4. if($result['pid'] != 0 && $yet_num > $result['total']) {
  5.     $result = $thanks_prize;
  6. }

  7. //此处应该查询数据库,查看该奖品今日已经抽中的数量
  8. $yet_today_num = 50;
  9. if($result['pid'] != 0 && $yet_today_num > $result['daynum']) {
  10.     $result = $thanks_prize;
  11. }
复制代码
二次过滤,奖品总数的限制以及奖品的每日限制等

七、最终抽奖结果
  1. <?php
  2. //删除敏感字段
  3. unset($result['total'],$result['chance'],$result['daynum'],$result['pay']);

  4. //返回最终抽奖结果
  5. echo json_encode([
  6.     'prize' => $award,
  7.     'rand' => $rand,
  8.     'result' => $result
  9. ]);
复制代码
八、抽奖封装成类
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: autofelix
  5. * Date: 2020/10/30
  6. * Time: 13:14
  7. * Desc: 抽奖算法
  8. */

  9. class Lottery
  10. {
  11.     /**
  12.      * 概率基数
  13.      * @var int
  14.      */
  15.     private $total_chance = 10000;

  16.     /**
  17.      * 谢谢参与奖励
  18.      * @var array
  19.      */
  20.     private $thanks_prize = [
  21.         'id' => 0,
  22.         'pid' => 0,
  23.         'type' => 1,
  24.         'name' => '谢谢参与'
  25.     ];

  26.     /**
  27.      * 奖池
  28.      * @var array
  29.      */
  30.     private $prize = [
  31.         ['id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],
  32.         ['id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  33.         ['id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
  34.         ['id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]
  35.     ];

  36.     /**
  37.      * Lottery constructor.
  38.      */
  39.     public function __construct()
  40. {
  41.     }

  42.     /**
  43.      * @return int
  44.      */
  45.     private function get_user_pay()
  46. {
  47.         //这里应该调用接口,返回用户正确的充值信息
  48.         return 3000;
  49.     }

  50.     /**
  51.      * 重构奖池、重组概率
  52.      * @return array
  53.      */
  54.     private function init_lottery_pond()
  55. {
  56.         $award = [];

  57.         //充值限制
  58.         $user_pay = $this->get_user_pay();
  59.         foreach ($this->prize as $key => $value) {
  60.             if($value['pay'] <= $user_pay) unset($this->prize[$key]);
  61.         }

  62.         //加入谢谢惠顾
  63.         $now_chance = array_sum(array_column($this->prize, 'chance'));
  64.         $remain_chance = $this->total_chance - $now_chance;
  65.         $this->prize[] = ['id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];

  66.         //重组概率
  67.         $num = 0;
  68.         foreach ($this->prize as $_v) {
  69.             $num += $_v['chance'];
  70.             $award[] = ['id' => $_v['id'], 'pid' => $_v['pid'], 'type' => $_v['type'], 'name' => $_v['name'], 'total' => $_v['total'], 'chance' => $num, 'daynum' => $_v['daynum'], 'pay' => $_v['pay']];
  71.         }

  72.         return $award;
  73.     }

  74.     /**
  75.      * 获取抽奖结果
  76.      * @return array
  77.      */
  78.     public function get_prize()
  79. {
  80.         $award = $this->init_lottery_pond();
  81.         $rand = mt_rand(1, $this->total_chance);
  82.         $result = [];
  83.         foreach ($award as $_k => $_v) {
  84.             if ($_k == 0) {
  85.                 if ($rand > 0 && $rand <= $_v['chance']) {
  86.                     $result = $_v;
  87.                     break;
  88.                 }
  89.             } else {
  90.                 if ($rand > $award[$_k - 1]['chance'] && $rand <= $_v['chance']) {
  91.                     $result = $_v;
  92.                     break;
  93.                 }
  94.             }
  95.         }

  96.         $result = $this->filter($result);
  97.         return $result;
  98.     }

  99.     /**
  100.      * 抽奖过滤回调函数
  101.      * @param $result
  102.      * @return array
  103.      */
  104.     public function filter($result)
  105. {
  106.         //奖品总数限制,此处应该查数据库
  107.         $yet_num = 50;
  108.         if($result['pid'] != 0 && $yet_num > $result['total']) {
  109.             $result = $this->thanks_prize;
  110.         }

  111.         //奖品每日数量限制,此处应该查数据库
  112.         $yet_today_num = 50;
  113.         if($result['pid'] != 0 && $yet_today_num > $result['daynum']) {
  114.             $result = $this->thanks_prize;
  115.         }

  116.         //不暴露敏感信息
  117.         unset($result['total'], $result['chance'], $result['daynum'], $result['pay'] );
  118.         return $result;
  119.     }

  120.     private function __clone()
  121. {
  122.     }
  123. }

  124. echo json_encode((new Lottery())->get_prize());
复制代码
以上就是PHP一文带你搞懂游戏中的抽奖算法的详细内容,更多关于PHP抽奖算法的资料请关注趣UU其它相关文章!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
打赏作者
  • 0
  • 0
  • 0
  • 0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表