根据很多需求的使用场景,如发红包、砍价类需求,这两个功能都有一个同样的特点,如下:

红包

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

砍价

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

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

3.最小砍价金额

开发思路

验证参数

最小金额不允许小于0

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

分配金额

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

开发代码

<?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红包算法的思路(附开发代码)
—–文章转载自PHP中文网如有侵权请联系ymkuzhan@126.com删除

下载声明:
  • 本站资源如无特殊说明默认解压密码为www.ymkuzhan.com建议使用WinRAR解压;
  • 本站资源来源于用户分享、互换、购买以及网络收集等渠道,本站不提供任何技术服务及有偿服务,资源仅提供给大家学习研究请勿作它用。
  • 赞助本站仅为维持服务器日常运行并非购买程序及源码费用因此不提供任何技术支持,如果你喜欢该程序,请购买正版!
  • 版权声明:
  • 下载本站资源学习研究的默认同意本站【版权声明】若本站提供的资源侵犯到你的权益,请提交版权证明文件至邮箱ymkuzhan#126.com(将#替换为@)站长将会在三个工作日内为您删除。
  • 免责声明:
  • 您好,本站所有资源(包括但不限于:源码、素材、工具、字体、图像、模板等)均为用户分享、互换、购买以及网络收集而来,并未取得原始权利人授权,因此禁止一切商用行为,仅可用于个人研究学习使用。请务必于下载后24小时内彻底删除,一切因下载人使用所引起的法律相关责任,包括但不限于:侵权,索赔,法律责任,刑事责任等相关责任,全部由下载人/使用人,全部承担。以上说明,一经发布视为您已全部阅读,理解、同意以上内容,如对以上内容持有异议,请勿下载,谢谢配合!支持正版,人人有责,如不慎对您的合法权益构成侵犯,请联系我们对相应内容进行删除,谢谢!