java 抽奖_JAVA基于权重的抽奖
https://blog.csdn.net/huyuyang6688/article/details/50480687
如有4个元素A、B、C、D,权重分别为1、2、3、4,随机结果中A:B:C:D的比例要为1:2:3:4。
总体思路:累加每个元素的权重A(1)-B(3)-C(6)-D(10),则4个元素的的权重管辖区间分别为[0,1)、[1,3)、[3,6)、[6,10)。
然后随机出一个[0,10)之间的随机数。落在哪个区间,则该区间之后的元素即为按权重命中的元素。
实现方法:
利用TreeMap,则构造出的一个树为:
B(3)
/ \
/ \
A(1) D(10)
/
/
C(6)
然后,利用treemap.tailMap().firstKey()即可找到目标元素。
(3落在70%权重,7落在70-95的权重,10落在95-100的权重)
https://www.bbsmax.com/A/LPdo4pk2z3/
三、依赖不可控的物理随机数
什么意思呢,先看个图,看完你就知道了
明白了吧,呵呵,这就是现如今灰常流行的一种抽奖算法,绝对公平、绝对透明、绝对木有暗箱(除非偷偷给你换了抽奖号码)!但是这种方法唯一的缺点是无法实时抽奖,只能事后抽奖。也就是只能拿个抽奖号等着上帝的眷顾,阿门。。。
例如游戏中打败一个boss,会掉落下面其中一个物品,而每个物品都有一定概率: 1. 靴子 20% 2. 披风 25% 3. 饰品 10% 4. 双手剑 5% 5. 金币袋 40% 现在的问题就是如何根据概率掉落一个物品给玩家。
一. 一般算法:生成一个列表,分成几个区间,例如列表长度100,1-20是靴子的区间,21-45是披风的区间等,然后随机从100取出一个数,看落在哪个区间。算法时间复杂度:预处理O(MN),随机数生成O(1),空间复杂度O(MN),其中N代表物品种类,M则由最低概率决定。
二、离散算法:也就是上面的改进,竟然1-20都是靴子,21-45都是披风,那抽象成小于等于20的是靴子,大于20且小于等于45是披风,就变成几个点[20,45,55,60,100],然后也是从1到99随机取一个数R,按顺序在这些点进行比较,知道找到第一个比R大的数的下标,比一般算法减少占用空间,还可以采用二分法找出R,这样,预处理O(N),随机数生成O(logN),空间复杂度O(N)。 请点击查看详细:http://www.cnblogs.com/miloyip/archive/2010/04/21/1717109.html
三、Alias Method Alias Method就不太好理解,实现很巧妙,推荐先看看这篇文章:http://www.keithschwarz.com/darts-dice-coins/ 大致意思:把N种可能性拼装成一个方形(整体),分成N列,每列高度为1且最多两种可能性,可能性抽象为某种颜色,即每列最多有两种颜色,且第n列中必有第n种可能性,这里将第n种可能性称为原色。 想象抛出一个硬币,会落在其中一列,并且是落在列上的一种颜色。这样就得到两个数组:一个记录落在原色的概率是多少,记为Prob数组,另一个记录列上非原色的颜色名称,记为Alias数组,若该列只有原色则记为null。
之前的例子,为了便于演示换成分数
1. 靴子 20% -> 1/4
2. 披风 25% -> 1/5
3. 饰品 10% -> 1/10
4. 双手剑 5% -> 1/20
5. 金币袋 40% -> 2/5
然后每个都乘以5(使每列高度为1),再拼凑成方形
拼凑原则:
每次都从大于等于1的方块分出一小块,与小于1的方块合成高度为1
由上图方形可得到两个数组: Prob: [3/4, 1/4, 1/2, 1/4, 1] Alias: [4, 4, 0, 1, null] (记录非原色的下标)
之后就根据Prob和Alias获取其中一个物品 随机产生一列C,再随机产生一个数R,通过与Prob[C]比较,R较大则返回C,反之返回Alias[C]。
Alias Method 复杂度:预处理O(NlogN),随机数生成O(1),空间复杂度O(2N)
https://www.cnblogs.com/younggun/p/3249772.html
简介
最近闲的无聊,将以前做的一个微信抽奖小demo拿来分享一下,以便加深印象。
效果图
1.gif
业务要求
在一个奖池中放一堆奖品,分别给它们设置不同的数量,比如一等奖A10个,二等奖B,30个,三等奖C10个,然后设置参与人数C人
条件是:
当奖品数大于参与人数,100%中奖。
当奖品A发放完是,不能被抽中。
当奖品发放完毕是,该抽奖活动自动下架。
同一个用户如果中奖了,将不能继续参与该活动。
这里只讨论下其中的核心算法的设计及一个示例函数,算法之外的系统控制暂不提及。
实现抽奖的方法应该有很多,没有仔细去考察和搜索那些非常复杂的算法,这里仅做了一个简单的假设,并在此基础上推出后面所有的控制逻辑。
实现方法
java核心抽奖代码如下:
public classLotteryUtil {/***
*@paramorignalRates 传人每一个奖品概率的集合,(集合的第一个参数是0.0 表示百分比中奖)
*@return
*/
public static int lottery(ListorignalRates) {if (orignalRates == null ||orignalRates.isEmpty()) {return -1;
}int size =orignalRates.size();//计算总概率,这样可以保证不一定总概率是1
double sumRate =0d;for (doublerate : orignalRates) {
sumRate+=rate;
}//计算每个物品在总概率的基础下的概率情况
List sortOrignalRates = new ArrayList(size);
Double tempSumRate=0d;/*遍历奖品概率的集合,计算每一个奖品的中间区间*/
for (doublerate : orignalRates) {
tempSumRate+=rate;
sortOrignalRates.add(tempSumRate/sumRate);
}//根据区块值来获取抽取到的物品索引
double nextDouble =Math.random();
sortOrignalRates.add(nextDouble);
Collections.sort(sortOrignalRates);returnsortOrignalRates.indexOf(nextDouble);
}
}
抽奖的业务逻辑代码如下
/*awardItems获取奖品的一个集合*/
if (activityUserDao.getCountByOpenId(Award.WHEEL_AWARD_TYPE, wid, open_id) <= 0) {/*awardItems获取奖品的一个集合*/List awardItems =awardDao.getByActivity(aw.getWheel_id(), Award.WHEEL_AWARD_TYPE);/*lotterys存放每一个奖品的中奖概率集合*/List lotterys = new ArrayList();/*获取总的奖品数量*/
int count = 0;for(Award a : awardItems) {
count+=a.getProvide_count();
}if (aw.getPeople_count() <=count) {
lotterys.add(0.0); //100%中奖
} else{/*预计参与人数减去奖品数 除以参与人数 = 未中奖概率*/lotterys.add((double) (aw.getPeople_count() - count) / (double) aw.getPeople_count());
}/*遍历奖品集合,获取每一个奖品中奖概率*/
for(Award a : awardItems) {if (a.getOver_count() > 0) {
lotterys.add((double) a.getProvide_count() / (double) aw.getPeople_count());
}else{
lotterys.add(0.0);
}
}//计算中奖概率
int index =LotteryUtil.lottery(lotterys);if (index > 0) {//中奖
Award a = awardItems.get(index - 1);long key = Math.round(Math.random() * (999999 - 100000) + 100000); //6位数中奖序列号//修改商品剩余数量 + 记录序列号
if (awardDao.doLowerOverCount(a.getAward_id()) > 0
&& activityUserDao.doInsert(new ActivityUser(aw.getPublic_id(), Award.WHEEL_AWARD_TYPE, wid, a.getAward_id(), key + "", open_id)) > 0) {
rb.setCode(index);
rb.setData(key);
rb.setMessage(a.getAward_name());
}else{
rb.setCode(0);
}
}//抽奖记录
activityRecordDao.doInsert(new ActivityRecord(open_id, Award.WHEEL_AWARD_TYPE, wid, request.getRemoteAddr()));
前端抽奖工具类
/**
* 注意:本插件运用了rem屏幕适配方案,一律采用rem作为单位,若项目中不是采用这种方案的,此段代码不会影响功能使用,仅会影响控件样式*/(function(win, doc, $) {var defaultOpt ={
rotateNum:5, //转盘转动圈数
body: "", //大转盘整体的选择符或zepto对象
disabledHandler:function() {}, //禁止抽奖时回调
clickCallback:function() {}, //点击抽奖按钮,再次回调中实现访问后台获取抽奖结果,拿到抽奖结果后显示抽奖画面
KinerLotteryHandler:function(deg) {} //抽奖结束回调
};functionKinerLottery(opts) {this.opts = $.extend(true, {}, defaultOpt, opts);this.doing = false;this.init();
}
KinerLottery.prototype.setOpts= function(opts) {this.opts = $.extend(true, {}, defaultOpt, opts);this.init();
};
KinerLottery.prototype.init= function() {var self = this;this.defNum = this.opts.rotateNum * 360; //转盘需要转动的角度
//console.log(this.defNum);
//alert(this.defNum);
//点击抽奖
$('#box').on('click', ".KinerLotteryBtn", function() {if($(this).hasClass('start') && !self.doing) {
self.opts.clickCallback.call(self);
}else{var key = $(this).hasClass('no_start') ? "noStart" : $(this).hasClass('completed') ? "completed" : "illegal";
self.opts.disabledHandler(key);
}
});
$(this.opts.body).find('.KinerLotteryContent').get(0).addEventListener('webkitTransitionEnd', function() {
self.doing= false;var deg = $(self.opts.body).attr('data-deg');if(self.opts.direction == 0) {
$(self.opts.body).attr('data-deg', 360 -deg);
$(self.opts.body).find('.KinerLotteryContent').css({'-webkit-transition': 'none','transition': 'none','-webkit-transform': 'rotate(' + (deg) + 'deg)','transform': 'rotate(' + (deg) + 'deg)'});
self.opts.KinerLotteryHandler(360 -deg);
}else{
$(self.opts.body).attr('data-deg', deg);
$(self.opts.body).find('.KinerLotteryContent').css({'-webkit-transition': 'none','transition': 'none','-webkit-transform': 'rotate(' + (-deg) + 'deg)','transform': 'rotate(' + (-deg) + 'deg)'});
self.opts.KinerLotteryHandler(deg);
}
});
};
KinerLottery.prototype.goKinerLottery= function(_deg) {if(this.doing) {return;
}var deg = _deg + this.defNum;var realDeg = this.opts.direction == 0 ? deg : -deg;this.doing = true;
$(this.opts.body).find('.KinerLotteryBtn').addClass('doing');
$(this.opts.body).find('.KinerLotteryContent').css({'-webkit-transition': 'all 5s','transition': 'all 5s','-webkit-transform': 'rotate(' + (realDeg) + 'deg)','transform': 'rotate(' + (realDeg) + 'deg)'});
$(this.opts.body).attr('data-deg', _deg);
};
win.KinerLottery=KinerLottery;
})(window, document, $);
前端js调用抽奖类
/**
* @author wjb
* @description
* @version 1.0.0 2017/2/11*/app.controller("wheelOneController", ['$scope', '$stateParams', '$neu_', 'awardService', '$filter', '$timeout', 'util.alert', 'cfg', 'wxService', function($scope, $stateParams, $neu_, awardService, $filter, $timeout, alert, cfg, wxService) {/*中奖开始时间*/$scope.wheelStatu={
start:true,
noStart:false,
completed:false}/*错误信息提示*/$scope.errorMsg= "";/*定义奖品数据变量*/$scope.awards=[];/*活动的id和活动的微信公众号ID*/
var activity_id = $neu_.isEmpty($stateParams.activity_id) ? 1: $stateParams.activity_id;var public_id = $neu_.isEmpty($stateParams.public_id) ? 1: $stateParams.public_id;var open_id = $neu_.isEmpty($stateParams.open_id) ?cfg.openId : $stateParams.open_id;
cfg.public_id=public_id;
cfg.open_id=open_id;
cfg.activity_id=activity_id;//alert(cfg.public_id+"=="+cfg.activity_id+"=="+cfg.open_id );
/*获取活动信息*/wxService.setConfig();
awardService.getWheelInfo(activity_id, public_id).then(function(res) {//console.dir(res)
if(res.success) {
$scope.wheelStatu.start= true;
}else{if(res.code == 1 || res.code == 3) {
$scope.wheelStatu.noStart= true;
}else if(res.code == 2) {
$scope.wheelStatu.completed= true;
}
$scope.errorMsg=res.msg;
}
$scope.wheelInfo=res.data;
});
awardService.getAwards(activity_id, public_id).then(function(res) {
$scope.awards=res.data;
});/*奖品预览*/
var result =[];
$scope.showPic= function(pic) {if(result.length == 0) {
$neu_.each($scope.awards,function(item) {
result.push(cfg.resourcePath+item.img);
});
}
wxService.previewImage(cfg.resourcePath+pic, result);
}/*中奖结果集*/$scope.result=[];
$scope.user={
user_name:'',
phone:'',
activity_id: activity_id,
user_openid: open_id
};/**
* 提交中奖人信息*/$scope.submit= function() {
$(".actBody_close").click();
$scope.isLoading= true;
awardService.updateLotteryUser($scope.user).then(function(res) {
$scope.isLoading= false;if(res.success) {
alert('您的中奖信息已备案,我们的客服人员稍后会联系您,如何领取奖品');
}else{
alert('提交失败');
}
})//alert('哈哈上当了吧^_^_^_^')
}
$scope.load= function() {
$timeout(function() {
ActBounced();
$("#layer").hide();newKinerLottery({
rotateNum:5, //转盘转动圈数
body: "#box", //大转盘整体的选择符或zepto对象
direction: 0, //0为顺时针转动,1为逆时针转动
disabledHandler: function(key) {switch(key) {case "noStart":
$scope.$apply(function() {
alert($scope.errorMsg);
});break;case "completed":
$scope.$apply(function() {
alert($scope.errorMsg);
});break;
}
},//禁止抽奖时回调
clickCallback: function() {var this_ = this;//此处访问接口获取奖品
$scope.isLoading = true;
awardService.startAweel(activity_id, open_id).then(function(res) {
$scope.isLoading= false;if(isDebug){
this_.goKinerLottery(0);
}else{if(res.success) {var index = cfg.isDebug ? Math.floor(Math.random() * 5) : res.code;
$scope.result= $filter('awardToAngle')(index, $scope.awards);if(index == 0) {
this_.opts.disabledHandler("noStart");
}else{
this_.goKinerLottery($scope.result[1]);
}
}else{
alert(res.msg);
}
}
})
},//点击抽奖按钮,再次回调中实现访问后台获取抽奖结果,拿到抽奖结果后显示抽奖画面
KinerLotteryHandler: function(deg) {
$("#smallActAdv").click();
}
});
},500);/*分享授权的地址*/$timeout(function(){var share ={shareUrl:"weixin/oauth.html?isBase=true&type=6&a_id="+activity_id+"&p_id="+public_id+"&appid="+cfg.appId};
wxService.onMenuShareAppMessage(share);
},3000)
}
}])
以上是抽奖的主要代码
java 抽奖_JAVA基于权重的抽奖相关推荐
- JAVA基于权重的抽奖
https://blog.csdn.net/huyuyang6688/article/details/50480687 如有4个元素A.B.C.D,权重分别为1.2.3.4,随机结果中A:B:C:D的 ...
- 砸金蛋java代码_java实现砸金蛋抽奖功能
本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下 代码如下 需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖10% 三等奖18% 四等奖70%. 累计砸第n次时必抽 ...
- 数字识别java开源_Java基于opencv实现图像数字识别(三)—灰度化和二值化
Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...
- socket java 客户端_Java基于socket实现的客户端和服务端通信功能完整实例
本文实例讲述了Java基于socket实现的客户端和服务端通信功能.分享给大家供大家参考,具体如下: 以下代码参考马士兵的聊天项目,先运行ChatServer.java实现端口监听,然后再运行Chat ...
- 抽奖功能java开发_基于Java实现抽奖系统
摘要:这篇Java开发技术栏目下的"基于Java实现抽奖系统",介绍的技术点是"抽奖系统.Java.抽奖.基于.系统.实现",希望对大家开发技术学习和问题解决有 ...
- java 抽奖系统源码_基于jsp的抽奖系统-JavaEE实现抽奖系统 - java项目源码
基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的抽奖系统, 该项目可用各类java课程设计大作业中, 抽奖系统的系统架构分为前后台两部分, 最终实现在线上进行抽奖 ...
- java抽奖_Java实现抽奖功能
需求简介 新项目有一个类似王者荣耀抽奖的功能:抽取花费积分,积累幸运值,每阶段幸运值可以抽取到不同的奖品,幸运值集满时,必得稀有道具 功能实现预期:建立一个抽奖池(抽奖池级别根据type区分),奖品在 ...
- java用map集合实现随机抽奖源码
import java.util.HashMap; import java.util.Random;//用map实现抽奖 public class demo3 {public static void ...
- 基于vue2.0+ 抽奖项目
前言 临近年关抽奖活动,基于vue2.0+开发的抽奖项目. 便于查看效果,贴上相关地址: 在线示例地址:快速访问 github地址:查看源码 简介 基于vue.js抽奖项目,截屏保存每次抽奖图片至本地 ...
最新文章
- 有关Expander组件的研究——Silverlight学习笔记[33]
- Invalid icon file 原因
- Tensorflow官方文档中文版——第一章
- 【2017-04--28】Winform中ListView控件
- 云原生,开发者的黄金时代
- 两个有序数组的中位数—leetcode4
- oracle 数据操作的相关参数
- React v16版本 源码解读
- 突然不能访问服务器未响应,windows 访问不服务器未响应
- C语言中的字符串函数
- php dede 发布时间_DedeCMS发布时间显示多少天月年前
- abaqus结构工程分析及实例详解pdf_“结构非线性、材料拟合、冲击碰撞、钣金/金属成形、顺序耦合、多物理场、有/非参优化”专题...
- 第一次在CSDN上写博客
- Python基于HRHet的跌倒检测系统(源码&教程)
- 基于Transformer的NLP智能对话机器人实战课程(第十六章、第十七章、第十八章)
- 关于百度OCR和EasyOCR的研究记录
- html5弹页面腮红,腮红总是打的很奇怪 这里有画腮红的小技巧
- 【Oracle】userenv()函数介绍分析
- oracle sql 不等 优化6,oracle sql 优化(三)
- 哲学家就餐问题python解决_关于哲学家就餐问题的分析代码.
热门文章
- 计算机文档排版软件,正式文档排版格式计算机软件及应用IT计算机专业资料-正式文档排.pdf...
- 广告、广告联盟、异业联盟及广告接入介绍
- GCJ经纬度(腾讯、高德)转WGS84经纬度EXCEL算法
- 统计力学练习: Ising模型的平均场解以及严格求解
- 捕捉RAISERROR异常
- 计算机的优缺点英语作文100词,跪求一篇英语作文 题目:论计算机的优缺点
- 996 有加班费,那加班是否合算?
- Vmware Ubuntu虚拟机之间传文件,Ubuntu ftp的相关设置
- nbtscan局域网内查找病毒主机
- 有声书制作是什么?有声书和电子书的区别是什么?