PHP 红包算法

class RedPacket
{
    public $bonus = [];                     //红包
    public $bonusNum;                       //红包个数
    public $bonusMoney;                     //红包总金额
    public $moneySingleMax;                 //单个红包最大限制
    public $moneySingleMin;                 //单个红包最小限制
    public static $error = '';

    /**
     * redPackageService constructor.
     * @param int $bonusNum
     * @param int $bonusMoney
     */
    public function __construct($bonusNum = 20, $bonusMoney = 200)
    {
        $avg = ceil($bonusMoney / $bonusNum);
        $avgHalf = ceil($avg / 2);

        $this->bonusNum = $bonusNum;
        $this->bonusMoney = $bonusMoney;
        $this->moneySingleMax = $avg + $avgHalf;
        $this->moneySingleMin = $avg - $avgHalf;
    }

    /**
     * 是否能够发随机红包
     * @param $bonusMoney
     * @param $bonusNum
     * @return bool
     */
    public function isCanBuilder($bonusMoney, $bonusNum)
    {
        if (false == is_int($bonusNum) || $bonusNum <= 0) {
            return false;
        }
        if (false == is_numeric($bonusMoney) || $bonusMoney <= 0) {
            return false;
        }

        //均值
        $avgMoney = $bonusMoney / 1.0 / $bonusNum;
        //均值小于最小值
        if ($avgMoney < 0.01) {
            return false;
        }

        return true;
    }

    private function randomFloat($min = 0, $max = 1)
    {
        $mtRand = mt_rand();
        $mtGetRandMax = mt_getrandmax();
        return $min + $mtRand / $mtGetRandMax * ($max - $min);
    }

    //计算
    public function compute()
    {
        if (!$this->isCanBuilder($this->bonusMoney, $this->bonusNum)) {
            return false;
        };
        $bonusMoneyTemp = $this->bonusMoney;
        $moneySingleMax = $this->moneySingleMax;
        $moneySingleMin = $this->moneySingleMin;
        $i = 1;
        while ($i < $this->bonusNum) {
            if ($moneySingleMax > $bonusMoneyTemp) {
                $moneySingleMax = floatval(sprintf("%01.2f", $bonusMoneyTemp / 2));//剩余金额不够分时,把剩余金额的一半作为备用金
                if ($moneySingleMin > $moneySingleMax) { //最小金额大于最大金额时,将最小金额设置为最大金额的一半
                    $moneySingleMin = floatval(sprintf("%01.2f", $moneySingleMax / 2));
                }
            }
            $bonusMoneyRad = $this->randomFloat($moneySingleMin, $moneySingleMax);//一个红包随机金额
            $bonusMoneyRad = floatval(sprintf("%01.2f", $bonusMoneyRad));
            $bonusMoneyTemp = $bonusMoneyTemp - $bonusMoneyRad;//待分配的总剩余金额
            $bonusMoneyTemp = floatval(sprintf("%01.2f", $bonusMoneyTemp));
            $this->bonus[] = $bonusMoneyRad;
            $i++;
        }
        $this->bonus[] = $bonusMoneyTemp;//分配剩余金额给最后一个红包
    }

    /**
     * 红包金额存入Redis
     * @param $hb_id
     */
    public function redisSave($hb_id)
    {
        foreach ($this->bonus as $key => $val) {
            Redis::rpush('red-packet-' . $hb_id, $val);
        }
    }

    /**
     * 领取红包
     * @param $hb_id
     * @return bool
     */
    public function getRedisInfo($hb_id)
    {
        if (!Redis::exists('red-packet-' . $hb_id)) {
            self::$error = '红包已领完';
            return false;
        }

        // todo 是否领取过红包判断
        return Redis::lpop('red-packet-' . $hb_id);

    }

    //打印
    public function output()
    {
        $total = 0;
        foreach ($this->bonus as $k => $v) {
            echo '红包' . ($k + 1) . '=' . $v . '<br/>';
            $total += $v;
        }
        echo '红包总金额:' . $total;
    }
}