簡單的抽獎系統實現
阿新 • • 發佈:2018-12-12
需求|原因
朋友突然給我一個抽獎的一個需求,讓我幫他他分析下,需求大致是這樣的。
1.發起一個抽象活動,選擇幾種商品作為這個活動的獎品。
2.商品的資訊都已經設定好,名稱、數量、單個獎品中獎率(儲存整數,以萬計。比如存的1,中獎率就是萬分之一。)
3.實現使用者抽獎,並給出是否中獎,如果中獎,什麼獎品?
思路分析
例如有3種獎品 iphone(數量:2,中獎率:1),手電(數量:2,中獎率:20),水筆(數量:3,中獎率:20)
注:中獎率是依照萬計算的。就是除以10000。
採用隨機數的方式來計算,但怎麼產生隨機數,才能符合這個概率問題呢。
直接看程式碼吧
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
class Prize{
String id;
String name;
//獎品個數
int sum;
//中獎率
int probability;
//中獎號碼
String winningStr;
public String getId () {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this .sum = sum;
}
public int getProbability() {
return probability;
}
public void setProbability(int probability) {
this.probability = probability;
}
public String getWinningStr() {
return winningStr;
}
public void setWinningStr(String winningStr) {
this.winningStr = winningStr;
}
}
/**
* 抽獎號碼類,此類只產生中獎號碼,
* 思路:在釋出一個抽獎活動是,為每個獎品產生中獎號碼;
* 當用戶來抽獎時,你需要先自己判斷獎品數量>0和狀態是否存在,如果狀態不存在或者數量=0;就直接返回謝謝,未抽中。
* 如果獎品數量>0;就產生一個隨機數(main方法裡有例子怎麼算出隨機數的)。然後比較是否中獎了。中獎之後再去查中了什麼獎,否則如果不中獎返回謝謝。
*
* @ClassName: PrizeRandom
* @Description:TODO(這裡用一句話描述這個類的作用)
* @author LiYuanyuan
* @date 2017年12月7日 下午1:19:30
*/
public class PrizeRandom {
//預設最大的概率基數
private static final int DEFAULT_MAX_RATE_NUM=10000;
/**
* 獲取獎品的對應的中獎號碼
* @Title: getWinningCode
* @Description: TODO(這裡用一句話描述這個方法的作用)
* @param: @param prizes 獎品物件集合
* @param: @return
* @author LiYuanyuan
* @date 2017年12月7日 上午10:24:06
* @return: Map<String,int[]>
* @throws
*/
public static List<Integer> getAllWinningCode(List<Prize> prizes,int maxRandom,int randomCount){
//儲存生成的中獎號碼
List<Integer> winningNums = new ArrayList<Integer>();
//產生隨機數
for(int i=0;i<randomCount;i++){
winningNums.add(getWinningNum(winningNums,maxRandom));
}
return winningNums;
}
public static Map<String,List<Integer>> getPrizeWinNums(List<Prize> prizes,List<Integer> winningNums, int prizeLSM){
Map<String,List<Integer>> prizesWinNumMap = new HashMap<String,List<Integer>>();
//生成中獎號碼的個數
int rateSum = winningNums.size();
//遍歷獎品,分配中獎數
int index=0;
for(Prize prize:prizes){
//獎品的中獎號碼個數
int probabilitySum = prize.getProbability()*prizeLSM;
//儲存獎品分配的中獎數
List<Integer> prizeWinNums = new ArrayList<Integer>();
//從總的中獎號碼中隨機獲取索引下的value
int i=0;
for(;index<rateSum;index++){
//防止在抽取到相同的index,獲取相同的數字。所以
prizeWinNums.add(winningNums.get(index));
if(i==probabilitySum-1){
break;
}
i++;
}
index++;
prizesWinNumMap.put(prize.getName(),prizeWinNums);
}
return prizesWinNumMap;
}
/**
* 獲取一個獎品的中獎號碼
* @param winningNumList 儲存中獎號碼的List集合
* @param maxRandom 隨機數的最大取值範圍
* @return 中獎號碼
*/
private static int getWinningNum(List<Integer> winningNumList, int maxRandom){
//
int winningNum = getRandom(maxRandom);
if(winningNumList.contains(winningNum)){
winningNum = getWinningNum(winningNumList,maxRandom);
}
return winningNum;
}
/**
* 獲取一個小於max的隨機數
* @param max 隨機數的最大範圍 =所有獎品個數的最小公倍數*10000;
* @return int 隨機數
*/
public static int getRandom(int max){
double randomD = Math.random()*max+1;
String randomStr = String.valueOf(randomD);
randomStr = randomStr.substring(0, randomStr.lastIndexOf("."));
return Integer.parseInt(randomStr);
}
/**
* 求最小公倍數
* @Title: getLSM
* @Description: TODO(這裡用一句話描述這個方法的作用)
* @param: @param rates 參與活動的所有獎品個數List集合
* @param: @return
* @author LiYuanyuan
* @date 2017年12月7日 上午10:19:38
* @return: int
* @throws
*/
public static int getLSM(List<Integer> rates){
int lsmNum = -1;
int max = getMaxByList(rates);
for(int i=max;;i++){
boolean isExsitLSM = true;
for(int num : rates){
if(i%num!=0){
isExsitLSM = false;
break;
}
}
if(isExsitLSM){
lsmNum = i;
break;
}
}
return lsmNum;
}
/**
* 獲取List中的最大值
* @Title: getMaxByList
* @Description: TODO(這裡用一句話描述這個方法的作用)
* @param: @param rates
* @param: @return
* @author LiYuanyuan
* @date 2017年12月7日 上午10:19:19
* @return: int
* @throws
*/
private static int getMaxByList(List<Integer> rates){
Arrays.sort(rates.toArray());
return rates.get(rates.size()-1);
}
public static void main(String[] args) {
//初始化一個活動獎品
List<Prize> prizes = new ArrayList<Prize>();
Prize prize = new Prize();
prize.setId("1");
prize.setName("iphoneX");
prize.setSum(1);
prize.setProbability(20);
prizes.add(prize);
prize = new Prize();
prize.setId("2");
prize.setName("手電");
prize.setSum(2);
prize.setProbability(50);
prizes.add(prize);
prize = new Prize();
prize.setId("3");
prize.setName("水筆");
prize.setSum(2);
prize.setProbability(100);
prizes.add(prize);
//定義一個儲存所有參與抽獎活動A的所有獎品個數集合
List<Integer> list = new ArrayList<Integer>();
list.add(1);//iphoneX個數
list.add(2);//手電個數
list.add(2);//水筆個數
//求獎品個數的最小公倍數,利用最小公倍數,算出隨機數的最大範圍。
int prizeMinLSMLSM = getLSM(list);
int maxRandom = prizeMinLSMLSM*DEFAULT_MAX_RATE_NUM;
//求出,每種獎品在最小公倍數作為分母基數時,分子的大小是多少,也就是佔用的概率是多少
int rateSum = 0;
for(Prize prizee:prizes){
rateSum+=(prizee.getProbability()*prizeMinLSMLSM);
}
//1.建立一個抽獎活動A時,生成活動獎品號碼
//獲取所有的中獎號碼
List<Integer> allWinningCodes = getAllWinningCode(prizes,maxRandom,rateSum);
//分配中獎號碼
Map<String,List<Integer>> prizesWinNumMap = getPrizeWinNums(prizes, allWinningCodes, prizeMinLSMLSM);
System.out.println("本次抽獎活動A的所有獎品幸運號碼:");
System.out.println(JSON.toJSON(prizesWinNumMap));
//2.使用者抽獎的時候
boolean isLuck = false;//是否中獎
int i = 1;//模仿許多使用者抽獎
int luckCount = 0;//中獎次數
while(!isLuck){
//產生一個隨機號碼
int luckNum = getRandom(maxRandom);
System.out.println("使用者 李園園第"+i+"次抽中的號碼為:"+luckNum);
//隨機號碼是否存在於獎品號碼裡
if(allWinningCodes.contains(luckNum)){
//遍歷獎品的中獎號碼,查詢中獎了那個獎品
for(String key:prizesWinNumMap.keySet()){
if(prizesWinNumMap.get(key).contains(luckNum)){
//遍歷獎品
for(Prize prizee:prizes){
if(prizee.getName().equals(key)){
//判斷獎品數量
if(prizee.getSum()>0){
prizee.setSum(prizee.getSum()-1);
System.out.println("恭喜中獎了:"+key+ " 剩餘獎品數:"+prizee.getSum());
luckCount++;
}else{
System.out.println("---獎品"+key+"派發完了,謝謝惠顧");
isLuck=true;
}
}
}
}
}
}else{
System.out.println("謝謝惠顧");
}
i++;
}
}
}