Created
February 23, 2016 06:03
-
-
Save zhugw/efd33b66a58824a86136 to your computer and use it in GitHub Desktop.
转盘抽奖算法demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.Optional; | |
import java.util.Random; | |
import java.util.concurrent.ConcurrentHashMap; | |
import java.util.stream.Collectors; | |
/** | |
* <pre> | |
* 转盘抽奖算法demo | |
* 转盘抽奖一共有6档内容:现金红包1元、2元、3元、5元、iphone6s、未中奖 | |
* 活动10天 | |
* 1元 2元 3元 5元 iphone6s | |
* 50000 10000 5000 1000 2 | |
* | |
* 日活用户5万 每个用户每天可以抽3次 | |
* 目的: | |
* 尽量保证在10天内平均随机的抽完这些奖品 | |
* | |
* 假如 | |
* </pre> | |
* | |
* @author 断木 | |
* @createTime: Feb 23, 2016 10:07:11 AM | |
* | |
*/ | |
public class WheelDrawDemo { | |
public static void main(String[] args) { | |
Map<String, Integer> awardTotalCountMap = new ConcurrentHashMap<>(); // 奖品 <--> 奖品总数目 | |
awardTotalCountMap.put("1", 50000); | |
awardTotalCountMap.put("2", 10000); | |
awardTotalCountMap.put("3", 5000); | |
awardTotalCountMap.put("5", 1000); | |
awardTotalCountMap.put("iphone", 2); | |
Map<String, Integer> awardCountMap = new ConcurrentHashMap<>(awardTotalCountMap); // 奖品 <--> 实时剩余数目 | |
int userNum = 50000; // 日活用户数 | |
int drawNum = userNum * 3; // 每天抽奖次数 = 日活数*抽奖次数 | |
int duration = 10; // 活动天数 | |
Map<String, Integer> winCountMap = new ConcurrentHashMap<>(); // 实际中奖计数 | |
for (int i = 0; i < duration; i++) { // 模拟10天 | |
Map<String, Integer> dailyWinCountMap = new ConcurrentHashMap<>(); // 每天实际中奖计数 | |
for (int j = 0; j < drawNum; j++) { // 模拟每次抽奖 | |
// 先选中是哪种奖品 | |
String choosedAward = null; | |
int totalCount = (int) awardCountMap.values().stream().collect(Collectors.summarizingInt(c -> c)) | |
.getSum(); // 当前实时总数 | |
int randNum = new Random().nextInt(totalCount); | |
int prev = 0; | |
for(Entry<String,Integer> e : awardCountMap.entrySet() ){ | |
if(randNum>=prev && randNum<prev+e.getValue()){ | |
choosedAward = e.getKey(); //选中该种奖品 | |
break; | |
} | |
prev = prev+e.getValue(); | |
} | |
// 确定是否中奖 中奖概率=奖品总数/活动天数/每日抽奖次数 | |
double prob = 1.0*awardTotalCountMap.get(choosedAward)/duration/drawNum*100000; | |
int probNum = Double.valueOf(prob).intValue()+1; | |
if(new Random().nextInt(100000)<=probNum){ //表示中奖 | |
winCountMap.compute(choosedAward, (k,v)->v==null?1:v+1); | |
dailyWinCountMap.compute(choosedAward, (k,v)->v==null?1:v+1); | |
awardCountMap.compute(choosedAward, (k,v)->v-1); //已中奖 减少库存数 | |
} | |
} | |
System.out.println(dailyWinCountMap); //每日各奖品中奖计数 | |
} | |
// 活动结束 | |
System.out.println(winCountMap); // 活动结束后各奖品中奖计数 | |
System.out.println(awardCountMap); //各奖品剩余数 | |
} | |
} | |
output | |
{1=3883, 2=145, 3=42, 5=3} | |
{1=3664, 2=153, 3=44, 5=1} | |
{1=3757, 2=186, 3=46} | |
{1=3469, 2=176, 3=45, 5=1} | |
{1=3365, 2=187, 3=52, 5=2} | |
{1=3392, 2=181, 3=52, 5=3} | |
{1=3281, 2=206, 3=53, 5=1} | |
{1=3144, 2=199, 3=69, 5=4} | |
{1=3040, 2=240, 3=59, 5=4} | |
{1=2856, 2=310, 3=67, 5=3} | |
{1=33851, 2=1983, 3=529, 5=22} | |
{1=16149, 2=8017, 3=4471, 5=978, iphone=2} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment