網上有個爛大街的演算法,具體請看連結
大概原理是:
1,產生一個隨機數;
2,循環對比第N個獎品的機率;
3,決定獎品;
如果按照這個演算法,主觀上是抽一次獎,但客觀上,把每個獎品都循環抽了一遍,其實是抽了N次,不知道我的理解對不對。
下面是我寫的演算法,具體原理是:
1,先確定隨機數(幸運號碼)的範圍;
2,確定每個獎品的號碼區間,確保只抽一次獎能對應到某個獎品;
3,根據範圍產生幸運號碼;
4,根據範圍決定獎品;
請教各路大神,有沒有更優的算法或思路?
<code>$goods = [ 0 => [ 'id' => 1, 'name' => '苹果电脑', 'odds' => '0.01' //概率 ], 1 => [ 'id' => 2, 'name' => 'Iphone', 'odds' => '10.99' ], 2 => [ 'id' => 3, 'name' => '200元红包', 'odds' => '19' ], 3 => [ 'id' => 4, 'name' => '安慰奖', 'odds' => '30' ], 4 => [ 'id' => 5, 'name' => '什么都没抽到', 'odds' => '40' ], ]; $baseOdds = 100; //抽奖概率基数,默认100% $maxBase = 1; //抽奖概率基数倍数,默认1,如果奖品概率有小数位,该倍数为10的小数位数平方,具体看下面 foreach ($goods as $good) { $decimal = strpbrk($good['odds'], '.'); //获取小数点后面的内容 if ($decimal !== false) { $decimalCount = strlen($decimal) - 1;//获取小数点后面的位数 $newMaxBase = pow(10, $decimalCount); //例如概率如果是0.01,则全局的抽奖概率基数需要以10的平方倍数上涨 if ($newMaxBase > $maxBase) { $maxBase = $newMaxBase; //更新基数倍数 } } } $baseOdds = $maxBase ? $baseOdds * $maxBase : $baseOdds; //更新概率基数 $start = 1; $end = 0; $luckyCompare = $tickets = []; //为每个奖品生成一个幸运数区间 foreach ($goods as $key => $good) { $newOdds = $good['odds'] * $maxBase; $end = $end + $newOdds; $luckyCompare[$good['id']] = [$start, $end]; $tick = mt_rand($start, $end); $start = $start + $newOdds; $tickets[$good['id']] = $tick; } $luckyNumber = mt_rand(1, $baseOdds); var_dump($luckyNumber); var_dump($luckyCompare); foreach ($luckyCompare as $goodId => $compare) { if ($compare[0] <= $luckyNumber && $compare[1] >= $luckyNumber) { $luckyGood = $goodId; //最终的奖品 break; } } var_dump($luckyGood);</code>
網路上有個爛大街的演算法,具體請看連結
大概原理是:
1,產生一個隨機數;
2,循環對比第N個獎品的機率;
3,決定獎品;
如果依照這個演算法,主觀上是抽一次獎,但客觀上,把每個獎品都循環抽了一遍,其實是抽了N次,不知道我的理解對不對。
下面是我寫的演算法,具體原理是:
1,先確定隨機數(幸運號碼)的範圍;
2,確定每個獎品的號碼區間,確保只抽一次獎能對應到某個獎品;
3,根據範圍產生幸運號碼;
4,根據範圍決定獎品;
請教各路大神,有沒有更優的算法或思路?
<code>$goods = [ 0 => [ 'id' => 1, 'name' => '苹果电脑', 'odds' => '0.01' //概率 ], 1 => [ 'id' => 2, 'name' => 'Iphone', 'odds' => '10.99' ], 2 => [ 'id' => 3, 'name' => '200元红包', 'odds' => '19' ], 3 => [ 'id' => 4, 'name' => '安慰奖', 'odds' => '30' ], 4 => [ 'id' => 5, 'name' => '什么都没抽到', 'odds' => '40' ], ]; $baseOdds = 100; //抽奖概率基数,默认100% $maxBase = 1; //抽奖概率基数倍数,默认1,如果奖品概率有小数位,该倍数为10的小数位数平方,具体看下面 foreach ($goods as $good) { $decimal = strpbrk($good['odds'], '.'); //获取小数点后面的内容 if ($decimal !== false) { $decimalCount = strlen($decimal) - 1;//获取小数点后面的位数 $newMaxBase = pow(10, $decimalCount); //例如概率如果是0.01,则全局的抽奖概率基数需要以10的平方倍数上涨 if ($newMaxBase > $maxBase) { $maxBase = $newMaxBase; //更新基数倍数 } } } $baseOdds = $maxBase ? $baseOdds * $maxBase : $baseOdds; //更新概率基数 $start = 1; $end = 0; $luckyCompare = $tickets = []; //为每个奖品生成一个幸运数区间 foreach ($goods as $key => $good) { $newOdds = $good['odds'] * $maxBase; $end = $end + $newOdds; $luckyCompare[$good['id']] = [$start, $end]; $tick = mt_rand($start, $end); $start = $start + $newOdds; $tickets[$good['id']] = $tick; } $luckyNumber = mt_rand(1, $baseOdds); var_dump($luckyNumber); var_dump($luckyCompare); foreach ($luckyCompare as $goodId => $compare) { if ($compare[0] <= $luckyNumber && $compare[1] >= $luckyNumber) { $luckyGood = $goodId; //最终的奖品 break; } } var_dump($luckyGood);</code>
只能說 呵呵 了。抽獎的演算法的決定權不在程式設計師,這才是重點。
通常抽獎活動是由行銷部門發起、策劃、評估、運作的,程式設計師的角色只是做實現而已。該行銷行為策劃案應該包含獎品設定、活動時間、推廣策略、冷/熱場時間、獎品投放批次等等東西,簡單來說,這是行銷部門導演的一場戲,開發人員是現場指揮,程式負責調度,抽獎者就是演員了。
所以,抽獎演算法根本沒用,只要你放出去的獎品不要超出獎金池就行了,別的都不重要。
可能有人會說了,那怎麼體現抽獎的公平公正?其實幾乎不需要考慮這個問題,因為程式寫好之後是自動執行的,這個時候對所有參與者來說已經是一個同等環境了,不存在不公平的問題。
典型的偽演算法如下:
雨露獎:消費抵扣券5元,中獎率100%;
水坑獎:消費抵扣券10元,中獎率50%;
奔雷獎:消費抵扣券100元,中獎率5%;
雷劈獎:iPad一個,共6個。
活動時間12小時,彩券無上限。
演算法:抽獎時間戳微秒部分是20的倍數=奔雷,是單數=水坑,否則為雨露。每兩個小時為一個週期,下一週期開始時的第一個抽獎人獲得上一個週期的雷劈獎,整個活動在持續時間截止後收到第一個彩票則完全結束。
有不公平的問題嗎?所以,呵呵。最後還是要根據需求寫程式。
<code>$arr = array(10000,1000,100,10,1); for ($i=0;$i<5;$i++){ if(rand(1,$arr[$i])==1){ echo "恭喜你中了".$i."奖";//这个描述自己写 } }</code>