天天福利抽奖-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~)

源码下载地址: https://pan.quark.cn/s/a4b39357ea24 "ZV-1 高级功能使用手册 用户详细指南" 此文档将全面阐述 Sony ZV-1 相机的进阶功能及其操作方法,为用户呈现详尽的操作指引和配置范例。 一、使用指南与摄影技巧 * 本手册旨在协助用户迅速掌握 Sony ZV-1 相机的使用方法 * 提供摄影技巧与操作方法等实用信息 * 可在线查阅配件兼容性详情及配置范例 二、基础操作 * 通过控制轮和菜单选项将常用功能分配至按键 * 探索功能按钮(Fn)与自定义按键的应用 * 学习显示(DISP)按钮的操作方法 * 明确拍摄及浏览时图标与提示的展示方式 三、电源与存储介质 * 查询电池续航时间及可拍摄照片数量 * 注意电池使用规范及更换事项 * 掌握存储卡插入方法及注意事项 四、语言与时间设定 * 说明语言及时间配置流程 * 熟悉相机内部功能说明和拍摄模式选择 五、拍摄模式与对焦系统 * 探究拍摄模式和对焦模式的选择 * 了解自动对焦、人脸/眼部自动对焦设置及主体追踪功能 * 掌握手动对焦和直接手动对焦(DMF)操作 * 理解峰值对焦设置及拍摄模式选择 六、触控操作与视频录制 * 阐明触控功能特性及触控快门使用 * 学习触控对焦与触控追踪功能 * 掌握视频录制模式及高帧速率(HFR)设置 * 了解智能自动与场景识别程序 七、曝光调整与白平衡 * 熟悉曝光模式和白平衡配置 * 探究ISO感光度调节与变焦功能 * 学习自动HDR及动态范围优化(DRO)技术 八、图像处理与编辑功能 * 明确图像质量与文件格式选项 * 了解美肤效果与自动构图功能 * 掌握色彩空间选择与快门速度设置 * 探索降噪处理及高ISO降噪技术 九、闪光灯与人脸识...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值