Skip to content

Instantly share code, notes, and snippets.

@zhugw
Created February 23, 2016 06:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zhugw/efd33b66a58824a86136 to your computer and use it in GitHub Desktop.
Save zhugw/efd33b66a58824a86136 to your computer and use it in GitHub Desktop.
转盘抽奖算法demo
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