• 技术文章 >后端开发 >php教程

    分享实现PHP红包算法的思路(附开发代码)

    藏色散人藏色散人2021-09-06 09:07:13转载967
    根据很多需求的使用场景,如发红包、砍价类需求,这两个功能都有一个同样的特点,如下:

    红包

    1.总金额
    2.红包个数
    3.最小红包数量

    砍价

    1.砍价总金额
    2.需要多少人完成砍价(人数根据需求而定)

    • 固定砍价人数
    • 随机砍价人数
    • 指定随机砍价人数
      第2点三个规则都需要根据规则得出一个人数

    3.最小砍价金额

    开发思路

    验证参数

    最小金额不允许小于0
    总金额不允许大于数量乘最小金额

    分配金额

    取得平均金额(总金额/剩余数量)

    分配金额 平均金额小于等于最金额时直接分配最小金额
    获取金额幅度比例 最小值不允许小于 -1 最大值不允许大于 1
    得出分配金额 幅度计算(平均值*(1+幅度比例))
    分配金额判断 分配金额小于最小金额或者分配金额大于 可领取最大金额 ((最小金额+剩余总金额)- (剩余数量×最小金额))时 重新分配金额
    剩余最后一个则剩余所有金额都分配

    开发代码

    <?php
    
    /**
     * 发送红包
     * Class sandRed
     */
    class sandRed
    {
        #红包金额
        protected $amount;
        #红包个数
        protected $num;
        #领取的红包最小金额
        protected $minAmount;
        #红包分配结果
        protected $amountArr = [];
    
        public function __construct($amount, $num = 1, $minAmount = 1)
        {
            $this->amount = $amount;
            $this->num = $num;
            $this->minAmount = $minAmount;
        }
    
        /**
         * 处理返回
         * @return array
         * @throws Exception
         */
        public function handle()
        {
            # 验证
            if ($this->amount < $validAmount = $this->minAmount * $this->num) {
                throw new Exception('红包总金额必须≥'.$validAmount.'元');
            }
            # 分配红包
            $this->allot();
            return $this->amountArr;
        }
    
        /**
         * 分配红包
         */
        protected function allot()
        {
            # 剩余可分配的红包个数
            $num = $this->num;
    
            # 剩余可领取的红包金额
            $amount = $this->amount;
            while ($num >= 1) {
                if ($num == 1) {
                    # 剩余一个的时候,直接取剩余红包
                    $coupon_amount = $this->formattingAmount($amount);
                } else {
    
                    # 平均金额
                    $avgAmount = $this->formattingAmount($amount / $num);
    
                    # 分配金额
                    $countAllotAmount = $this->countAllotAmount($avgAmount, $amount, $num);
    
                    # 剩余的红包的平均金额
                    $coupon_amount = $this->formattingAmount($countAllotAmount);
                }
                # 追加分配金额
                $this->amountArr[] = $coupon_amount;
    
                # 计算剩余金额
                $amount -= $coupon_amount;
    
                $num--;
            }
            # 随机打乱
            // shuffle($this->amountArr);
        }
    
        /**
         * 计算分配的红包金额
         * @param float $avgAmount 每次计算的平均金额
         * @param float $amount 剩余可领取金额
         * @param int $num 剩余可领取的红包个数
         * @return float
         */
        protected function countAllotAmount($avgAmount, $amount, $num)
        {
            # 如果平均金额小于等于最低金额,则直接返回最低金额
            if ($avgAmount <= $this->minAmount) {
                return $this->minAmount;
            }
            # 浮动比率
            $floatingRate = $this->floatingRate();
    
            # 分配金额
            $allotAmount = $avgAmount * (1 + $floatingRate);
    
            # 浮动计算
            $coupon_amount = $this->formattingAmount($allotAmount);
    
            # 如果低于最低金额或超过可领取的最大金额,则重新获取
            if ($coupon_amount < $this->minAmount || $coupon_amount > $this->canReceiveMaxAmount($amount, $num)) {
                return $this->countAllotAmount($avgAmount, $amount, $num);
            }
            return $coupon_amount;
        }
    
        /**
         * 计算分配的红包金额-可领取的最大金额
         * @param $amount
         * @param $num
         * @return float|int
         */
        protected function canReceiveMaxAmount($amount, $num)
        {
            return $this->minAmount + $amount - $num * $this->minAmount;
        }
    
        /**
         * 红包金额浮动比例
         * @return float|int
         */
        protected function floatingRate()
        {
            # 60%机率获取剩余平均值的大幅度红包(可能正数、可能负数)
            if (rand(1, 100) <= 60) {
                # 上下幅度70%
                return rand(-70, 70) / 100;
            }
            # 其他情况,上下浮动30%;
            return rand(-30, 30) / 100;
        }
    
        /**
         * 格式化金额,保留2位
         * @param $amount
         * @return string
         */
        protected function formattingAmount($amount)
        {
            return sprintf('%01.2f', round($amount, 2));
        }
    }
    • 总金额
    $amount = 1;
    • 分配数量
    $num = 10;
    • 最小金额
    $minAmount = 0.01;
    
    $red = new sandRed($amount, $num, $minAmount);
    
    $res = $red->handle();
    print_r($res);
    • 输出结果 [0.10,0.04,0.08,0.04,0.16,0.14,0.11,0.13,0.11,0.09]
    echo array_sum($res);
    • 输出结果 1

    推荐学习:《PHP视频教程

    以上就是分享实现PHP红包算法的思路(附开发代码)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:segmentfault,如有侵犯,请联系admin@php.cn删除
    专题推荐:php
    上一篇:数组实现方式:PHP5 VS PHP7 下一篇:简单对比一下PHP 7 和 PHP 5 中的对象
    线上培训班

    相关文章推荐

    • PHP 生成随机红包算法• 实现PHP微信红包API接口• 简析PHP拆红包算法• 详解PHP怎么使用动态规划实现最优红包组合

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网