PHP red packet algorithm

  1. Total amount of red packets
  2. No limit on the number of red packets
  3. limit red packets, maximum and minimum
  4. when everyone opens the red packet, he or she can get the red packet no more than the total amount of the red packet

based on the above requirements, is there any good way to achieve it

Mar.05,2021

simply write that the amount of red packets sent $count should be saved in memcache or redis. Each time the red packets are taken and sent, the values will be added up to no more than the total amount.
example: (the amount of red packets sent is temporarily saved in a static variable and needs to be modified)

function getRedPack($total, $min, $max){
    static $count = 0;
    $money = mt_rand($min, $max)/100;
    $count += $money;
    if ($count < $total) {
        return $money;
    }
    return false;
}

can you see if this is all right? that's probably the way of thinking.

/**
 * 
 *
 * 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));
    }
}

this code is reproduced to PHPhuo.org users' leaf pit, intruded and deleted!
PHP implements WeChat red packet split algorithm

Menu