java实现砸金蛋抽奖功能
程序员文章站
2022-06-21 14:10:17
本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下代码如下需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%。累计砸第n次时必抽中x等...
本文实例为大家分享了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; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。