[PHP]奖池抽奖概率递增示例代码

需求:默认概率固定,数量抽完为止,单个奖品未抽中则递增概率。

<?php
class Gift {

    protected $giftPool = [];

    protected $userData = [];

    public function __construct()
    {
        $this->setUserData();
        $this->setGiftPool();
    }

    protected function setGiftPool() {
        /**
         * 奖池默认几率 当前数量 递增几率
         */
        $this->giftPool = [
            [
                'index'=> 0, 'name' => '奖品1', 'probability' => 1, 'quantity' => 3, 'inc_probability' => 0
            ],
            [
                'index'=> 1, 'name' => '奖品2', 'probability' => 10, 'quantity' => 10, 'inc_probability' => 30
            ],
            [
                'index'=> 2, 'name' => '奖品3', 'probability' => 100, 'quantity' => 10, 'inc_probability' => 20
            ],
            [
                'index'=> 3, 'name' => '奖品4', 'probability' => 100, 'quantity' => 10, 'inc_probability' => 30
            ],
            [
                'index'=> 4, 'name' => '奖品5', 'probability' => 1000, 'quantity' => 10, 'inc_probability' => 20
            ],
            [
                'index'=> 5, 'name' => '奖品6', 'probability' => 10000, 'quantity' => 100, 'inc_probability' => 20
            ]
        ];
    }

    protected function setUserData()
    {
        /**
         * 用户抽奖记录
         */
        $this->userData = [
            [
                'time' => time(), 'result' => '奖品6', 'quantity' => 1,
            ],
            [
                'time' => time(), 'result' => '奖品6', 'quantity' => 1,
            ]
        ];
    }

    protected function addUserData($gift)
    {
        $this->userData[] = [
            'time' => time(), 'result' => $gift, 'quantity' => 1,
        ];
    }

    protected function getUserPool()
    {
        $userPool = [];
        foreach ($this->giftPool as $item) { //获取到默认奖池数据 重新计算用户几率
            $userPool[$item['name']] = $item;
            if ($item['inc_probability'] == 0) { //不递增几率奖品
                continue;
            }
            $defaultProbability = $item['probability'];
            foreach ($this->userData as $userData) {
                if ($userData['result'] == $item['name']) { //抽中的话则回归默认概率
                    $userPool[$item['name']]['probability'] = $defaultProbability;
                } else {
                    $userPool[$item['name']]['probability'] += $item['inc_probability'];
                }
            }
        }
        return array_values($userPool);
    }

    protected function getRandomPoolArr()
    {
        $userPool = $this->getUserPool(); //用户正确奖池
        $arr = [];
        while (true) {
            $index = self::random_int(0, count($userPool) - 1);
            $gift = $userPool[$index];
            if ($gift['probability'] == 0) {
                unset($userPool[$index]);
                $userPool = array_values($userPool); //重新分配下标
            } else {
                $arr[] = ['index' => $userPool[$index]['index'], 'name' => $userPool[$index]['name'], 'quantity' => 1];
                $userPool[$index]['probability']--; //移除一个几率数量
            }
            if (empty($userPool)) {
                break;
            }
        }
        return $arr;
    }

    /**
     * 瞎写的取随机值
     * @param $min
     * @param $max
     * @return int
     * @throws Exception
     */
    private function random_int($min, $max)
    {
        if ($max == 0) return 0;
        $r = substr((string)((int)(microtime(true) * 1000)), -(strlen($max))) + random_int($min, random_int($min, $max)) ;
        $avg = abs((int)(($min + $max) / 2) - $r);
        $avg = ($avg % $max) + $min;
        while ($avg > $max) {
            $avg = ($avg % $max) + $min;
        }
        return $avg;
    }

    /**
     * 抽奖
     */
    public function get()
    {
        //抽取奖品
        $pool = $this->getRandomPoolArr();
        while (true) {
            $gift = $pool[self::random_int(0, count($pool) - 1)];
            if ($this->giftPool[$gift['index']]['quantity'] > 0) {
                $this->giftPool[$gift['index']]['quantity']--;
                $this->addUserData($gift['name']);
                return $gift;
            }
            //重新抽取
        }
    }
}

$gift = new Gift();
for ($i=0; $i < 100; $i++) {
    $result = $gift->get();
    $arr[$result['name']] = ($arr[$result['name']] ?? 0) +1;
}
var_dump($arr);