^_^内容原创,禁止转载


 假设配置如下:

 local reward_pool = {
     {weight = , item = {, num = }},
     {weight = , item = {, num = }},
     {weight = , item = {, num = }},
     {weight = , item = {, num = }},
     {weight = , item = {, num = }},
     {weight = , item = {, num = }},
 }

1.顺序查找,预处理时间复杂度O(n),抽奖最坏情况O(n)

 --预处理
 local N = #reward_pool

 for _, v in ipairs(reward_pool) do
     total_weight = total_weight + v.weight
 end

 --实现
 local rand_weight = math.random(total_weight)
 local reward_index

 for k, v in ipairs(reward_pool) do
     _total_weight = _total_weight + v.weight
     if _total_weight >= rand_weight then
         reward_index = k
         break
     end
 end

2.按照离散思路进行分割,二分查找,预处理时间复杂度O(n),抽奖最坏情况O(logn)

 --预处理
 local N = #reward_pool

 for _, v in ipairs(reward_pool) do
     com_weight = com_weight + v.weight
     v.weight = com_weight
 end

 --实现
 , #reward_pool
 while right >= left then
     )
     local mid_weight = reward_pool[mid].weight
     if value == mid_weight then
         right = right -
         break
     elseif value < mid_weight then
         right = mid -
     else
         left = mid +
     end
 end
 right = right +  --此时right为reward_pool中抽到的索引

这种方法在实际上是对第一种方法的优化,在大多数情况下都可以取代第一种方法,但取舍还要看实际情况,一个极端且明显的例子如下:

 local reward_pool = {
     {weight = , item = {, num = }}, {weight = , item = {, num = }},
     {weight = , item = {, num = }}, {weight = , item = {, num = }},
     {weight = , item = {, num = }}, {weight = , item = {, num = }},
     {weight = , item = {, num = }}, {weight = , item = {, num = }},
     {weight = , item = {, num = }}, {weight = , item = {, num = }},
 }

3.AliasMethod,个人实现的预处理O(3n),抽奖时间复杂度O(1),下面是实现过程,证明日后有时间再整理给出

 queue = {}

 function queue:new()
     , last = -}
     self.__index = self
     setmetatable(res, self)
     return res
 end

 function queue:push(value)
     self.last = self.last +
     self[self.last] = value
 end

 function queue:pop()
     local first = self.first
     if first > self.last then
         self.first =
         self.last = -
         return nil
     end
     local value = self[first]
     self[first] = nil
     self.first = self.first +
     return value
 end

 function queue:front()
     return self[self.first]
 end

 --预处理
 local N = #reward_pool

 for _, v in ipairs(reward_pool) do
     total_weight = total_weight + v.weight
 end

 local Prob = {}
 local Alias = {}
 local weightN_queue_L = queue:new()
 local weightN_queue_U = queue:new()
 for k, v in ipairs(reward_pool) do
     local weight_N = v.weight * N
     if weight_N == total_weight then
         Prob[k] = weight_N
     else
         local tb = {index = k, value = weight_N}
         local qu = weight_N > total_weight and weightN_queue_U or weightN_queue_L
         qu:push(tb)
     end
 end

 while true do
     local l_qu = weightN_queue_L:pop()
     if not l_qu then
         break
     end
     local u_qu = weightN_queue_U:front() --或直接pop,比total_weight大再push回去
     Prob[l_qu.index] = l_qu.value
     Alias[l_qu.index] = u_qu.index
     u_qu.value = u_qu.value + l_qu.value - total_weight
     if u_qu.value < total_weight then
         weightN_queue_U:pop()
         weightN_queue_L:push(u_qu)
     elseif u_qu.value == total_weight then
         weightN_queue_U:pop()
         Prob[u_qu.index] = total_weight
     end
 end
 weightN_queue_U = nil
 weightN_queue_L = nil

 --实现
 local n = math.random(N)
 local weight = math.random(total_weight)
 local reward_index = weight > Prob[n] and Alias[n] or n

lua实现游戏抽奖的几种方法的更多相关文章

  1. 【转载】解决繁体、日文游戏乱码的五种方法 转载自:http://tieba.baidu.com/p/488627981

    方法1:转换区域 开始——设置——控制面板——区域和语言选项——分别选择“高级”和“区域选项”标签——在其下拉框中都选择“日语”(或“日本”)(选项有点多,慢慢找)——重启后即可生效. *某影注:日语 ...

  2. Unity3d获取游戏对象的几种方法

    1.GameObject.Find() 通过场景里面的名子或者一个路径直接获取游戏对象. GameObject root = GameObject.Find("GameObject" ...

  3. 游戏对象消失三种方法的区别?(enabled/Destroy/active)

    gameObject.renderer.enabled=fasle是控制一个物体是否在屏幕上渲染或显示  而物体实际还是存在的 只是想当于隐身 而物体本身的碰撞体还依然存在的GameObject.De ...

  4. slua中,绑定lua文件到Monobehavior的一种方法

    slua本身并不提供如何把一个lua文件绑定到一个预制中,就像一个普通的继承自monobehavior的自定义脚本那样,而tolua的框架却采用了拙劣的做法: public class LuaBeha ...

  5. unity3d 游戏对象消失三种方法的区别(enabled/Destroy/active)

    gameObject.renderer.enabled //是控制一个物体是否在屏幕上渲染或显示 而物体实际还是存在的 只是想当于隐身 而物体本身的碰撞体还依然存在的 GameObject.Destr ...

  6. 【Cocos2d-x游戏开发】解决Cocos2d-x中文乱码的三种方法

    众所周知,Cocos2d-x是一款不错的开源引擎,但是在Cocos2d-x中直接使用中文是无法正确显示的.比如下面的情况: 解决这个问题常用的有三种方法:1.通过转换为UTF-8编码来显示.2.使用i ...

  7. C模块回调Lua函数的两种方法

    作者:ani_di 版权所有,转载务必保留此链接 http://blog.csdn.net/ani_di C模块回调Lua函数的两种方法 lua和C通过虚拟栈这种交互方式简单而又可靠,缺点就是C做栈平 ...

  8. [Unity3D]Unity3D游戏开发Lua随着游戏的债券(于)

    ---------------------------------------------------------------------------------------------------- ...

  9. lua中 table 重构index/pairs元方法优化table内存占用

    转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...

随机推荐

  1. sentry使用

    开篇-Sentry是什么 Sentry是开源错误跟踪,帮助开发人员实时监控和修复崩溃.不断重复.提高效率.改善用户体验. 这篇文章的作用 记录这篇文章是想分享一下,因为本人在配置时因为邮件服务花费了很 ...

  2. 15.自动部署web工程

    用maven自动部署web工程 在pom.xml中写入以下: <build> <!--最终名称,进入网页时有http://localhost:8080/xxx/--> < ...

  3. BZOJ 4472 salesman 题解

    题目 某售货员小T要到若干城镇去推销商品,由于该地区是交通不便的山区,任意两个城镇之间都只有唯一的可能经过其它城镇的路线.小T可以准确地估计出在每个城镇停留的净收益.这些净收益可能是负数,即推销商品的 ...

  4. 移动自动化appium(2)- Allure报告使用详解

    6 Allure报告 6.1 Allure介绍 Allure是一个独立的报告插件,生成美观易读的报告,比之前的html好看,目前支持的语言:Java.PHP.Ruby.Python.C#等 6.2 A ...

  5. WiX 自定义

    WiX 允许用户做一些自定义操作 用户界面向导 对于安装界面,用户可以用自己的位图.图标和许可证文本替换默认的.它们的路径存储在变量中,您可以在命令行或直接在源代码中指定这些变量: <WixVa ...

  6. JS 剑指Offer(一) 数组中的重复数字

    题目:在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中任意一个重复的数字. 分析: ...

  7. supervisor 的使用 (fastcgi管理)

    本文主要介绍 supervisor 对 fastcgi 进程的管理 fastcgi 进程的管理 在php 中,php-fpm 有主进程来管理和维护子进程的数量.但是并不是所有的服务都有类似的主进程来做 ...

  8. 从 Socket 编程谈谈 IO 模型(三)

    快过年啦,估计很多朋友已在摸鱼的路上.而我为了兄弟们年后的追逐,却在苦苦寻觅.规划,导致文章更新晚了些,各位猿粉谅解. 上期分享,我们结合新春送祝福的场景,通过一坨坨的代码让 BIO.NIO 编程过程 ...

  9. 使用 Nginx 实现 301 跳转至 https 的根域名

    基于 SEO 和安全性的考量,需要进行 301 跳转,以下使用 Nginx 作通用处理 实现结果 需要将以下地址都统一跳转到 https 的根域名 https://chanvinxiao.com ht ...

  10. 使用Azure Rest API获得Access Token介绍

    背景 本文主要介绍如何获取如何获取Azure Rest API的访问token,所采用的是v2.0版本的Microsoft标识平台,关于1.0和2.0的区别可以参考 https://docs.azur ...