您好,登錄后才能下訂單哦!
本篇文章為大家展示了利用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; }
上述內容就是利用java編寫一個砸金蛋功能,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。