java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)功能
本文實(shí)例為大家分享了java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)的具體代碼,供大家參考,具體內(nèi)容如下
代碼如下
需求:用戶(hù)每一次砸金蛋,抽中一等獎(jiǎng)的概率為2% 二等獎(jiǎng)10% 三等獎(jiǎng)18% 四等獎(jiǎng)70%。
累計(jì)砸第n次時(shí)必抽中x等獎(jiǎng)以上的獎(jiǎng)品。比如,累計(jì)砸第5次,則此次必中二等獎(jiǎng)及以上的獎(jiǎng)品。且配置的此次必中中獎(jiǎng)概率不一樣。
/** * 金蛋抽獎(jiǎng) * userId : 抽獎(jiǎng)用戶(hù)ID * consumeType : 抽獎(jiǎng)消耗的物品 1:金幣 2:次數(shù) */ @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 { //查詢(xún)活動(dòng)開(kāi)關(guān) String hget = jedis.hget(Rkey.SMASH_GOLD_EGGS_GLOBAL_CONFIG, "status"); if (null == hget || "0".equals(hget)) { throw new BusiException(E.INVALID_PARAMETER, "活動(dòng)暫未開(kāi)啟,敬請(qǐng)期待"); } //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, "活動(dòng)配置有誤!"); } 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); // 抽獎(jiǎng)結(jié)束后 記錄今日總共完成的抽獎(jiǎng)次數(shù) +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); } } /** * 抽獎(jiǎng) 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; // 剩余次數(shù) 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, "請(qǐng)先完善砸金蛋全局配置"); } freeCount = Integer.valueOf(whenAwardCount) - count - 1; if (count >= Integer.valueOf(whenAwardCount) - 1) { logger.info("此次是必中...."); // 此次是必中 jackpotType = 2; // 抽獎(jiǎng)結(jié)束后 先把記錄總共完成的抽獎(jiǎng)次數(shù) 置為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); } } // 根據(jù)配置得到總的獎(jiǎng)品數(shù)量 Integer totalCount = 0; if (jackpotType == 1) { totalCount = getAwardTotalCount(1); } else { totalCount = getAwardTotalCount(2); } Integer award = getRandomNumber(totalCount); // 看落在哪個(gè)區(qū)間 Integer awardId = getWinAwardId(award, jackpotType); BsGoldEggsConfig goldEggsConfig = goldEggsConfigMapper.selectById(awardId); if (goldEggsConfig == null) { throw new BusiException(E.INVALID_REQUEST, "獎(jiǎng)品信息未找到"); } 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 {}, 獎(jiǎng)勵(lì)金幣:{}, 隨機(jī)生成抽獎(jiǎng)數(shù):{}", userId, goldEggsConfig.getDescribe(), goldEggsConfig.getGoldCount(), award); // 抽獎(jiǎng)結(jié)束 action: if (jackpotType == 1) { // 抽獎(jiǎng)結(jié)束后 記錄累計(jì)抽獎(jiǎng)次數(shù) +1 // 必中 不加 jedis.hincrBy(Rkey.SMASH_GOLD_EGGS_USER_WIN_COUNT, userId.toString(), 1); } // 獎(jiǎng)勵(lì)金幣結(jié)算 Date now1 = new Date(); lotteryAddGold(goldEggsConfig.getGoldCount().longValue(), now1, userId); return map; } /** * 得到中獎(jiǎng)id * * @param award : 隨機(jī)生成的抽獎(jiǎng)數(shù)字 * @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, "請(qǐng)先完成砸金蛋獎(jiǎng)品配置!"); } Integer[] weight = new Integer[4]; if (jackpotType == 1) { // 基礎(chǔ)抽獎(jiǎng) for (int i = 0; i < goldEggsConfigList.size(); i++) { weight[i] = goldEggsConfigList.get(i).getBaseWeight(); } } else { // 必中抽獎(jiǎng) for (int i = 0; i < goldEggsConfigList.size(); i++) { weight[i] = goldEggsConfigList.get(i).getWinWeight(); } } // 判斷隨機(jī)數(shù)落在了哪個(gè)區(qū)間 左開(kāi)右閉 ---------- 這里如果用redis的set來(lái)做區(qū)間?如何實(shí)現(xiàn)? Integer awardId = 1; if (0 < award && award <= weight[0]) { // 一等獎(jiǎng) awardId = 1; } else if (weight[0] < award && award <= (weight[0] + weight[1])) { // 二等獎(jiǎng) awardId = 2; } else if ((weight[0] + weight[1]) < award && award <= (weight[1] + weight[2])) { // 三等獎(jiǎng) awardId = 3; } else { // 四等獎(jiǎng) awardId = 4; } return awardId; } /** * 獲取1-max范圍內(nèi) 一個(gè)隨機(jī)數(shù) * * @param max * @return */ private Integer getRandomNumber(Integer max) { int i = (int) (Math.random() * max + 1); return i; }
下面是用獎(jiǎng)池寫(xiě)的一個(gè)算法 讀者可忽略,博主只是記錄一下。
思路:
根據(jù)需求:
1.生成兩類(lèi)獎(jiǎng)池(普通獎(jiǎng)池,和必中獎(jiǎng)池),中獎(jiǎng)概率不一樣!為了保證概率正確,我們生成100組(1-100)的數(shù)字,隨機(jī)打亂放入redis中,作為一個(gè)獎(jiǎng)池。
2.生成中獎(jiǎng)區(qū)間,放入redis
3.每次用戶(hù)砸金蛋,從獎(jiǎng)池里面取一個(gè)數(shù),
4.判斷該數(shù)在哪個(gè)中獎(jiǎng)區(qū)間
/** * 抽獎(jiǎng) begin---- 該方法廢除 */ private Map<String, Object> lottery2(Jedis jedis, Date now, Integer userId, Long consumeScore) { // 從獎(jiǎng)池中拿出第一個(gè)獎(jiǎng)品 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>(); // 獎(jiǎng)池存在 且獎(jiǎng)池不為空 String awardFlag = jedis.lpop(jackpotKey); // 如:20 Integer award = Integer.valueOf(awardFlag); // if (!StringUtils.isEmpty(awardFlag)) { // 判斷該獎(jiǎng)品的等級(jí) // 這里是有問(wèn)題的 博主后面糾正 Set<String> winLimitSet = jedis.zrange(baseWinLimitKey, 0, award - 1); if (winLimitSet != null && !winLimitSet.isEmpty()) { Integer size = winLimitSet.size(); List list = new ArrayList(winLimitSet); // 取區(qū)間最后一個(gè) String lastAwardLevel = String.valueOf(list.get(size - 1)); // 獲取獎(jiǎng)品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, "獎(jiǎng)品信息未找到"); } map.put("userId", userId); map.put("awardId", id); map.put("awardName", goldEggsConfig.getDescribe()); map.put("goldCount", goldEggsConfig.getGoldCount()); logger.info("userId {} win award {}, 獎(jiǎng)勵(lì)金幣:{}, 隨機(jī)生成抽獎(jiǎng)數(shù):{}", userId, goldEggsConfig.getDescribe(), goldEggsConfig.getGoldCount(), award); } } return map; } /** * 生成獎(jiǎng)池 * * @param jackpotType : 獎(jiǎng)池類(lèi)型 1:普通獎(jiǎng)池 2:必中獎(jiǎng)池 * @param jackpotSort :獎(jiǎng)池序號(hào) 1,2,3...... 如普通獎(jiǎng)池1,普通獎(jiǎng)池2, */ @Override public void addAwardToJackpot(Integer jackpotType, Integer jackpotSort) { // 存放獎(jiǎng)池?cái)?shù)據(jù) List<String> awadList = new ArrayList<>(); // 獎(jiǎng)池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("開(kāi)始生成{}獎(jiǎng)池{}。。。。。", jackpotTypeToStr, jackpotSort); Jedis jedis = RedisPool.getJedis(); try { if (jedis.exists(jackpotKey)) { // 判斷獎(jiǎng)池中是否還有獎(jiǎng)品 Long length = jedis.llen(jackpotKey); if (length <= 0) { // 獎(jiǎng)池空了,重新放入獎(jiǎng)品 logger.info("{}獎(jiǎng)池{}空了,重新放入獎(jiǎng)品。。。。。", jackpotTypeToStr, jackpotSort); // 根據(jù)配置得到總的獎(jiǎng)品數(shù)量 Integer totalCount = getAwardTotalCount(1); setSingleAwardToJackpot(awadList, jedis, jackpotKey, totalCount); } } else { // 直接生成獎(jiǎng)池 logger.info("{}獎(jiǎng)池{}不存在,直接放入獎(jiǎng)品。。。。。", jackpotTypeToStr, jackpotSort); Integer totalCount = getAwardTotalCount(1); setSingleAwardToJackpot(awadList, jedis, jackpotKey, totalCount); } } finally { RedisPool.returnJedis(jedis); } } /** * 獲取獎(jiǎng)池獎(jiǎng)品數(shù)量 * * @param type 獎(jiǎng)池類(lèi)型:1:普通獎(jiǎng)池 2:必中獎(jiǎng)池 * @return */ Integer getAwardTotalCount(Integer type) { List<BsGoldEggsConfig> goldEggsConfigList = goldEggsConfigMapper.queryAllList(); if (goldEggsConfigList == null || goldEggsConfigList.size() < 4) { throw new BusiException(E.INVALID_REQUEST, "請(qǐng)先完成砸金蛋獎(jiǎng)品配置!"); } Integer totalCount = 0; if (type == 1) { // 普通獎(jiǎng)池獎(jiǎng)品數(shù)量 for (BsGoldEggsConfig goldEggsConfig : goldEggsConfigList) { totalCount += goldEggsConfig.getBaseWeight(); } } else { // 必中獎(jiǎng)池?cái)?shù)量 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, "請(qǐng)先完成砸金蛋獎(jiǎng)品配置!"); } 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 總的獎(jiǎng)品個(gè)數(shù) 比如一等獎(jiǎng)10個(gè),二等獎(jiǎng)20個(gè),三等獎(jiǎng)30,四等獎(jiǎng)40 則totalCount = 10+20+30+40=100 */ private void setSingleAwardToJackpot(List<String> awadList, Jedis jedis, String jackpotKey, Integer totalCount) { // 1.生成 100組 [1-100] 隨機(jī)數(shù) 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("獎(jiǎng)品info:預(yù)設(shè)值:{} 實(shí)際設(shè)置:{}", 10000, awadList.size()); } /** * jdk8 得到包含1-end數(shù)字的list * end : 生成數(shù)字的個(gè)數(shù) * * @return */ private List<Integer> getOneToHundredNumber(Integer end) { // 起始數(shù)字 int start = 1; // 生成數(shù)字的個(gè)數(shù) // 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; }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java實(shí)現(xiàn)抽獎(jiǎng)功能
- Java實(shí)現(xiàn)游戲抽獎(jiǎng)算法
- Java實(shí)現(xiàn)多用戶(hù)注冊(cè)登錄的幸運(yùn)抽獎(jiǎng)
- Java實(shí)現(xiàn)簡(jiǎn)單抽獎(jiǎng)功能界面
- java實(shí)現(xiàn)抽獎(jiǎng)概率類(lèi)
- 基于Java實(shí)現(xiàn)抽獎(jiǎng)系統(tǒng)
- 簡(jiǎn)單實(shí)現(xiàn)java抽獎(jiǎng)系統(tǒng)
- Java抽獎(jiǎng)算法第二例
- 純java代碼實(shí)現(xiàn)抽獎(jiǎng)系統(tǒng)
- JAVA使用隨機(jī)數(shù)實(shí)現(xiàn)概率抽獎(jiǎng)
相關(guān)文章
使用Mybatis接收Integer參數(shù)的問(wèn)題
這篇文章主要介紹了使用Mybatis接收Integer參數(shù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot對(duì)數(shù)據(jù)訪(fǎng)問(wèn)層進(jìn)行單元測(cè)試的方法詳解
我們公司作為一個(gè)面向銀行、金融機(jī)構(gòu)的TO B類(lèi)企業(yè),頻繁遇到各個(gè)甲方爸爸提出的國(guó)產(chǎn)化數(shù)據(jù)庫(kù)的改造需求,包括OceanBase, TiDB,geldenDB等等,本文就介紹一種快高效、可復(fù)用的解決方案——對(duì)數(shù)據(jù)訪(fǎng)問(wèn)層做單元測(cè)試,需要的朋友可以參考下2023-08-08springboot動(dòng)態(tài)注入配置與docker設(shè)置環(huán)境變量的方法
這篇文章主要介紹了springboot動(dòng)態(tài)注入配置與docker設(shè)置環(huán)境變量的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04Elasticsearch配置文件選項(xiàng)作用詳解(es7)
這篇文章主要為大家介紹了Elasticsearch配置文件選項(xiàng)作用詳解(es7),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09使用json字符串插入節(jié)點(diǎn)或者覆蓋節(jié)點(diǎn)
這篇文章主要介紹了使用json字符串插入節(jié)點(diǎn)或者覆蓋節(jié)點(diǎn)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08JavaFX Application應(yīng)用實(shí)例
下面小編就為大家?guī)?lái)一篇JavaFX Application應(yīng)用實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10