import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        Main m = new Main();
        m.draw( int mode);
    }

    /**
     * 初始化奖池
     *
     * @return 奖池
     */
    public List<AwardItem> initAwardItem() {
        List<AwardItem> list = new ArrayList<>(); //此处查数据库 获取 库存>0 且 概率>0 的奖项
        list.add(new AwardItem(1, 1, 10000, "iphone"));
        list.add(new AwardItem(2, 3, 10000, "耳机"));
        list.add(new AwardItem(3, 5, 10000, "周卡"));
        list.add(new AwardItem(4, 10, 10000, "次卡"));
        list.add(new AwardItem(5, 20, 10000, "100元券"));
        list.add(new AwardItem(6, 30, 10000, "300元券"));
        list.add(new AwardItem(7, 50, 10000, "500元券"));

        // 若无结果,则提示活动结束
        if (list.size() == 0) {
            throw new RuntimeException("正在努力补货中......");
        }

        // 业务处理,过滤掉本次不能抽中的奖项(自行处理)

        return list;
    }

    /**
     * 抽奖
     *
     * @param mode 1单次抽 2连连抽
     */
    void draw(int mode) {
        String uid = null; // 当前登录用户
        // 1 检查 是否当前用户还有抽奖次数
        int drawCount = 0; // 此处查询数据库当前用户本次活动还剩余的抽奖次数
        if (drawCount < 1) {
            throw new RuntimeException("您的抽奖次数已经用完");
        }

        // 计算本次循环抽多少次
        // 1、如果是单次抽 循环1次
        int count = 1;
        // 2、如果是连连抽
        if (mode == 2) {
            count = 10; // 查询连连抽的次数
        }

        int usedCount = 0; //本轮抽奖所使用的次数
        while (usedCount < count) {
            usedCount++;
            List<AwardItem> list = initAwardItem();
            int awardItemId = doDraw(list);
            if (awardItemId == -1) {
                throw new RuntimeException("未中奖");
            }
            // 用当前奖品ID加redis锁(key='DRAW_ITEM_'+awardItemId),扣库存,剪掉用户本次抽奖次数
            try {
                // 处理中奖的数据
                processingTheWinningData(awardItemId, uid);
            } finally {
                // 此处解锁redis锁(key='DRAW_ITEM_'+awardItemId)
            }
        }
    }

    /**
     * 处理中奖数据
     *
     * @param awardItemID 奖项id
     * @param uid         用户id
     */
    void processingTheWinningData(int awardItemID, String uid) {
        // 插入中奖记录 扣减中奖奖品的库存 和 用户抽奖次数
        // 此处加事务
    }

    /**
     * 执行抽奖
     *
     * @param list 奖池
     * @return 中奖的奖项ID
     */
    int doDraw(List<AwardItem> list) {
        // 计算所有奖项权重总和
        int sumWeight = list.stream().mapToInt(AwardItem::getProbability).sum();

        // 此次中奖的随机数
        int randomNum = (int) (Math.random() * sumWeight);
        int min = 0;
        int max = 0;
        int selected = -1;

        // 遍历奖池,找出中奖的奖项
        for (int i = 0; i < list.size(); i++) {
            if (i > 0) {
                min = max;
            }
            max += list.get(i).getProbability();
            if (randomNum >= min && randomNum < max) {
                selected = i;
                break;
            }
        }

        return selected == -1 ? selected : list.get(selected).getId();
    }

    /**
     * 奖项
     */
    class AwardItem {
        int id;
        int probability; // 概率
        int stock; // 库存
        String name;

        public AwardItem(int id, int probability, int stock, String name) {
            this.id = id;
            this.probability = probability;
            this.stock = stock;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public int getProbability() {
            return probability;
        }

        public void setProbability(int probability) {
            this.probability = probability;
        }

        public int getStock() {
            return stock;
        }

        public void setStock(int stock) {
            this.stock = stock;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

}

 

 

原文地址:http://www.cnblogs.com/JiHC/p/16883686.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性