抽獎
由於最近項目需要做一個抽獎活動,於是實現了一個簡單的抽獎算法,可以控制抽獎概率。提到抽獎,想必大家都見過玩過轉輪抽獎吧,投一個幣,然后轉輪抽獎開始轉動,當幾個輪子的圖片都是一樣的時候就表示中獎了(當然還有大轉盤的玩法,即投幣后指針開始轉動,轉動停止后指針指向的那個位置就是判斷中獎與否)。
1、抽獎原理
假設現在有三個轉輪,每個轉輪上有(1~10)數字圖片。中獎情況如下:
每一次投幣之后,系統會返回3個數字,中獎情況可以自由設定:
* 三個數字都相同:中大獎
* 三個數字中有兩個相同:中小獎或不算中獎
* 三個數字都不同:沒中獎
2、概率控制
每一個數字都有相應的概率值:
數字 物品 概率
1 蘋果 5%
2 橘子 7%
3 香蕉 9%
4 葡萄 13%
5 荔枝 12%
6 柚子 14%
7 橙子 10%
8 柿子 11%
9 西瓜 8%
10 芒果 11%
每個轉輪轉動一次后會隨機(根據概率)選中一個數字。
每個轉輪上的數字的順序是隨機分配的。
第一個轉輪選取過程(第一個默認順序):
數字 物品 概率區段
1 蘋果 0~5%
2 橘子 5~12%
3 香蕉 12~21%
4 葡萄 21~34%
5 荔枝 34~46%
6 柚子 46~60%
7 橙子 60~70%
8 柿子 70~81%
9 西瓜 81~89%
10 芒果 89~100%
* 在1~100之間產生一個隨機數如:56
* 根據產生的隨機數 56 放到轉輪一中的概率區段去匹配,中獎數字是:6
第二個轉輪選取過程:
數字 物品 概率區段
2 橘子 0~7%
1 蘋果 7~12%
3 香蕉 12~21%
5 荔枝 21~33%
4 葡萄 33~46%
6 柚子 46~60%
7 橙子 60~70%
8 柿子 70~81%
10 芒果 81~92%
9 西瓜 92~100%
* 在1~100之間產生一個隨機數如:77
* 根據產生的隨機數77放到轉輪一中的概率區段去匹配,中獎數字是:8
第三個轉輪選取過程:
數字 物品 概率區段
4 葡萄 0~13%
10 芒果 13~24%
7 橙子 24~34%
1 蘋果 34~39%
9 西瓜 39~47%
6 柚子 47~61%
3 香蕉 61~70%
8 柿子 70~81%
5 荔枝 81~93%
2 橘子 93~100%
* 在1~100之間產生一個隨機數如:21
* 根據產生的隨機數21放到轉輪一中的概率區段去匹配,中獎數字是:10
最終的抽獎結果:6,8,10即:柚子,柿子,芒果,未中獎
3、代碼
* 獎品類
package com.lottery.model; /** * @author zyd * @date 2012-10-3 * @desc: * 抽獎獎品 */ public class Reward { /** * 獎品編號 */ public int index; /** * 獎品名稱 */ public String name; /** * 中獎概率 */ public int succPercent; public Reward(int index, String name, int succPercent) { super(); this.index = index; this.name = name; this.succPercent = succPercent; } @Override public String toString() { return "Reward [index=" + index + ", name=" + name + ", succPercent=" + succPercent + "]"; } }
* 抽獎算法類
package com.lottery.util; import java.util.ArrayList; import java.util.List; import java.util.Random; import com.lottery.model.Reward; /** * @author zyd * @date 2012-10-3 * @desc: * 抽獎主類 */ public class Lottery { public static List<Reward> randomList; /** * 獲取中獎編碼數組 * @param rlist * @param keyLength * @return */ public List<Reward> getKeys(List<Reward> rlist,int keyLength){ List<Reward> list = new ArrayList<Reward>(); for(int i=0;i<keyLength;i++){ list.add(getKey(rlist)); } return list; } /** * 獲取中獎編碼 * @param rlist * @return */ private Reward getKey(List<Reward> rlist) { //隨機列表 List<Reward> randomList = getRandomList(rlist); //根據隨機列表得到的概率區段 List<Integer> percentSteps = getPercentSteps(rlist); //概率區段的最大值 int maxPercentStep = percentSteps.get(percentSteps.size()-1); //在概率區段范圍內取一個隨機數 int randomStep = new Random().nextInt(maxPercentStep); //中間元素的下標 int keyIndex = 0; int begin = 0; int end = 0; for(int i=0;i<percentSteps.size();i++){ if(i == 0){ begin = 0; }else{ begin = percentSteps.get(i-1); } end = percentSteps.get(i); //判斷隨機數值是否在當前區段范圍內 if(randomStep>begin && randomStep<=end){ keyIndex = i; break; } } return randomList.get(keyIndex); } /** * 獲取概率區段[如:10,15,25,30,40,60,75,80,90,95,100] * @param rlist * @return */ private List<Integer> getPercentSteps(List<Reward> rlist) { List<Integer> percentSteps = new ArrayList<Integer>(); int percent = 0; for(Reward r: rlist){ percent += r.succPercent; percentSteps.add(percent); } return percentSteps; } /** * 獲取隨機列表 * @param rlist * @return */ private List<Reward> getRandomList(List<Reward> rlist){ List<Reward> oldList = new ArrayList<Reward>(rlist); List<Reward> newList = new ArrayList<Reward>(); //隨機排序的老序列中元素的下標 int randomIndex = 0; //隨機排序下標的取值范圍 int randomLength = 0; for(int i=0;i<rlist.size();i++){ //指向下標范圍 randomLength = oldList.size()-1; //取值范圍元素的個數為多個時,從中隨機選取一個元素的下標 if(randomLength != 0){ randomIndex = new Random().nextInt(randomLength); //取值范圍元素的個數為一個時,直接返回該元素的下標 }else{ randomIndex = 0; } //在新的序列當中添加元素,同時刪除元素取值范圍中的randomIndex下標所對應的元素 newList.add(oldList.remove(randomIndex)); } return newList; } }
* 測試類
package com.lottery.test; import java.util.ArrayList; import java.util.List; import com.lottery.model.Reward; import com.lottery.util.Lottery; /** * @author zyd * @date 2012-10-3 * @desc: * 測試 */ public class Test { public static void main(String[] args){ List<Reward> rlist = initRewards(); Lottery lottery = new Lottery(); List<Reward> rewards = null; for(int i=0;i<1000;i++){ rewards = lottery.getKeys(rlist, 3); if(isWinner(rewards)){ System.out.println("============================抽獎開始 第"+i+"次 ==============================="); for(Reward r:rewards){ System.out.println(r); } System.out.println("============================抽獎結束==============================="); } } } public static boolean isWinner(List<Reward> list){ boolean isWinner = false; for(int i=0;i<list.size();i++){ for(int j=i+1;j<list.size();j++){ if(list.get(i).index != list.get(j).index){ return false; }else{ isWinner =true; } } } return isWinner; } public static List<Reward> initRewards(){ List<Reward> rlist = new ArrayList<Reward>(); rlist.add(new Reward(1, "香蕉", 5)); rlist.add(new Reward(2, "蘋果", 15)); rlist.add(new Reward(3, "橘子", 5)); rlist.add(new Reward(4, "葡萄", 15)); rlist.add(new Reward(5, "荔枝", 5)); rlist.add(new Reward(6, "西瓜", 5)); rlist.add(new Reward(7, "柚子", 20)); rlist.add(new Reward(8, "橙子", 10)); rlist.add(new Reward(9, "柿子", 5)); rlist.add(new Reward(10, "芒果", 15)); return rlist; } } * 測試輸出 ============================抽獎開始 第82次 =============================== Reward [index=1, name=香蕉, succPercent=5] Reward [index=1, name=香蕉, succPercent=5] Reward [index=1, name=香蕉, succPercent=5] ============================抽獎結束=============================== ============================抽獎開始 第115次 =============================== Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] ============================抽獎結束=============================== ============================抽獎開始 第510次 =============================== Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] ============================抽獎結束=============================== ============================抽獎開始 第542次 =============================== Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] ============================抽獎結束=============================== ============================抽獎開始 第584次 =============================== Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] Reward [index=9, name=柿子, succPercent=5] ============================抽獎結束=============================== ============================抽獎開始 第706次 =============================== Reward [index=5, name=荔枝, succPercent=5] Reward [index=5, name=荔枝, succPercent=5] Reward [index=5, name=荔枝, succPercent=5] ============================抽獎結束===============================