java实现砸金蛋抽奖功能

本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下

代码如下

需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%。

累计砸第n次时必抽中x等奖以上的奖品。比如,累计砸第5次,则此次必中二等奖及以上的奖品。且配置的此次必中中奖概率不一样。

/**
 * 金蛋抽奖
 * userId : 抽奖用户ID
 * consumeType : 抽奖消耗的物品 1:金币 2:次数
 */
 @Override
 public 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 type
     Long 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);  // 如:20
   Integer 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));

       // 获取奖品info
       Integer 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,
 */
 @Override
 public void addAwardToJackpot(Integer jackpotType, Integer jackpotSort) {

   // 存放奖池数据
   List<String> awadList = new ArrayList<>();
   // 奖池key
   String 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] 随机数 awadList
   for (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.放入redis
   awadList.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...100
   List<Integer> list = Stream.iterate(start, item -> item + 1).limit(end).collect(Collectors.toList());
   return list;
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java抽奖算法第二例

    本文实例为大家分享了java抽奖算法,供大家参考,具体内容如下 1. 算法分析  根据概率将奖品划分区间,每个区间代表一个奖品,然后抽取随机数,反查落在那个区间上,即为所抽取的奖品. 2. 代码 核心算法 public class Arithmetic { // 放大倍数 private static final int mulriple = 1000000; public int pay(List<Prize> prizes) { int lastScope = 0; // 洗牌,打乱奖品次

  • 纯java代码实现抽奖系统

    本文实例为大家分享了java实现抽奖系统 的具体代码,供大家参考,具体内容如下 模拟一个在终端登陆注册的页面 public class Cjtest { public static void main(String[] args) { String isGoOn = "n"; //循环的判断条件是否继续 do { System.out.println("*********幸运52********"); System.out.println("1.注册&qu

  • java实现抽奖概率类

    本文实例为大家分享了java实现抽奖概率类的具体代码,供大家参考,具体内容如下 在一些项目需求中,可能会遇到抽奖问题,如提供一系列奖品及获奖概率,要求根据概率返回每次抽到的奖品.以下是本人在实际项目中写的一个抽奖工具类,与大家共同分享: import java.util.ArrayList; import java.util.List; import java.util.Random; /** * 抽奖工具类,概率和可以不等于1 * 概率为百分数去掉百分号的部分,如10%,则为10 * 抽奖操作

  • 基于Java实现抽奖系统

    本次任务要求为某商场开发一套幸运抽奖系统,客户必须首先注册成为该商场会员,会员登录成功后,就可以参加抽奖活动了. 注册 用户选择"注册"菜单,进入注册界面.输入用户名和密码后,系统提示注册成功,并给出会员卡号. 登录 注册成功后,用户选择"登录"菜单,进入登录界面.输入注册时的用户名和密码.登录成功,系统提示欢迎信息.如果用户和密码输入错误,提示用户继续输入,最多有3次机会. 抽奖 登录成功后,用户选择"抽奖"菜单,进入幸运抽奖界面.输入会员卡号

  • Java实现游戏抽奖算法

    常用抽奖算法对比 基础的游戏抽奖算法通常要求实现在指定奖品的集合中,每个奖品根据对对应概率进行抽取.个人了解的主要有以下几中抽奖算法: 随机数一一对应 算法思想 这种算法思想最为简单.将n个奖品编号0 - N-1,其中各类奖品的概率通过其数量体现,最后程序产生0~n-1之间的随机数便是抽中的奖品编号.例如: 苹果手机概率1%,网站会员20%,折扣券20%,很遗憾59%.这样,编号0是苹果手机,1-20是会员,21-40是折扣券,41~100是 很遗憾.产生的随机数落在那个区间,就代表那个奖品被抽

  • Java实现简单抽奖功能界面

    本文实例为大家分享了Java实现简单抽奖功能的具体代码,供大家参考,具体内容如下 要求:定义文本框添加姓名,将姓名存储并且在界面中可见,点击抽奖按钮进行抽奖并输出最后的中奖得主. 关于抽奖当然需要用到随机数的生成函数,在Java中Random 的使用合适比较简单的: 有两种不同的Random方法的使用,其中一种是Math中的random. 该方法生成的是0-1之间的浮点数,如果要生成整数类型的数字,可以乘一个整数,强制转换为整数类型. int n = (int)(Math.random()*x)

  • Java实现抽奖功能

    本文实例为大家分享了Java实现抽奖功能的具体代码,供大家参考,具体内容如下 1 概述 项目开发中经常会有抽奖这样的营销活动的需求,例如:积分大转盘.刮刮乐.老虎机等等多种形式,其实后台的实现方法是一样的,本文介绍一种常用的抽奖实现方法. 整个抽奖过程包括以下几个方面: 奖品 奖品池 抽奖算法 奖品限制 奖品发放 2 奖品 奖品包括奖品.奖品概率和限制.奖品记录. 奖品表: CREATE TABLE `points_luck_draw_prize` ( `id` bigint(20) NOT N

  • JAVA使用随机数实现概率抽奖

    本文实例为大家分享了JAVA使用随机数实现概率抽奖的具体代码,供大家参考,具体内容如下 需求 网站现有一抽奖功能,已经定义好奖品,每个奖品都有对应的中奖概率.通过奖品概率随机进行抽奖 实现思路 1.每个奖品都有对应的中奖概率,先对所有奖品中奖概率求和 2.计算出每个奖品在0-1之间所占的区间块 3.随机产生0-1之间的随机数,随机数落在哪个区间,就是中奖哪个 例如现有以下奖品: 奖品A 中奖概率为 0.1 奖品B 中奖概率为 0.01 奖品C 中奖概率为 0.001 奖品D 中奖概率为 0.8

  • Java实现多用户注册登录的幸运抽奖

    本文实例为大家分享了Java实现简单幸运抽奖的具体代码,供大家参考,具体内容如下 代码模块: User类: package test1; public class User { private String userName; private String password; private int vipID; public User(String userName,String password,int vipID) { this.userName = userName; this.pass

  • 简单实现java抽奖系统

    本文为大家分享了java抽奖系统的具体代码,供大家参考,具体内容如下 用户信息类 /* * 用户信息类 * 1.账号 * 2.密码 * 3.卡号 * 4.是否登录 */ public class User { public static String userName = ""; public static String passWord = ""; public static int cardNumber = 0; // 是否登录 public static bo

随机推荐