php stats红包算法,PHP红包算法

PHP红包算法

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

红包

1.总金额

2.红包个数

3.最小红包数量

砍价

1.砍价总金额

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

固定砍价人数

随机砍价人数

指定随机砍价人数

第2点三个规则都需要根据规则得出一个人数

3.最小砍价金额

开发思路

验证参数

最小金额不允许小于0

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

分配金额

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

分配金额 平均金额小于等于最金额时直接分配最小金额

获取金额幅度比例 最小值不允许小于 -1 最大值不允许大于 1

得出分配金额 幅度计算(平均值*(1+幅度比例))

分配金额判断 分配金额小于最小金额或者分配金额大于 可领取最大金额 ((最小金额+剩余总金额)- (剩余数量×最小金额))时 重新分配金额

剩余最后一个则剩余所有金额都分配

开发代码

/**

* 发送红包

* 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值