根据很多需求的使用场景,如发红包、砍价类需求,这两个功能都有一个同样的特点,如下:
빨간 봉투
1. 총 금액
2. 빨간 봉투의 개수
3. 빨간 봉투의 최소 수량
총 할인 금액2. . 필요한 인원수 완전 교섭(인원은 수요에 따라 다름)
고정된 교섭 인원
- 교섭할 인원 무작위
- 교섭할 인원 무작위 지정
- 포인트 2: 3명 규칙은 모두 규칙에 따라 여러 사람에게 도달해야 합니다
-
3. 최소 협상 금액
개발 아이디어
검증 매개 변수
최소 금액은 0보다 작을 수 없습니다총 금액은 수량에 최소금액을 곱한 금액을 초과할 수 없습니다
배분금액평균금액을 구합니다(총액/잔여수량) 배포금액 평균금액은
이하
이고 최소량은 직접 할당됩니다. 진폭 비율
을 가져옵니다. 최소값은 -1
보다 작을 수 없으며 최대값은 1진폭 계산(평균 * (1+진폭 비율
))
분배량
이 최소 금액 또는 배분 금액
이 수취 가능한 최대 금액
보다 큰 경우 ((최소 금액 + 남은 총액) - (남은 수량 × 최소 금액) ))) 재할당 금액이 마지막이면 남은 금액 모두 할당개발 코드小于等于
最金额时直接分配最小金额
获取金额幅度比例
最小值不允许小于-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.14,0.11,0.11,0.09]echo array_sum($res);