抽奖
由于最近项目需要做一个抽奖活动,于是实现了一个简单的抽奖算法,可以控制抽奖概率。提到抽奖,想必大家都见过玩过转轮抽奖吧,投一个币,然后转轮抽奖开始转动,当几个轮子的图片都是一样的时候就表示中奖了(当然还有大转盘的玩法,即投币后指针开始转动,转动停止后指针指向的那个位置就是判断中奖与否)。
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] ============================抽奖结束===============================