/* * 不一樣機率的抽獎原理就是把0到*(比重總數)的區間分塊 * 分塊的依據是物品佔整個的比重,再根據隨機數種子來產生0-* 中的某個數 * 判斷這個數是落在哪一個區間上,區間對應的就是抽到的那個物品。 * 隨機數理論上是機率均等的,那麼相應的區間所含數的多少就體現了抽獎物品機率的不一樣。 */ /** * 抽獎方法 * @return [array] [抽獎狀況] */ public function doDraw() { // 獎品數組 $proArr = array( // id => 獎品等級, name => 獎品名稱, v => 獎品權重 array('id'=>1,'name'=>'超級獎品','v'=>0), array('id'=>2,'name'=>'特等獎','v'=>1), array('id'=>3,'name'=>'一等獎','v'=>5), array('id'=>4,'name'=>'二等獎','v'=>10), array('id'=>5,'name'=>'三等獎','v'=>12), array('id'=>6,'name'=>'四等獎','v'=>22), array('id'=>7,'name'=>'五等獎','v'=>50), array('id'=>8,'name'=>'六等獎','v'=>100), array('id'=>9,'name'=>'七等獎','v'=>200), array('id'=>10,'name'=>'沒中獎','v'=>500), ); // 獎品等級獎品權重數組 $arr = []; foreach ($proArr as $key => $val) { $arr[$val['id']] = $val['v']; } // 中獎 id $rid = $this->get_rand($arr); /**模擬抽獎測試**/ /* $i = 0; while ( $i < 10000) { $rid = $this->get_rand($arr); $res[] = $rid; $i++; } // 統計獎品出現次數 $result = array_count_values($res); asort($result); foreach ($result as $id => $times) { foreach ($proArr as $gifts) { if($id == $gifts['id']){ $response[$gifts['name']] = $times; } } } dump($response); die;*/ $result = []; // 中獎禮品 $result['yes'] = $proArr[$rid-1]['name']; // 從原獎品數組中剔除已經中獎禮品 unset($proArr[$rid-1]); // 打亂數組排序 shuffle($proArr); for ($i=0; $i < count($proArr); $i++) { $result['no'][] = $proArr[$i]['name']; } // foreach ($proArr as $k => $v) { // // 沒中獎禮品 // $result['no'][] = $v['name']; // } dump($result); } /** * 抽獎算法 * @param array $proArr 獎品等級獎品權重數組 * @return [int] 中獎獎品等級 */ public function get_rand($proArr = array()) { if(empty($proArr)) die; $rid = ''; // 機率數組的總權重 $proSum = array_sum($proArr); // 機率數組循環 foreach ($proArr as $k => $proCur) { // 從 1 到機率總數中任意取值 $randNum = mt_rand(1, $proSum); // 判斷隨機數是否在機率權重中 if ($randNum <= $proCur) { // 取出獎品 id $rid = $k; break; } else { // 若是隨機數不在機率權限中,則不斷縮小總權重,直到從獎品數組中取出一個獎品 $proSum -= $proCur; } } unset($proArr); return $rid; }
測試方法:php
public function test(){ $proArr = array( array('id'=>1,'name'=>'特等獎','v'=>1), array('id'=>2,'name'=>'一等獎','v'=>5), array('id'=>3,'name'=>'二等獎','v'=>10), array('id'=>4,'name'=>'三等獎','v'=>12), array('id'=>5,'name'=>'四等獎','v'=>22), array('id'=>6,'name'=>'沒中獎','v'=>500) ); $result = array(); foreach ($proArr as $key => $val) { $arr[$key] = $val['v']; } // 機率數組的總權重 $proSum = array_sum($arr); // 機率數組循環 foreach ($arr as $k => $v) { // 從 1 到機率總數中任意取值 $randNum = mt_rand(1, $proSum); $aa[$k] = $randNum . '+' . $v . '+' . $proSum; if ($randNum <= $v) { $result = $proArr[$k]; // 找到符合條件的值就跳出 foreach 循環 // dump($result); break; } else { $proSum = $proSum - $v; $bb[$k] = $randNum . '+' . $v . '+' . $proSum; } } dump($aa); dump($bb); // // dump($result); // // dump(__DIR__); // $path = __DIR__ . DS . 'log'; // if(!is_dir($path)){ // mkdir($path); // } // $fileName = $path . DS . 'log.txt'; // 建立文件和打開文件的函數都是 fopen // $cFile = fopen($fileName,'a+'); // $a = json_encode($aa) . "\r\n"; // $b = json_encode($bb) . "\r\n"; // fwrite($cFile,$a); // fwrite($cFile,$b); // fclose($cFile); // 讀文件 // $lines = file($fileName); // foreach ($lines as $key => $value) { // dump($value.'555555555'); // } // dump($lines); }
如下代碼也是意義程度上相同的代碼,可是這種算法用的很少算法
function get_rand($proArr) { $result = array(); foreach ($proArr as $key => $val) { $arr[$key] = $val['v']; } $proSum = array_sum($arr); // 計算總權重 $randNum = mt_rand(1, $proSum); $d1 = 0; $d2 = 0; for ($i=0; $i < count($arr); $i++) { $d2 += $arr[$i]; if($i==0) { $d1 = 0; } else { $d1 += $arr[$i-1]; } if($randNum >= $d1 && $randNum <= $d2) { $result = $proArr[$i]; } } unset ($arr); return $result; }
// 開啓百分百中獎模式json
<?php /** * $prize_arr 參與抽獎人員數據 * id: 通常是成員ID * name 姓名 * v 得獎機率 ***/ $prize_arr = array( '0' => array('id'=>1,'name'=>'小王','v'=>1), '1' => array('id'=>2,'name'=>'小李','v'=>5), '2' => array('id'=>3,'name'=>'小張','v'=>10), '3' => array('id'=>4,'name'=>'小二','v'=>12), '4' => array('id'=>5,'name'=>'小菜','v'=>22), '6' => array('id'=>6,'name'=>'小范','v'=>50), '7' => array('id'=>7,'name'=>'小范01','v'=>50), '8' => array('id'=>8,'name'=>'小范02','v'=>100), '9' => array('id'=>9,'name'=>'小范03','v'=>50), '10' => array('id'=>10,'name'=>'小范04','v'=>50), '11' => array('id'=>11,'name'=>'小范05','v'=>50), '12' => array('id'=>12,'name'=>'小范06','v'=>50), '13' => array('id'=>13,'name'=>'小范07','v'=>50), '14' => array('id'=>14,'name'=>'小范08','v'=>50), '15' => array('id'=>15,'name'=>'小范09','v'=>100), '16' => array('id'=>16,'name'=>'小范10','v'=>100), ); foreach ($prize_arr as $key => $val) { $arr[$key] = $val['v']; } $total_num = '8'; //設定得中獎人數量 $temp_rest=array(); for($i=0;$i<$total_num;$i++) { $rid = get_rand($arr,true); //根據機率獲取人員ID $temp_rest[]= $prize_arr[$rid]; //中獎項 unset($prize_arr[$rid]); unset($arr[$rid]); } print_r($temp_rest);//得出結果 /**** * 得出當前中獎人 * $is_status是否開啓機率爲100必中: 默認不開啓 ***/ function get_rand($proArr,$is_status = false) { $result = ''; if($is_status){ $rest = get_100($proArr); //調用獲取100命中 }else{ $rest =''; } if(empty($rest) || !isset($rest)){ //機率數組的總機率精度 $proSum = array_sum($proArr); //機率數組循環 foreach ($proArr as $key => $proCur) { $randNum = mt_rand(1, $proSum); if ($randNum <= $proCur) { $result = $key; break; } else { $proSum -= $proCur; } } }else{ $result = $rest; } unset ($proArr); return $result; } function get_100($arr_mast){ $result = ''; foreach ($arr_mast as $key => $value_mast) { if($value_mast== 100){ $result = $key; break; } } unset ($arr_mast); return $result; }