您现在的位置: 首页 > 开发编程 > PHP教程 > 正文

PHP 实现微信红包拆分算法

作者:admin来源:网络浏览:时间:2018-04-07 20:47:32我要评论
分享到
PHP 实现微信红包拆分算法

  1. <?php 
  2. /** 
  3.  * 红包分配算法 
  4.  * 
  5.  * example 
  6.  *      $coupon = new Coupon(200, 5); 
  7.  *      $res = $coupon->handle(); 
  8.  *      print_r($res); 
  9.  * 
  10.  * @author Flc <2018-04-06 20:09:53> 
  11.  * @see http://flc.ren | http://flc.io | https://github.com/flc1125 
  12.  */ 
  13. class Coupon 
  14.     /** 
  15.      * 红包金额 
  16.      * 
  17.      * @var float 
  18.      */ 
  19.     protected $amount
  20.  
  21.     /** 
  22.      * 红包个数 
  23.      * 
  24.      * @var int 
  25.      */ 
  26.     protected $num
  27.  
  28.     /** 
  29.      * 领取的红包最小金额 
  30.      * 
  31.      * @var float 
  32.      */ 
  33.     protected $coupon_min
  34.  
  35.     /** 
  36.      * 红包分配结果 
  37.      * 
  38.      * @var array 
  39.      */ 
  40.     protected $items = []; 
  41.  
  42.     /** 
  43.      * 初始化 
  44.      * 
  45.      * @param float $amount     红包金额(单位:元)最多保留2位小数 
  46.      * @param int   $num        红包个数 
  47.      * @param float $coupon_min 每个至少领取的红包金额 
  48.      */ 
  49.     public function __construct($amount$num = 1, $coupon_min = 0.01) 
  50.     { 
  51.         $this->amount = $amount
  52.         $this->num = $num
  53.         $this->coupon_min = $coupon_min
  54.     } 
  55.  
  56.     /** 
  57.      * 处理返回 
  58.      * 
  59.      * @return array 
  60.      */ 
  61.     public function handle() 
  62.     { 
  63.         // A. 验证 
  64.         if ($this->amount < $validAmount = $this->coupon_min * $this->num) { 
  65.             throw new Exception('红包总金额必须≥'.$validAmount.'元'); 
  66.         } 
  67.  
  68.         // B. 分配红包 
  69.         $this->apportion(); 
  70.  
  71.         return [ 
  72.             'items' => $this->items, 
  73.         ]; 
  74.     } 
  75.  
  76.     /** 
  77.      * 分配红包 
  78.      */ 
  79.     protected function apportion() 
  80.     { 
  81.         $num = $this->num;  // 剩余可分配的红包个数 
  82.         $amount = $this->amount;  //剩余可领取的红包金额 
  83.  
  84.         while ($num >= 1) { 
  85.             // 剩余一个的时候,直接取剩余红包 
  86.             if ($num == 1) { 
  87.                 $coupon_amount = $this->decimal_number($amount); 
  88.             } else { 
  89.                 $avg_amount = $this->decimal_number($amount / $num);  // 剩余的红包的平均金额 
  90.  
  91.                 $coupon_amount = $this->decimal_number( 
  92.                     $this->calcCouponAmount($avg_amount$amount$num
  93.                 ); 
  94.             } 
  95.  
  96.             $this->items[] = $coupon_amount// 追加分配 
  97.  
  98.             $amount -= $coupon_amount
  99.             --$num
  100.         } 
  101.  
  102.         shuffle($this->items);  //随机打乱 
  103.     } 
  104.  
  105.     /** 
  106.      * 计算分配的红包金额 
  107.      * 
  108.      * @param float $avg_amount 每次计算的平均金额 
  109.      * @param float $amount     剩余可领取金额 
  110.      * @param int   $num        剩余可领取的红包个数 
  111.      * 
  112.      * @return float 
  113.      */ 
  114.     protected function calcCouponAmount($avg_amount$amount$num
  115.     { 
  116.         // 如果平均金额小于等于最低金额,则直接返回最低金额 
  117.         if ($avg_amount <= $this->coupon_min) { 
  118.             return $this->coupon_min; 
  119.         } 
  120.  
  121.         // 浮动计算 
  122.         $coupon_amount = $this->decimal_number($avg_amount * (1 + $this->apportionRandRatio())); 
  123.  
  124.         // 如果低于最低金额或超过可领取的最大金额,则重新获取 
  125.         if ($coupon_amount < $this->coupon_min 
  126.             || $coupon_amount > $this->calcCouponAmountMax($amount$num
  127.         ) { 
  128.             return $this->calcCouponAmount($avg_amount$amount$num); 
  129.         } 
  130.  
  131.         return $coupon_amount
  132.     } 
  133.  
  134.     /** 
  135.      * 计算分配的红包金额-可领取的最大金额 
  136.      * 
  137.      * @param float $amount 
  138.      * @param int   $num 
  139.      */ 
  140.     protected function calcCouponAmountMax($amount$num
  141.     { 
  142.         return $this->coupon_min + $amount - $num * $this->coupon_min; 
  143.     } 
  144.  
  145.     /** 
  146.      * 红包金额浮动比例 
  147.      */ 
  148.     protected function apportionRandRatio() 
  149.     { 
  150.         // 60%机率获取剩余平均值的大幅度红包(可能正数、可能负数) 
  151.         if (rand(1, 100) <= 60) { 
  152.             return rand(-70, 70) / 100; // 上下幅度70% 
  153.         } 
  154.  
  155.         return rand(-30, 30) / 100; // 其他情况,上下浮动30%; 
  156.     } 
  157.  
  158.     /** 
  159.      * 格式化金额,保留2位 
  160.      * 
  161.      * @param float $amount 
  162.      * 
  163.      * @return float 
  164.      */ 
  165.     protected function decimal_number($amount
  166.     { 
  167.         return sprintf('%01.2f'round($amount, 2)); 
  168.     } 
  169.  
  170. // 例子 
  171. $coupon = new Coupon(200, 5, 30); 
  172. $res = $coupon->handle(); 
  173. print_r($res); 

 

相关热词搜索: 微信红包