讀古今文學網 > 微信公眾平台開發:從零基礎到ThinkPHP5高性能框架實踐 > 24.5.6 中獎算法實現 >

24.5.6 中獎算法實現

中獎算法實現是程序中的一個核心功能,它決定著整個抽獎是否能正常運作。下面將這一過程分解後進行講解。

1)身份合法性判斷。

首先獲取用戶微信的OpenID,如果沒有傳輸過來,或者傳輸了但值為空,則返回空。其實現代碼如下。


include_once('mysql.class.php');
$db = new class_mysql;

if (!isset($_GET['openid']) || ($_GET['openid'] == "")){
    echo "非法調用";
    return ;
}

$openid = $_GET['openid'];

// 1.判斷該用戶是否已註冊,未註冊不返回
$mysql_state = "SELECT * FROM 'wx_user' WHERE 'openid' = '".$openid."' ";
$userInfo = $db->query_array_one($mysql_state);
// var_dump($userInfo);
if (count($userInfo) == 0){
    echo "未註冊或非法用戶";
    return;
}
  

2)抽獎資格判斷。

首先獲取系統配置表中每個用戶每天最大的抽獎次數,然後查詢當前用戶當天已抽獎的次數。如果用戶當前的抽獎次數已達到每天最大次數,則返回「max_times」的錯誤類型。


// 2.判斷該用戶是否還有抽獎資格
$mysql_state = "SELECT * FROM 'wx_config' WHERE 'id' = 1 LIMIT 0 , 1";
$config = $db->query_array_one($mysql_state);
// var_dump($config);
$mysql_state = "SELECT * FROM 'wx_winner' WHERE 'openid' =  '".$openid."' AND 'getdate' = '".date("Y-m-d",time)."'";
$qualification = $db->query_array($mysql_state);
// var_dump($qualification);
if (count($qualification) >= $config['maxtimes']){
    // echo "已抽獎";
    echo '{
        "error": "max_times",
        "message": "",
        "prizelevel": "", 
        "success": ""
    }';
    return;
}
  

3)獎品余留判斷。

即使用戶還有抽獎資格,也要對當前獎品剩餘量進行判斷。如果獎品已經都抽完了,那麼所有用戶都不應該再抽到獎品。


// 3. 判斷獎項是否仍有剩餘
$mysql_state = "SELECT * FROM 'wx_award' WHERE LENGTH('name') > 0";
$award = $db->query_array($mysql_state);
if (count($award) == 0){
    echo "沒有配置獎項???";
    return;
}
  

4)生成中獎概率。

用戶能不能中獎,是以所有概率相加之後為基數,以當前的隨機數為分子來進行匹配的如果能匹配到某個獎品等級的區間,則認為他中了該等級的獎。其代碼如下。


// 4.生成中獎概率
// 統計總的中獎概率
$allprob = 0;
for ($i = 0; $i < count($award); $i++) {
    $allprob += $award[$i]['prob'];
}

// 總和不足100,補齊100
if ($allprob <= 100){
    $allprob =100;
}
// var_dump('allprob:'.$allprob);

// 4. 隨機生成本次中獎概率
// 使用區間分佈方法,保證各概率上的倍率一致
$random = rand(1, $allprob); // 21/100 = 20% 最終中獎概率
$min = 0;
$max = 0;
$level = -1;
// var_dump('random:'.$random);
for ($i = 0; $i < count($award); $i++) {
    $min += ($i < 1)?0:$award[$i-1]['prob'];
    $max += $award[$i]['prob'];
    // var_dump('min:'.$min);
    // var_dump('max:'.$max);
    if ($random >= $min  && $random < $max ){
        $level = $i + 1;
        break;
    }
}
  

5)獎品分配及返回。

如果在上一步計算出用戶應該中獎,那麼在中獎獎品仍有剩餘的情況下,給他分配當前獎品,並且將中獎記錄寫入數據庫,同時返回中獎信息。如果沒有中獎,則消耗一次中獎機會。其代碼如下。


// 24.分配獎品
$lucky = false;
$finally = "";
for ($i = 0; $i < count($award); $i++) {
    
    if ($award[$i]['id'] ==  $level && $award[$i]['total'] >= 1){
        // 獎項減1
        $mysql_state1 = "UPDATE 'wx_award' SET 'total' = 'total' -1 WHERE 'id' = ".$level;
        $result = $db->execute($mysql_state1);
        // 寫入抽獎並且中獎
        $mysql_state1 = "INSERT INTO 'wx_winner' ('id' ,'openid' ,'award' ,'getdate' ,
        'status') VALUES (NULL ,  '".$openid."', '".$award[$i]['name']."',  '".date
        ("Y-m-d",time)."',  '0');";
        $result = $db->execute($mysql_state1);
        // 要返回的結果
        $finally = '{
            "error": "ok",
            "message": "'.$award[$i]['name'].'",
            "prizelevel": "'.$award[$i]['id'].'", 
            "success": "y"
        }';
        $lucky = true;
        break;
    }
}
if (!$lucky){
    // 寫入已抽獎,但不中獎
    $mysql_state1 = "INSERT INTO 'wx_winner' ('id' ,'openid' ,'award' ,'getdate' ,
    'status') VALUES (NULL ,  '".$openid."', '',  '".date("Y-m-d",time)."',  '0');";
    // var_dump($mysql_state1);
    $result = $db->execute($mysql_state1);
    $finally = '{
        "error": "noprize",
        "message": "",
        "prizelevel": "", 
        "success": ""
    }';
}
echo $finally;
  

經過上述5個煩瑣的步驟,中獎的實現過程就實現了。