代码如下

需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%。
累计砸第n次时必抽中x等奖以上的奖品。比如,累计砸第5次,则此次必中二等奖及以上的奖品。且配置的此次必中中奖概率不一样。有点绕。。。

/*** 金蛋抽奖* userId : 抽奖用户ID* consumeType : 抽奖消耗的物品  1:金币 2:次数*/@Overridepublic Map<String, Object> eggsLottery(Integer userId, Integer consumeType) {/*******first : check user ************/checkUserIsLock(userId);logger.info("userId {} start lottery  -eggs.", userId);Jedis jedis = RedisPool.getJedis();try {//查询活动开关String hget = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "status");if (null == hget || "0".equals(hget)) {throw new BusiException(E.INVALID_PARAMETER, "活动暂未开启,敬请期待");}//check lottery typeLong consumeScore = 0L;/**score lottery**/consumeScore = jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "consumeGoldScore", 0);if (consumeScore < 1) {throw new BusiException(E.EGGS_ACTIVITY_CONFIG_EXCEPTION, "活动配置有误!");}long surScore = goldWalletMapper.selectAmountGoldByUserId(userId);surScore = surScore - consumeScore;if (surScore < 0) {throw new BusiException(E.SCORE_NOT_ENOUGH, "您的金币不足");}// 砸金蛋之前扣除金币Date now = new Date();reduceGold(consumeScore, now, userId);/*******second : lottery ************/Map<String, Object> map;try {map = lottery(jedis, now, userId, consumeScore);// 抽奖结束后 记录今日总共完成的抽奖次数 +1// 必中 不加jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_TOTAL_COUNT, userId.toString(), 1);} catch (Exception e) {throw e;}return map;} finally {RedisPool.returnJedis(jedis);}}/*** 抽奖 begin----*/private Map<String, Object> lottery(Jedis jedis, Date now, Integer userId, Long consumeScore) {Map<String, Object> map = new HashMap<String, Object>();// 判断本次是否是必中?  jackpotType=1: 不是 2:是必中Integer jackpotType = 1;// 剩余次数Integer freeCount = 0;String countStr = jedis.hget(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString());if (StringUtils.isNotEmpty(countStr)) {Integer count = Integer.valueOf(countStr);String whenAwardCount = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "whenAwardCount");if (StringUtils.isEmpty(whenAwardCount)) {throw new BusiException(E.INVALID_REQUEST, "请先完善砸金蛋全局配置");}freeCount = Integer.valueOf(whenAwardCount) - count - 1;if (count >= Integer.valueOf(whenAwardCount) - 1) {logger.info("此次是必中....");// 此次是必中jackpotType = 2;// 抽奖结束后 先把记录总共完成的抽奖次数 置为0次jedis.hdel(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString());jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString(), 0);} else {logger.info("此次不是必中....");}if (freeCount == 0) {freeCount = Integer.valueOf(whenAwardCount);}}// 根据配置得到总的奖品数量Integer totalCount = 0;if (jackpotType == 1) {totalCount = getAwardTotalCount(1);} else {totalCount = getAwardTotalCount(2);}Integer award = getRandomNumber(totalCount);// 看落在哪个区间Integer awardId = getWinAwardId(award, jackpotType);BsGoldEggsConfig goldEggsConfig = goldEggsConfigMapper.selectById(awardId);if (goldEggsConfig == null) {throw new BusiException(E.INVALID_REQUEST, "奖品信息未找到");}map.put("freeCount", freeCount);map.put("userId", userId);map.put("awardId", awardId);map.put("awardName", goldEggsConfig.getDescribe());map.put("goldCount", goldEggsConfig.getGoldCount());map.put("awardImg", goldEggsConfig.getAwardImg());logger.info("userId {} win award {}, 奖励金币:{}, 随机生成抽奖数:{}", userId, goldEggsConfig.getDescribe(), goldEggsConfig.getGoldCount(), award);// 抽奖结束 action:if (jackpotType == 1) {// 抽奖结束后 记录累计抽奖次数 +1// 必中 不加jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString(), 1);}// 奖励金币结算Date now1 = new Date();lotteryAddGold(goldEggsConfig.getGoldCount().longValue(), now1, userId);return map;}/*** 得到中奖id** @param award : 随机生成的抽奖数字* @return*/private Integer getWinAwardId(Integer award, Integer jackpotType) {List<BsGoldEggsConfig> goldEggsConfigList = goldEggsConfigMapper.queryAllList();if (goldEggsConfigList == null || goldEggsConfigList.size() < 4) {throw new BusiException(E.INVALID_REQUEST, "请先完成砸金蛋奖品配置!");}Integer[] weight = new Integer[4];if (jackpotType == 1) {// 基础抽奖for (int i = 0; i < goldEggsConfigList.size(); i++) {weight[i] = goldEggsConfigList.get(i).getBaseWeight();}} else {// 必中抽奖for (int i = 0; i < goldEggsConfigList.size(); i++) {weight[i] = goldEggsConfigList.get(i).getWinWeight();}}// 判断随机数落在了哪个区间  左开右闭      ---------- 这里如果用redis的set来做区间?如何实现?Integer awardId = 1;if (0 < award && award <= weight[0]) {// 一等奖awardId = 1;} else if (weight[0] < award && award <= (weight[0] + weight[1])) {// 二等奖awardId = 2;} else if ((weight[0] + weight[1]) < award && award <= (weight[1] + weight[2])) {// 三等奖awardId = 3;} else {// 四等奖awardId = 4;}return awardId;}/*** 获取1-max范围内 一个随机数** @param max* @return*/private Integer getRandomNumber(Integer max) {int i = (int) (Math.random() * max + 1);return i;}

下面是用奖池写的一个算法 读者可忽略,博主只是记录一下。

思路:
根据需求,
1.生成两类奖池(普通奖池,和必中奖池),中奖概率不一样!为了保证概率正确,我们生成100组(1-100)的数字,随机打乱放入redis中,作为一个奖池。

2.生成中奖区间,放入redis

3.每次用户砸金蛋,从奖池里面取一个数,

4.判断该数在哪个中奖区间

/*** 抽奖 begin----  该方法废除*/private Map<String, Object> lottery2(Jedis jedis, Date now, Integer userId, Long consumeScore) {// 从奖池中拿出第一个奖品String jackpotKey = Rkey.SMASH_GOLD_EGGS_JACKPOT_ + "one";String baseWinLimitKey = Rkey.SMASH_GOLD_EGGS_AWARD_WIN_LIMIT_BASE;String nextWinLimitKey = Rkey.SMASH_GOLD_EGGS_AWARD_WIN_LIMIT_NEXT;Map<String, Object> map = new HashMap<String, Object>();// 奖池存在 且奖池不为空String awardFlag = jedis.lpop(jackpotKey);   // 如:20Integer award = Integer.valueOf(awardFlag);//if (!StringUtils.isEmpty(awardFlag)) {// 判断该奖品的等级// 这里是有问题的  博主后面纠正Set<String> winLimitSet = jedis.zrange(baseWinLimitKey, 0, award - 1);if (winLimitSet != null && !winLimitSet.isEmpty()) {Integer size = winLimitSet.size();List list = new ArrayList(winLimitSet);// 取区间最后一个String lastAwardLevel = String.valueOf(list.get(size - 1));// 获取奖品infoInteger id = null;if ("one".equals(lastAwardLevel)) {id = 1;} else if ("two".equals(lastAwardLevel)) {id = 2;} else if ("three".equals(lastAwardLevel)) {id = 3;} else if ("four".equals(lastAwardLevel)) {id = 4;}BsGoldEggsConfig goldEggsConfig = goldEggsConfigMapper.selectById(id);if (goldEggsConfig == null) {throw new BusiException(E.INVALID_REQUEST, "奖品信息未找到");}map.put("userId", userId);map.put("awardId", id);map.put("awardName", goldEggsConfig.getDescribe());map.put("goldCount", goldEggsConfig.getGoldCount());logger.info("userId {} win award {}, 奖励金币:{}, 随机生成抽奖数:{}", userId, goldEggsConfig.getDescribe(), goldEggsConfig.getGoldCount(), award);}}return map;}
/*** 生成奖池** @param jackpotType : 奖池类型  1:普通奖池 2:必中奖池* @param jackpotSort :奖池序号 1,2,3...... 如普通奖池1,普通奖池2,*/@Overridepublic void addAwardToJackpot(Integer jackpotType, Integer jackpotSort) {// 存放奖池数据List<String> awadList = new ArrayList<>();// 奖池keyString jackpotKey = "";String jackpotTypeToStr = "";if (jackpotType == 1) {jackpotTypeToStr = "普通";jackpotKey = Rkey.SMASH_GOLD_EGGS_JACKPOT_ + jackpotSort;} else {jackpotTypeToStr = "必中";jackpotKey = Rkey.SMASH_GOLD_EGGS_NEXT_WIN_JACKPOT_ + jackpotSort;}logger.info("开始生成{}奖池{}。。。。。", jackpotTypeToStr, jackpotSort);Jedis jedis = RedisPool.getJedis();try {if (jedis.exists(jackpotKey)) {// 判断奖池中是否还有奖品Long length = jedis.llen(jackpotKey);if (length <= 0) {// 奖池空了,重新放入奖品logger.info("{}奖池{}空了,重新放入奖品。。。。。", jackpotTypeToStr, jackpotSort);// 根据配置得到总的奖品数量Integer totalCount = getAwardTotalCount(1);setSingleAwardToJackpot(awadList, jedis, jackpotKey, totalCount);}} else {// 直接生成奖池logger.info("{}奖池{}不存在,直接放入奖品。。。。。", jackpotTypeToStr, jackpotSort);Integer totalCount = getAwardTotalCount(1);setSingleAwardToJackpot(awadList, jedis, jackpotKey, totalCount);}} finally {RedisPool.returnJedis(jedis);}}/*** 获取奖池奖品数量** @param type 奖池类型:1:普通奖池  2:必中奖池* @return*/Integer getAwardTotalCount(Integer type) {List<BsGoldEggsConfig> goldEggsConfigList = goldEggsConfigMapper.queryAllList();if (goldEggsConfigList == null || goldEggsConfigList.size() < 4) {throw new BusiException(E.INVALID_REQUEST, "请先完成砸金蛋奖品配置!");}Integer totalCount = 0;if (type == 1) {// 普通奖池奖品数量for (BsGoldEggsConfig goldEggsConfig : goldEggsConfigList) {totalCount += goldEggsConfig.getBaseWeight();}} else {// 必中奖池数量Jedis jedis = RedisPool.getJedis();try {String mustAwardLevel = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "mustAwardLevel");if (StringUtils.isEmpty(mustAwardLevel)) {throw new BusiException(E.INVALID_REQUEST, "请先完成砸金蛋奖品配置!");}for (int i = 0; i < Integer.valueOf(mustAwardLevel); i++) {totalCount += goldEggsConfigList.get(i).getWinWeight();}} finally {RedisPool.returnJedis(jedis);}}return totalCount;}/*** @param awadList* @param jedis* @param jackpotKey* @param totalCount 总的奖品个数 比如一等奖10个,二等奖20个,三等奖30,四等奖40  则totalCount = 10+20+30+40=100*/private void setSingleAwardToJackpot(List<String> awadList, Jedis jedis, String jackpotKey, Integer totalCount) {// 1.生成 100组 [1-100] 随机数 awadListfor (int i = 0; i < 2; i++) {List<Integer> list = getOneToHundredNumber(totalCount);for (Integer j : list) {awadList.add(j.toString());}}// 2.awadList打乱放入redis(list)  这里打乱2次Collections.shuffle(awadList);Collections.shuffle(awadList);// 3.放入redisawadList.forEach(s -> jedis.lpush(jackpotKey, s));logger.info("奖品info:预设值:{} 实际设置:{}", 10000, awadList.size());}/*** jdk8 得到包含1-end数字的list* end : 生成数字的个数** @return*/private List<Integer> getOneToHundredNumber(Integer end) {// 起始数字int start = 1;// 生成数字的个数// int end = 100;// 生成1,2,3,4,5...100List<Integer> list = Stream.iterate(start, item -> item + 1).limit(end).collect(Collectors.toList());return list;}

JAVA 砸金蛋抽奖的简单实现相关推荐

  1. 简单的几句PHP生成美团3周年砸金蛋抽奖代码

    一款界面风格十分漂亮的HTML5手机砸金蛋抽奖代码,适用于微信.手机移动端抽奖活动.简单的几句PHP生成美团3周年砸金蛋抽奖代码,不多说直接上源码: <!DOCTYPE html PUBLIC ...

  2. 砸金蛋java代码_java实现砸金蛋抽奖功能

    本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下 代码如下 需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%. 累计砸第n次时必抽 ...

  3. paip 刮刮卡砸金蛋抽奖概率算法跟核心流程

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! paip ...

  4. php 砸金蛋抽奖,jQuery的砸金蛋抽奖代码

    jQuery的砸金蛋抽奖代码 .egg { width: 750px; height: 500px; margin: 50px auto 20px auto; background: url(imag ...

  5. 魔众抽奖系统 v2.0.0 上线超级砸金蛋抽奖方式

    倾情发布,打造易用的抽奖系统 魔众抽奖系统发布v2.0.0版本,新功能和Bug修复累计14项,上线超级砸金蛋抽奖方式. 2021年08月19日魔众抽奖系统发布v2.0.0版本,增加了以下14个特性: ...

  6. 砸蛋程序php,魔众砸金蛋抽奖系统PHP源码 v2.0.0

    魔众 魔众砸金蛋抽奖系统发布v2.0.0版本,新功能和Bug修复累计21项,支付抽奖,更有趣味的砸金蛋系统. 2020年07月23日魔众砸金蛋抽奖系统发布v2.0.0版本,增加了以下21个特性: – ...

  7. js砸金蛋抽奖js特效

    下载地址 js砸金蛋抽奖特效代码,基于jquery实现的砸金蛋抽奖活动页面. dd:

  8. php+mysql砸金蛋抽奖程序系统

    php砸金蛋抽奖程序模板,可设置背景音乐,可设置中奖概率,可以设置奖项,可设置抽奖码指定中奖.支持卡密,外部链接,实物 3种抽奖模式: 1.先登记资料,然后后抽奖, 2.匿名(无需登记,直接抽奖) 支 ...

  9. php 砸金蛋抽奖,jQuery抽奖砸金蛋代码

    特效描述:jQuery抽奖 砸金蛋代码.请在PHP环境下砸蛋 代码结构 1. 引入JS 2. HTML代码 jquery+php 请在服务器环境运行才能看到敲蛋后的效果. 锤子 123 functio ...

最新文章

  1. 中国开发者新福利:大模型API接口出炉,让普通用户玩转内容生成
  2. 2020-10-27(补码10000000为什么可以表示-128?)
  3. python处理表格很厉害么_Python读写Excel表格,就是这么简单粗暴又好用
  4. Spring RESTful错误处理
  5. mysql 查出相差年数_MySQL计算两个日期相差的天数、月数、年数
  6. 重大技术突破首次发布!十问解密云栖大会!
  7. Java IO流关闭顺序
  8. java的fprintf_fprintf不接受一个字符数组吗?
  9. Microsoft.VisualBasic.dll的妙用(开发中肯定会用到哦)
  10. css实现背景动态效果图
  11. 计算机学风建设新闻稿,第十一届学风建设月动员大会新闻稿_
  12. vuepress-theme-reco@1.x 解决博客首页 与 仓库README不兼容问题
  13. ARM与Intel芯片性能不严谨比较
  14. 51.Linux 什么是线程?
  15. 【本人秃顶程序员】高级 Java 必须突破的 10 个知识点!
  16. 减肥瘦不下来的三个关键
  17. Android输入法方法,Android的输入法系统框架原理
  18. mysql 多表查询语句
  19. 福建省区块链应用商会成立大会 发起单位零伽壹现场做主题分享
  20. 微信如何群发不封号?

热门文章

  1. 美国福禄克2021年1月重磅发布两款红外热像仪——TiS55+和TiS75+
  2. 兰芝女王 的炒股心得-转载编辑
  3. banner panel 页面_广告位(banner)的可视化管理后台逻辑说明
  4. Outlook Express邮件丢失的原因
  5. Element中table组件(el-table)右侧滚动条空白占位处理
  6. chrome拓展以及油猴脚本推荐
  7. EPS QOS 体系解读
  8. Android MediaPlayer源码分析
  9. Win10 Rational Rose 安装教程
  10. 求无序数组的第K(大/小)数的三种方法