天天福利抽奖-JAVA概率抽奖

搞了个抽奖活动,中大奖中的简直爽歪歪?

 

不过还是要偷偷告诉你:抽奖是有内幕的~~~(不能让领导看到,会被打?)

总在各种app上看到转盘抽奖,翻牌抽奖,每次抱着中最大奖的心,换来的都是未中奖的提示,可谓是竹篮打水一场空,屡战屡败,屡败屡战~

现在就聊聊中奖的事,搬好小板凳排队做好了?‍♂️??‍♂️??‍♂️????????????

一、实现思路(这个应该不难理解吧~)


每个奖品都有对应的中奖概率,先对所有奖品中奖概率求和
计算出每个奖品在0-1之间所占的区间块
随机产生0-1之间的随机数,随机数落在哪个区间,就是中奖哪个 
例如现有以下奖品: 
奖品A 中奖概率为 0.1 
奖品B 中奖概率为 0.01 
奖品C 中奖概率为 0.001 
奖品D 中奖概率为 0.8

第一步:求出概率总和 0.1+0.01+0.001+0.8 = 0.911 
第二步:计算每个奖品的所占区间块 
奖品A: 0.1 / 0.911 = 0.1098 
奖品B: (0.1+0.01)/ 0.911 = 0.1207 
奖品C:(0.1+0.11+0.001)/ 0.911 = 0.1218 
奖品D:(0.1+0.11+0.001+0.8)/ 0.911 = 1 
则: 
奖品A的所占区间为:0~0.1098 
奖品B的所占区间为:0.1098~0.1207 
奖品C的所占区间为:0.1207~0.1218 
奖品D的所占区间为:0.1218~1
到此为止思路应该了解了,不过我要做的是这个的升级版

根据不同类型的人分别设置概率(emm~换句话说根据身份设置概率发放奖品)

特此说明一下:里面的概率10代表10%,可以精确到小数点后两位,比如 0.01%

二、干货如下

import lombok.Data;
import lombok.ToString;
/**
 * @Author: yansf
 * @Description:奖励实体
 * @Date:Creat in 10:35 AM 2019/1/16
 * @Modified By:
 */
@Data
@ToString
public class RewardDto {
    /**
     * 奖品id
     */
    private int welfareId;
    /**
     * 天天福利管理Id(Welfare_ManagerId)
     */
    private int welfareMgrId;
    /**
     * 奖品名称
     */
    private String welfareName;
    /**
     * 奖品类型(游戏币10 vip试用20 京东卡30)
     */
    private int welfareType;
    /**
     * 奖品数量(单个奖品上限)
     */
    private int AwardCount;
    /**
     * 奖品值
     */
    private int welfareValue;
    /**
     * 奖品概率 (10代表10%)
     */
    private int AwardPct;
    /**
     * 子概率-A类概率
     */
    private int APct;
    /**
     * 子概率-B类概率
     */
    private int BPct;
    /**
     * 子概率-C类概率
     */
    private int CPct;
    /**
     * 子概率-D类概率
     */
    private int DPct;
    /**
     * 奖品剩余库存
     */
    private int remainderAmount;
    /**
     * 奖品配置库存
     */
    private int totalAmount;

}
/**
     * @Author: yansf
     * @Description:userType 1-A类人 2-B 5-C 7-D
     * @Date: 11:28 AM 2019/9/5
     * @Modified By:
     */
    public RewardDto lottery1(int userId, boolean isVip, int userType) {
        RewardDto dto = null;
        RewardDto dto1 = null;
        //获取奖品配置信息
        List<RewardDto> list = welfareMapper.getRewardPctList();
        if (dto == null) {
            OptionalInt s = list.stream().filter(e -> e.getWelfareType() == 10).mapToInt(RewardDto::getWelfareValue).min();
            dto1 = list.stream().filter(e -> e.getWelfareValue() == s.getAsInt()).findAny().orElse(null);
        }
        //移除库存为0的奖品
        list.removeIf(e -> e.getRemainderAmount() == 0);
        var firstReward = welfareMapper.getWelfareReceiveRecord(userId, null, null);
        //近一个月内是否中奖过vip试用,不再抽中vip
        var vipTrial = welfareMapper.getvipTrialRecord(userId);
        //如果已经是vip,则不可抽vip
        if (isVip || vipTrial > 0) {
            list.removeIf(e -> e.getWelfareType() == 20);
        }
        //如果活动间第一次抽奖,中最小的奖的概率为0
        if (firstReward <= 0 && (list.size() >= 2)) {
            //移除最小奖的配置
            OptionalInt s = list.stream().filter(e -> e.getWelfareType() == 10).mapToInt(RewardDto::getWelfareValue).min();
            list.removeIf(e -> e.getWelfareValue() == s.getAsInt() && e.getWelfareType() == 10);
        }
        if (list != null && list.size() > 0) {
            //总的概率区间
            float totalPro = 0f;
            //存储每个奖品新的概率区间
            List<Float> proSection = new ArrayList<Float>();
            DecimalFormat df = new DecimalFormat("######0.00");
            int random = -1;
            try {
                //计算总权重
                double sumWeight = 0;
                for (RewardDto award : list) {
                    if (userType == 1) {
                        sumWeight += award.getAPct();
                    } else if (userType == 2) {
                        sumWeight += award.getBPct();
                    } else if (userType == 5) {
                        sumWeight += award.getCPct();
                    } else if (userType == 7) {
                        sumWeight += award.getDPct();
                    }
                }
                //产生随机数
                double randomNumber;
                randomNumber = Math.random();
                //根据随机数在所有奖品分布的区域并确定所抽奖品
                double d1 = 0;
                double d2 = 0;
                for (int i = 0; i < list.size(); i++) {
                    if (userType == 1) {
                        d2 += Double.parseDouble(String.valueOf(list.get(i).getAPct())) / sumWeight;
                        if (i == 0) {
                            d1 = 0;
                        } else {
                            d1 += Double.parseDouble(String.valueOf(list.get(i - 1).getAPct())) / sumWeight;
                        }
                    } else if (userType == 2) {
                        d2 += Double.parseDouble(String.valueOf(list.get(i).getBPct())) / sumWeight;
                        if (i == 0) {
                            d1 = 0;
                        } else {
                            d1 += Double.parseDouble(String.valueOf(list.get(i - 1).getBPct())) / sumWeight;
                        }
                    } else if (userType == 5) {
                        d2 += Double.parseDouble(String.valueOf(list.get(i).getCPct())) / sumWeight;
                        if (i == 0) {
                            d1 = 0;
                        } else {
                            d1 += Double.parseDouble(String.valueOf(list.get(i - 1).getCPct())) / sumWeight;
                        }
                    } else if (userType == 7) {
                        d2 += Double.parseDouble(String.valueOf(list.get(i).getDPct())) / sumWeight;
                        if (i == 0) {
                            d1 = 0;
                        } else {
                            d1 += Double.parseDouble(String.valueOf(list.get(i - 1).getDPct())) / sumWeight;
                        }
                    }
                    if (randomNumber >= d1 && randomNumber <= d2) {
                        random = i;
                        break;
                    }
                }
            } catch (Exception e) {
                System.out.println("生成抽奖随机数出错,出错原因:" + e.getMessage());
//                throw e;
            }
            if (random != -1) {
                dto = list.get(random);
            }
        }
        if (dto == null) {
            dto = dto1;
        }
        return dto;
    }
    /**
     * @Author: yansf
     * @Description:抽奖测试
     * @Date: 3:35 PM 2019/8/19
     * @Modified By:
     */
    @GetMapping(value = "lottery")
    public ResponseUtil lottery(int userId, boolean isVip, int userType) {
        int coin = 0;
        int vip = 0;
        int jd = 0;
        RewardDto result = new RewardDto();
        List<RewardDto> list = new ArrayList();
        System.out.println("抽奖开始");
        for (int i = 0; i < 1000; i++) {
            result = welfareService.lottery(userId, isVip, userType);
            if (result.getWelfareType() == 10) {
                coin += 1;
            } else if (result.getWelfareType() == 20) {
                vip += 1;
            } else if (result.getWelfareType() == 30) {
                jd += 1;
            }
            list.add(result);
        }
        Map<String, List<RewardDto>> count = list.stream().collect(Collectors.groupingBy(RewardDto::getWelfareName));
                if (result != null) {
            return ResponseUtil.response(200, "游戏币:" + coin + ",vip:" + vip + ",京东卡:" + jd, count);
        } else {
            return ResponseUtil.response(500, "未中奖", count);
        }
    }

此处循环1000次,使用非vipD类人做一下测试,结果如下图

概率抽奖其实很简单,如果又要分奖品概率,又要根据不同人设置不同的概率,那就比重相乘然后相加,举个简单的例子:

//计算总权重
                double sumWeight = 0;
                for (RewardDto award : list) {
                    if (userType == 1) {
                //此处奖品概率*不同人抽到该奖品的概率
                        sumWeight += award.getAPct()*avard.getPct();
    }
}
for (int i = 0; i < list.size(); i++) {
                    if (userType == 1) {
//概率相乘
                        d2 += Double.parseDouble(String.valueOf(list.get(i).getAPct()*list.get(i).getPct())) / sumWeight;
                        if (i == 0) {
                            d1 = 0;
                        } else {
                            d1 += Double.parseDouble(String.valueOf(list.get(i - 1).getAPct()*list.get(i).getPct())) / sumWeight;
                        }
                    }

看到这,你应该学会了吧???

(不得不diss下,多数抽奖活动大奖概率设置的很低甚至为0,大奖可谓是可望不可及,所以还是好好工作比较靠谱,写bug,找bug,改bug    ???emm~)

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值