php split red envelopes

<?php
/**
 * Red envelope allocation algorithm
 *
 * 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
{
    /**
     * The amount of red envelopes
     *
     Float * @var
     */
    protected $amount;
  
    /**
     * The number of red envelopes
     *
     * @was not
     */
    protected $num;
  
    /**
     * Receive a minimum amount of red envelopes
     *
     Float * @var
     */
    protected $coupon_min;
  
    /**
     * Red envelope allocation results
     *
     * @Var array
     */
    protected $items = [];
  
    /**
     * Initialization
     *
     * @Param float $ amount envelopes Amount (Unit: RMB) retain up to two decimal places
     * $ @Param int num the number of red envelopes
     * @Param float $ coupon_min each receive at least the amount of red envelopes
     */
    public function __construct($amount, $num = 1, $coupon_min = 0.01)
    {
        $this->amount = $amount;
        $this->num = $num;
        $this->coupon_min = $coupon_min;
    }
  
    /**
     * Processing returns
     *
     * @return array
     */
    public function handle()
    {
        // A. Verify 
        IF ( $ the this -> AMOUNT < $ validAmount = $ the this -> coupon_min * $ the this -> NUM) {
             the throw  new new  Exception ( 'red total amount must be ≥'. $ ValidAmount 'dollars' );
        }
  
        // B. allocated envelopes 
        $ the this -> apportion ();
  
        return [
            'items' => $this->items,
        ];
    }
  
    /**
     * Red envelope distribution
     */
    protected function apportion()
    {
        NUM $ = $ the this -> NUM;   // remaining number assigned red 
        $ AMOUNT = $ the this -> AMOUNT;   // red can receive the remaining amount of
  
        the while ( $ NUM > =. 1 ) {
             // remaining a time, direct access to the remaining red 
            IF ( $ NUM ==. 1 ) {
                 $ of COUPON_AMOUNT = $ the this -> decimal_number ( $ AMOUNT );
            } The else {
                 $ avg_amount = $ the this -> decimal_number ( $ AMOUNT / $ NUM );   // the average amount of remaining red
  
                $coupon_amount = $this->decimal_number(
                    $this->calcCouponAmount($avg_amount, $amount, $num)
                );
            }
  
            the this $ -> items [] = $ of COUPON_AMOUNT ; // additional distribution
  
            $amount -= $coupon_amount;
            --$num;
        }
  
        shuffle ( $ the this -> items);   // random disrupted 
    }
  
    /**
     * Calculated assigned amount of red envelopes
     *
     * @Param float $ avg_amount average amount of each calculation
     * @Param float $ amount remaining can receive money
     * @Param int num $ number can receive the remaining red
     *
     * @return float
     */
    protected function calcCouponAmount($avg_amount, $amount, $num)
    {
        // If the average amount is less than equal to the minimum amount, the minimum amount returned directly 
        IF ( $ avg_amount <= $ the this -> coupon_min) {
             return  $ the this -> coupon_min;
        }
  
        // sliding scale 
        $ of COUPON_AMOUNT = $ the this -> decimal_number ( $ avg_amount * (. 1 + $ the this -> apportionRandRatio ()));
  
        // If the amount is below the minimum or maximum amount that can receive over, then re-acquired 
        IF ( $ of COUPON_AMOUNT < $ the this -> coupon_min
             || $ of COUPON_AMOUNT > $ the this -> calcCouponAmountMax ( $ AMOUNT , $ NUM )
        ) {
            return $this->calcCouponAmount($avg_amount, $amount, $num);
        }
  
        return $coupon_amount;
    }
  
    /**
     * Red envelope calculation amount allocated - can receive the maximum amount
     *
     * @param float $amount
     * @Param int $ whether
     */
    protected function calcCouponAmountMax($amount, $num)
    {
        return $this->coupon_min + $amount - $num * $this->coupon_min;
    }
  
    /**
     * Amount proportion of floating red envelopes
     * / 
    Protected  function apportionRandRatio ()
    {
        // 60% chance of obtaining a substantial average remaining red (may be positive, negative possible) 
        IF ( RAND (. 1, 100) <= 60 ) {
             return  RAND (-70, 70) / 100; // vertical width 70 % 
        }
  
        return  RAND (-30, 30) / 100; // other cases, plus or minus 30%; 
    }
  
    /**
     * Formatting amount reserved 2
     *
     * @param float $amount
     *
     * @return float
     */
    protected function decimal_number($amount)
    {
        return sprintf('%01.2f', round($amount, 2));
    }
}
  
// 例子
$coupon = new Coupon(200, 5, 30);
$res = $coupon->handle();
print_r($res);

  

Guess you like

Origin www.cnblogs.com/wangguizhong/p/11981977.html