当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Java实现按比抽奖功能

    栏目:Linux/apache问题 时间:2020-01-08 10:30

    需求是要做几个小游戏的抽奖功能,需要根据不同的游戏有不同的抽奖规则,其中也有很多共性,可归纳为只按奖品占比抽取、奖品占比与奖品数量抽取、分段抽取,为方便起见将这些的抽奖的规则统一封装到了工具类中。抽奖的核心逻辑使用的叫做离散算法实现的。

    一.概述

    使用离散算法即根据奖品占比进行分段,然后再产生随机数匹配所对应的区间。
    首先定义Prize奖品实体类,类中有prizeName(奖品名称)、prizeWeight(奖品比重)、prizeCount(奖品数量)属性,下面是核心的代码:

     /**
       * 按比例随机抽取一项
       * @param list 奖品列表
       * @return 类型值
       */
      public static String ratioExtract(List<Prize> list) {
        //非空判断
        if (list==null || list.size()<1) {
          return null;
        }
        //占比之和
        double sum=0.00;
        //分段数组(20,30,60)
        double[] subArray=new double[list.size()+1];
        //将概率分段
        for (int i = 0; i < list.size(); i++) {
          subArray[i]=sum;
          //这里除要考虑奖品所占比重外还要将奖品数量计算分段其中
          sum+=list.get(i).getPrizeWeight()*list.get(i).getPrizeCount();
        }
        //加上取最大的值
        subArray[subArray.length-1]=sum;
    
        /* 产生随机数 */
        Random random=new Random();
        double rand = random.nextDouble()*sum;
    
        //返回字符
        String field=null;
        for (int i = 0; i < subArray.length; i++) {
          if (i==subArray.length-1) {
            return field;
          }
          if (rand>=subArray[i] && rand<subArray[i+1]) {
            field=list.get(i).getPrizeName();
            break;
          }
        }
        return field;
      }

    二、测试

    以下是完整的抽奖工具类

    import lombok.Data;
    import org.apache.commons.lang.math.RandomUtils;
    
    import java.util.List;
    import java.util.Random;
    
    /**
     * @Description: 抽奖工具类
     * @author: xiake
     * @Date: 2020/1/5 13:23
     * @ModifiedDate:2020/1/5 13:23
     * @Copyright: miaoxaike.com
     */
    public class PrizeMathRandom {
    
      /**
       * 按比例随机抽取一项
       * @param fieldArray 类型值数组
       * @param proportions 与类型值对应 的占比值
       * @return 类型值
       */
      public static String ratioExtract(String[] fieldArray,double[] proportions) {
        //判断两个数组长度是否相等
        if(fieldArray.length!=proportions.length) {
          return "两数组长度不相等,无法执行";
        }
    
        //占比之和
        double sum=0.00;
        //分段数组(20,30,60)
        double[] subArray=new double[proportions.length+1];
        //将概率分段
        for (int i = 0; i < proportions.length; i++) {
          subArray[i]=sum;
          sum+=proportions[i];
        }
        //加上取最大的值
        subArray[subArray.length-1]=sum;
        Random random=new Random();
        /* 产生随机数 区间为 (0,sum)*/
        double rand = random.nextDouble()*sum;
        //返回字符
        String field=null;
        for (int i = 0; i < subArray.length; i++) {
          if (rand>=subArray[i] && rand<subArray[i+1]) {
            field=fieldArray[i];
          }
        }
        return field;
      }
    
      /**
       * 按比例随机抽取一项
       * @param list 奖品列表
       * @return 类型值
       */
      public static String ratioExtract(List<Prize> list) {
        //非空判断
        if (list==null || list.size()<1) {
          return null;
        }
        //占比之和
        double sum=0.00;
        //分段数组(20,30,60)
        double[] subArray=new double[list.size()+1];
        //将概率分段
        for (int i = 0; i < list.size(); i++) {
          subArray[i]=sum;
          sum+=list.get(i).getPrizeWeight()*list.get(i).getPrizeCount();
        }
        //加上取最大的值
        subArray[subArray.length-1]=sum;
    
        /* 产生随机数 */
        Random random=new Random();
        double rand = random.nextDouble()*sum;
    
        //返回字符
        String field=null;
        for (int i = 0; i < subArray.length; i++) {
          if (i==subArray.length-1) {
            return field;
          }
          if (rand>=subArray[i] && rand<subArray[i+1]) {
            field=list.get(i).getPrizeName();
            break;
          }
        }
        return field;
      }
    
    
      /**
       * 双重分段抽取,
       * @param fieldArray 分段数组, 参数值用"-"组装(例: {"6-14","14-23","23-32","32-40"})
       * @param proportions 每段出现的概率
       * @return 返回按比例抽取后, 分段范围内的随机一个值
       */
      public static Integer ratioExtractDouble(String[] fieldArray,double[] proportions) {
        String string = ratioExtract(fieldArray,proportions);
        String[] split = string.split("-");
        int result = RandomUtils.nextInt(Integer.parseInt(split[1]))+Integer.parseInt(split[0]);
        return result;
      }
    
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      class Prize{
        //奖品名称
        private String prizeName;
        //奖品占比
        private double prizeWeight;
        //奖品数量
        private int prizeCount;
      }
    }