PHP 实现微信红包拆分的算法


/*** 红包分配算法** @example*      $coupon = new Coupon(200, 5);*      $res = $coupon->handle();*      print_r($res);** @author Flc <2018-04-06 20:09:53>* @see http://flc.ren | http://flc.io | https://github.com/flc1125*/
class Coupon
{/*** 红包金额** @var float*/protected $amount;/*** 红包个数** @var int*/protected $num;/*** 领取的红包最小金额** @var float*/protected $coupon_min;/*** 红包分配结果** @var array*/protected $items = [];/*** 初始化** @param float $amount     红包金额(单位:元)最多保留2位小数* @param int   $num        红包个数* @param float $coupon_min 每个至少领取的红包金额*/public function __construct($amount, $num = 1, $coupon_min = 0.01){$this->amount = $amount;$this->num = $num;$this->coupon_min = $coupon_min;}/*** 处理返回** @return array*/public function handle(){// A. 验证if ($this->amount < $validAmount = $this->coupon_min * $this->num) {throw new Exception('红包总金额必须≥'.$validAmount.'元');}// B. 分配红包$this->apportion();return ['items' => $this->items,];}/*** 分配红包*/protected function apportion(){$num = $this->num;  // 剩余可分配的红包个数$amount = $this->amount;  //剩余可领取的红包金额while ($num >= 1) {// 剩余一个的时候,直接取剩余红包if ($num == 1) {$coupon_amount = $this->decimal_number($amount);} else {$avg_amount = $this->decimal_number($amount / $num);  // 剩余的红包的平均金额$coupon_amount = $this->decimal_number($this->calcCouponAmount($avg_amount, $amount, $num));}$this->items[] = $coupon_amount; // 追加分配$amount -= $coupon_amount;--$num;}shuffle($this->items);  //随机打乱}/*** 计算分配的红包金额** @param float $avg_amount 每次计算的平均金额* @param float $amount     剩余可领取金额* @param int   $num        剩余可领取的红包个数** @return float*/protected function calcCouponAmount($avg_amount, $amount, $num){// 如果平均金额小于等于最低金额,则直接返回最低金额if ($avg_amount <= $this->coupon_min) {return $this->coupon_min;}// 浮动计算$coupon_amount = $this->decimal_number($avg_amount * (1 + $this->apportionRandRatio()));// 如果低于最低金额或超过可领取的最大金额,则重新获取if ($coupon_amount < $this->coupon_min|| $coupon_amount > $this->calcCouponAmountMax($amount, $num)) {return $this->calcCouponAmount($avg_amount, $amount, $num);}return $coupon_amount;}/*** 计算分配的红包金额-可领取的最大金额** @param float $amount* @param int   $num*/protected function calcCouponAmountMax($amount, $num){return $this->coupon_min + $amount - $num * $this->coupon_min;}/*** 红包金额浮动比例*/protected function apportionRandRatio(){// 60%机率获取剩余平均值的大幅度红包(可能正数、可能负数)if (rand(1, 100) <= 60) {return rand(-70, 70) / 100; // 上下幅度70%}return rand(-30, 30) / 100; // 其他情况,上下浮动30%;}/*** 格式化金额,保留2位** @param float $amount** @return float*/protected function decimal_number($amount){return sprintf('%01.2f', round($amount, 2));}
}// 例子
$coupon = new Coupon(200, 5, 30);
$res = $coupon->handle();
print_r($res);


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部