需求:默认概率固定,数量抽完为止,单个奖品未抽中则递增概率。
<?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);