首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 抽獎演算法:加權機率與大轉盤實作

     編輯:PHP 相關知識

核心演算法:加權隨機抽取

/**
 * 依權重陣列抽取索引
 * @param array $weights ['prize_id' => weight, ...] 權重總和為基數
 * @return int|string 抽中鍵名
 */
function weighted_rand(array $weights) {
    $total = array_sum($weights);
    $rand  = mt_rand(1, $total);
    foreach ($weights as $key => $weight) {
        if ($rand <= $weight) return $key;
        $rand -= $weight;
    }
    // 理論不會到達這裡,保底回傳最後一項
    return array_key_last($weights);
}

完整抽獎流程範例

<?php
// 獎項設定:id, 名稱, 權重(整數)
$prizes = [
    1 => ['name' => 'iPad Pro',        'weight' => 1],   // 0.5%
    2 => ['name' => 'AirPods',         'weight' => 5],   // 2.5%
    3 => ['name' => '星巴克禮券 500',  'weight' => 20],  // 10%
    4 => ['name' => '折扣碼 9 折',      'weight' => 50],  // 25%
    5 => ['name' => '再接再厲',        'weight' => 124], // 62%
];

// 基數 = 200,機率 = weight / 200
$weights = array_column($prizes, 'weight', 'id');

// 抽獎
$winId = weighted_rand($weights);
$win   = $prizes[$winId];

// 紀錄中獎、扣除庫存、記錄日誌...
echo "恭喜中獎:{$win['name']}";

// 前端 AJAX 回傳 JSON
header('Content-Type: application/json');
echo json_encode(['code'=>0, 'prize'=>$win['name'], 'id'=>$winId]);

大轉盤前端配合

  1. 後端回傳中獎索引 winId
  2. 前端計算對應角度:angle = (winId - 1) * (360 / count) + random(0, sectorAngle)
  3. CSS transform: rotate() + transition: transform 3s cubic-bezier(0.17, 0.67, 0.12, 0.99) 產生減速效果
  4. 動畫結束後彈窗顯示獎品

防作弊與公平性機制

風險對策
前端竄改請求簽名驗證 (HMAC)、CSRF Token、Rate Limit
重複抽獎Redis SETNX 鎖 + 用戶每日次數計數器
內部人員操縱權重配置審計日志、上線審核、開獎結果不可逆記錄
機率顯示不實公開演算法邏輯、第三方公證、區塊鏈存證

庫存控制:動態權重調整

function adjust_weights($prizes, $stock) {
    foreach ($prizes as $id => &$p) {
        if ($stock[$id] <= 0) $p['weight'] = 0; // 售罄機率歸零
    }
    return $prizes;
}

擴充:保底機制 (Pity System)

// 連續 N 次未中大獎 → 第 N+1 次必中
$userPity = $redis->get("pity:{$uid}") ?: 0;
if ($userPity >= 99) {
    $weights[1] = 10000; // 大獎權重拉高
    $userPity = 0;
} else {
    $userPity++;
}
$redis->set("pity:{$uid}", $userPity);
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved