专栏首页Danny的专栏【项目实战】——Java根据奖品权重计算中奖概率实现抽奖(适用于砸金蛋、大转盘等抽奖活动)

【项目实战】——Java根据奖品权重计算中奖概率实现抽奖(适用于砸金蛋、大转盘等抽奖活动)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/details/50480687

  双蛋节(圣诞+元旦)刚刚过去,前几天项目上线的砸金蛋活动也圆满结束。

  现在在许多网站上都会有抽奖的活动,抽奖的算法也是多种多样,这里介绍一下如何根据每种奖品的权重来抽奖,适用于多种抽奖形式。

奖品设置


  比如现在举行一次砸金蛋活动中,奖品如下:

  奖品在数据库中的存储情况

抽奖实现


  奖品实体 Prize.java

    public class Prize {    
    private int id;//奖品id
    private String prize_name;//奖品名称
    private int prize_amount;//奖品(剩余)数量
    private int prize_weight;//奖品权重
    //getter、setter

  这里只考虑最简单的抽奖实现,所以暂时只为奖品设计如上4个字段。

  见注释,prize_name表示奖品名称;prize_amount表示奖品数量,即本次抽奖活动计划发放此奖品的数量;prize_weight表示奖品权重,表示奖品被抽到的几率的比重,权重越大,被抽到的几率越大,比如本次砸金蛋活动有4种奖品,权重分别是1、2、3、4,总权重是10,那么每种奖品被抽到的几率就是1/10,2/10,3/10,4/10。

  核心算法:

/**
     * 根据Math.random()产生一个double型的随机数,判断每个奖品出现的概率
     * @param prizes
     * @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
     */
    public int getPrizeIndex(List<Prize> prizes) {
        DecimalFormat df = new DecimalFormat("######0.00");  
        int random = -1;
        try{
            //计算总权重
            double sumWeight = 0;
            for(Prize p : prizes){
                sumWeight += p.getPrize_weight();
            }

            //产生随机数
            double randomNumber;
            randomNumber = Math.random();

            //根据随机数在所有奖品分布的区域并确定所抽奖品
            double d1 = 0;
            double d2 = 0;          
            for(int i=0;i<prizes.size();i++){
                d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight()))/sumWeight;
                if(i==0){
                    d1 = 0;
                }else{
                    d1 +=Double.parseDouble(String.valueOf(prizes.get(i-1).getPrize_weight()))/sumWeight;
                }
                if(randomNumber >= d1 && randomNumber <= d2){
                    random = i;
                    break;
                }
            }
        }catch(Exception e){
            System.out.println("生成抽奖随机数出错,出错原因:" +e.getMessage());
        }
        return random;
    }

  抽奖的逻辑可以用下面这张图表示:

  分析:如上图,为了便于计算和理解,设置每种奖品的权重分别为1,2,3,4,所以被抽到的概率分别为0.1,0.2,0.3,0.4(本次活动中奖概率为100%)。

  先生成一个随机数randomNumber,然后根据随机数所处区域判断奖品:

0<randomNumber<=0.1   表示抽中一等奖
0.1<randomNumber<=0.3 表示抽中二等奖
0.3<randomNumber<=0.6 表示抽中三等奖
0.6<randomNumber<=1.0 表示抽中四等奖

抽奖测试


public static void main(String[] agrs) {
        int i = 0;
        PrizeMathRandom a = new PrizeMathRandom();
        int[] result=new int[4];
        List<Prize> prizes = new ArrayList<Prize>();

        Prize p1 = new Prize();
        p1.setPrize_name("范冰冰海报");
        p1.setPrize_weight(1);//奖品的权重设置成1
        prizes.add(p1);

        Prize p2 = new Prize();
        p2.setPrize_name("上海紫园1号别墅");
        p2.setPrize_weight(2);//奖品的权重设置成2
        prizes.add(p2);

        Prize p3 = new Prize();
        p3.setPrize_name("奥迪a9");
        p3.setPrize_weight(3);//奖品的权重设置成3
        prizes.add(p3);

        Prize p4 = new Prize();
        p4.setPrize_name("双色球彩票");
        p4.setPrize_weight(4);//奖品的权重设置成4
        prizes.add(p4);

        System.out.println("抽奖开始");
        for (i = 0; i < 10000; i++)// 打印100个测试概率的准确性
        {
            int selected=a.getPrizeIndex(prizes);
            System.out.println("第"+i+"次抽中的奖品为:"+prizes.get(selected).getPrize_name());
            result[selected]++;
            System.out.println("--------------------------------");
        }
        System.out.println("抽奖结束");
        System.out.println("每种奖品抽到的数量为:");
        System.out.println("一等奖:"+result[0]);
        System.out.println("二等奖:"+result[1]);
        System.out.println("三等奖:"+result[2]);
        System.out.println("四等奖:"+result[3]);       
    }

  尝试抽奖10000次的结果如下:

一等奖:962
二等奖:2007
三等奖:3043
四等奖:3988

  每类奖品获奖次数比例刚好大约为1:2:3:4,学过概率的你肯定知道抽奖次数越多,测试结果越准确~~

  Tips

  如果计划中奖率是100%的话,那么10个奖品只能抽奖10次,所以还要根据实际情况设置每种奖品数量和权重。

  如果需要设置中奖率不为100%,可以添加一个“伪奖品”,并为其设置权重,那么抽到这个“伪奖品”的概率就是不中奖的概率。

  如果在抽奖过程中某类奖品抽完了,可以做个判断,如果此奖品的剩余数量为0,则重新抽取奖品,直到抽到其他奖品位置。

  本来活动期间小编报着随时抢救bug的心态,连回家都抱着电脑,然而从活动上线到活动结束,并没有出现bug~~在此感谢产品部、测试部和研发部所有同事在上线前轰炸式的测试~~

【 转载请注明出处——胡玉洋《【项目实战】——Java中根据奖品权重实现抽奖(砸金蛋、大转盘等)》】

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【J2SE快速进阶】——数组(及其内存分析 )

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

    DannyHoo
  • 图解MySQL索引--B-Tree(B+Tree)

    看了很多关于索引的博客,讲的大同小异。但是始终没有让我明白关于索引的一些概念,如B-Tree索引,Hash索引,唯一索引…或许有很多人和我一样,没搞清楚概念就开...

    DannyHoo
  • 在EasyUI的DataGrid中嵌入Combobox

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

    DannyHoo
  • 为什么你总是不中奖?

    那么,除了那句冷冰冰的“该活动最终解释权归 xxx 公司所有”之外,我们还能否了解更多关于抽奖逻辑的信息呢?答案是肯定的。本文中姬小光将向大家展示,一些基本的概...

    姬小光
  • 2017败北清单:人工智能在这些游戏中战胜了人类

    大数据文摘
  • 2017年 AI在人类设计的所有游戏中都打败了人类

    在20世纪的大部分时间里,国际象棋是人工智能研究人员的一个基准。早在上世纪50年代初,约翰?麦卡锡提出了“人工智能”一词,他曾把国际象棋称为“人工智能领域的果蝇...

    企鹅号小编
  • Leetcode: Sqrt(x)

    卡尔曼和玻尔兹曼谁曼
  • mac python virtualenv 安装虚拟环境

    主要是为了解决在同一个系统中存在多个项目的情况, 采用虚拟的方式,为每个项目创建各自的环境,使各个项目不会相互干扰

    onety码生
  • win8降级win7步骤

    用户1127987
  • 人工智能语音进化史三部曲

    关于人工智能诞生没有统一说法,有部分学者以1950年“人工智能之父”马文·明斯基建造世界上第一台神经网络计算机为起点。且以当年语音交互起始到现在,大致经历三段演...

    企鹅号小编

扫码关注云+社区

领取腾讯云代金券