抽獎活動 演算法設計
- 2021 年 3 月 5 日
- 筆記
- php, 抽獎
場景
項目變數
- 參與人數未知
- 活動持續時間未知(活動方可能根據活動熱度增減時間,以月為單位)
- 可預見的『老闆需求』:活動人數太多了,臨時增加1個大獎 & 無數個小獎。或者大獎太少,臨時增加出大獎概率刺激活動效果。
舉例:獎池設定
- 一等獎: 2個
- 二等獎:30個
- 三等獎:500個
- 四等獎:20000個
實現方案討論
- rand 程式隨機? 可能會超發,據說有策劃團隊已經賠過錢了
- 提前把獎品數量轉化為資料庫的記錄。用戶抽獎時,利用資料庫的隨機查詢
select * from 獎池表 where status = '未被抽中' order by rand() limit 0,1
。問題:記錄數太多,調整(增減)獎品數量不靈活,方案不優雅
最終方案
- 每次開獎結果:
rand(1, 當時的獎品總數)
,具體看程式碼
- 優勢:隨時增減獎池數量,沒有關聯其它表(靈活、解耦),不會超發
程式碼
<?php
$priceInfo = [
'102' => 3,
'203' => 10,
'3092' => 100,
];
function getPrice(&$priceInfo)
{
if (!array_sum($priceInfo)) {
return 0;
}
$randId = rand(1, array_sum($priceInfo));
$i = 0;
foreach ($priceInfo as $id => $num) {
$i += $num;
if ($i >= $randId) {
$priceInfo[$id]--;
return $id;
}
}
}
for ($i = 0; $i < 130; $i++) {
echo "\n 中獎ID: " . getPrice($priceInfo);
}
echo "\n 獎池狀態:\n";
print_r($priceInfo);