【Java算法】Java抽奖算法,适用于各种抽奖

算法原理:
把0到1的区间分块,而分块的依据就是物品占整个的比重,再根据随机数种子来产生0-1中间的某个数,来判断这个数是落在哪个区间上,而对应的就是抽到了那个物品。随机数理论上是概率均等的,产生的每个数理论上也应该概率均等,那么相应的区间所含数的多少就体现了抽奖物品概率的不同。如果概率是0的话,这个区间也就是0,就不会落在这个区间上。最终返回会返回对应商品信息。

奖品类

/**
 * 奖品类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Prize {
    
    

    /**
     * 奖品序号
     */
    private Integer prizeIndex;
    /**
     * 奖品id
     */
    private Long prizeId;
    /**
     * 奖品名称
     */
    private String prizeName;
    /**
     * 库存
     */
    private Integer stock;
    /**
     * 概率
     */
    private double probability;
}

抽奖算法工具类

/**
 * 抽奖算法工具类
 *
 * @author xiegege
 * @date 2021/1/7 17:02
 */
public class LotteryUtil {
    
    

    /**
     * 抽奖算法
     *
     * @param originRates 原始的概率列表,保证顺序和实际物品对应
     * @return 物品的索引
     */
    public static int lottery(List<Double> originRates) {
    
    
        // 计算总概率,这样可以保证不一定总概率是1
        double sumRate = 0d;
        for (double rate : originRates) {
    
    
            sumRate += rate;
        }
        // 计算每个物品在总概率的基础下的概率情况
        List<Double> sortOriginRates = new ArrayList<>();
        double tempSumRate = 0d;
        for (double rate : originRates) {
    
    
            tempSumRate += rate;
            sortOriginRates.add(tempSumRate / sumRate);
        }
        // 根据区块值来获取抽取到的物品索引
        double nextDouble = Math.random();
        sortOriginRates.add(nextDouble);
        Collections.sort(sortOriginRates);
        return sortOriginRates.indexOf(nextDouble);
    }
}

调用

/**
 * 不同概率抽奖
 *
 * @author xiegege
 * @date 2021/1/5 17:02
 */
public class LotteryTest {
    
    
    public static void main(String[] args) {
    
    

        List<Prize> prizes = new ArrayList<>();
        // 奖品序号==奖品id==奖品名称==库存==概率
        prizes.add(new Prize(2580, 11L, "再来一次", -1, 0.2d));
        prizes.add(new Prize(1234, 22L, "本站VIP一年", 20, 0.1d));
        prizes.add(new Prize(5678, 33L, "谢谢参与", -1, 0.4d));
        prizes.add(new Prize(1230, 55L, "50金币", 0, 0.3d));
        prizes.add(new Prize(3726, 66L, "iphone12", 0, 0d));
        prizes.add(new Prize(3737, 77L, "ipad Air8", 0, -0.1d));
        prizes.add(new Prize(2568, 88L, "100元手机话费", 5, 0.008d));

        if (CollectionUtils.isEmpty(prizes)) {
    
    
            System.out.println("无奖品数据");
            return;
        }

        List<Double> originRates = new ArrayList<>();
        for (Prize prize : prizes) {
    
    
            double probability = prize.getProbability();
            int stock = prize.getStock();
            // 概率为负数或者库存为0的数据,概率设置为0
            if (probability < 0 || stock == 0) {
    
    
                probability = 0;
            }
            originRates.add(probability);
        }

        // 测试1000次的抽奖调用
        for (int i = 0; i < 1000; i++) {
    
    
            int originIndex = LotteryUtil.lottery(originRates);
            Prize prize = prizes.get(originIndex);
            if (prize.getProbability() <= 0 || prize.getStock() == 0) {
    
    
                // 多一步判断
                System.out.println("库存不足或概率小于等于0======谢谢参与======");
            } else {
    
    
                System.out.println(prize);
            }
        }
    }
}

当库存为0或者概率小于等于0时抽不到该奖品。这里的测试代码没有做库存扣减,实际开发中应做库存扣减操作,还有一些用户能抽几次,什么条件能抽,这些逻辑可以根据自己的业务需求去增加。

总结

如果觉得不错,可以点赞+收藏或者关注下博主。感谢阅读!

猜你喜欢

转载自blog.csdn.net/weixin_42825651/article/details/112323460