PHP抽奖算法

一、初始化奖品
  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
  ]);

八、抽奖封装成类
  <?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());

posted @   橙子与柠檬  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版
点击右上角即可分享
微信分享提示