欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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;
 }

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

相关标签: java 抽奖