大轉盤抽獎邏輯--區間

部分原文自: https://blog.csdn.net/larva_s/article/details/87532195java

1. 抽獎需求

​ 根據配置獎品的機率去抽取獎品,其中總機率不必定是 1 ,此時是按照權重去抽取獎品的。數組

2. 實現

2.1 思路:區間

區間 [0, 10):獎品1 [10, 65):謝謝參與 [65, 98):獎品2 [98, 100):獎品3
機率 獎品1機率:10 謝謝參與機率:55 獎品2機率:33 獎品3機率:2
  • ​​​​​​ 根據獎品機率構造一個區間
  • 經過隨機數Rondom的API獲取隨機值 [0, 最大值)
  • 根據隨機值匹配到對應區間的獎品,便是抽取到的獎品
/**
 * 獎品類
 */
@Data
@AllArgsConstructor
public class Award {

    private Integer id;
    private String name;
    private Integer weight;
}

/**
 * 通用抽獎接口
 * @param <T>
 */
public interface ILotteryService<T> {

    T draw(List<T> awardList) throws DrawException;
}

/**
 * 區間實現抽獎機率
 */
public class IntervalLotteryService implements ILotteryService<Award>{

    /**
     * 經過區間來實現機率分配  
     * 獎品1 [0,10)
     * 獎品2 [10,90)
     * 獎品3 [90,100)
     * 獎品4 [100,980)
     * @param awardList
     * @return
     */
    @Override
    public Award draw(List<Award> awardList) throws DrawException {
        int listSize = awardList.size();
        if (awardList == null || listSize < 1){
            return null;
        }
        
        // 遍歷list,計算區間最右值,封裝到 int數組中 中
        int[] interval = new int[listSize];
        for (int i = 0; i < listSize; i++) {
            Award award = awardList.get(i);
            Integer weight = award.getWeight();
            
            if (i == 0){
                interval[0] = weight;
            }else {
                Integer lastAwardWeight = interval[i - 1];
                // 區間最右是上一個 區間最右 + 本身的權重
                interval[i] = weight + lastAwardWeight;
            }
        }
        
        // random int 獲取隨機到的值
        int maxInterval = interval[listSize - 1];
        Random random = new Random();
        int ranVal = random.nextInt(maxInterval);
        
        // 遍歷 int數組 ,找到隨機值是位於哪一個區間,獲取award,返回該award
        for (int i = 0; i < interval.length; i++) {
            if (ranVal >= interval[i] && ranVal < interval[i + 1]){
                return awardList.get(i + 1);
            }else if (ranVal < interval[0]){
                // 第一個區間以內
                return awardList.get(0);
            }
        }
        throw new DrawException("抽獎異常");
    }

    // 測試
    public static void main(String args[]){
        IntervalLotteryService lotteryService = new IntervalLotteryService();
        List<Award> awardList = Lists.newArrayList(
                new Award(1,"0.088 機率獎品", 88),
                new Award(2,"0.333 機率獎品", 333),
                new Award(3,"0.155 機率獎品", 155),
                new Award(4,"0.424 機率獎品", 424)
        );

        try {
            Map<String, Integer> statMap = Maps.newHashMap();
            for (int i = 0; i < 1000; i++) {
                Award drawAward = lotteryService.draw(awardList);
                String awardName = drawAward.getName();
                if (statMap.containsKey(awardName)){
                    Integer count = statMap.get(awardName);
                    statMap.put(awardName, count + 1);
                }else {
                    statMap.put(awardName, 1);
                }
            }

            statMap.forEach((k, v) -> System.out.println(k + " : " + v));

            /*
            0.088 機率獎品 : 94
            0.155 機率獎品 : 152
            0.333 機率獎品 : 320
            0.424 機率獎品 : 434
            */
        } catch (DrawException e) {
            System.out.println("拋異常");
        }
    }
}

3. 問題

3.1 抽獎成功,但發獎失敗,如何處理?

​ 發獎失敗,包括拋異常等狀況,都設爲抽不到獎品,兜底處理便可。dom

3.2 某一個獎品庫存消耗完時,是如何處理的?

​ 仍然可被抽中,只不過扣庫存時發現庫存已消耗完則返回謝謝參與ide

相關文章
相關標籤/搜索