php实现概率性随机抽奖代码


Posted in PHP onJanuary 02, 2016

1、初始数据:

权重越大,抽取的几率越高
[奖品1, 权重 5], [ 奖品2, 权重6], [ 奖品3, 权重 7], [ 奖品4, 权重2]

2、处理步骤:

1)N = 5 + 6 + 7 + 2 = 20
2)然后取1-N的随机数M
3)界定各 奖品的权重范围值 奖品 1 : 1-5 ; 奖品2 : 6-11; 奖品3: 12-18; 奖品4: 19-20
4) 如果M在某个奖品的权重范围值内,标识这个奖品被抽取到

<?php
/**
 * 奖品
 */
class Prize {
  # ID
  public $id = null;
  # 权重
  public $weight = null;
  # 奖品名
  public $name = null;
 
  # 权重范围区间起始值
  protected $start = 0;
  # 权重范围区间结束值
  protected $end = 0;
 
  public function __construct($id, $weight, $name) {
    if (!$id) {
      throw new Exception('奖品ID为空.');
    }
    $this->id = $id;
    $this->weight = $weight ? $weight : 0;
    $this->name = $name ? $name : '随机奖品' . $id;
  }
 
  # id
  public function getId() {
    return $this->id;
  }
 
  # 权重
  public function getWeight() {
    return $this->weight;
  }
 
  # 设置权重范围区间
  public function setRange($start, $end) {
    $this->start = $start;
    $this->end = $end;
  }
 
  # 判断随机数是否在权重范围区间
  public function inRange($num) {
    return ($num >= $this->start) && ($num <= $this->end);
  }
}
 
/**
 * 奖品池
 */
class PrizePoll implements IteratorAggregate, Countable {
  # 奖品集
  protected $items = array();
 
  # 加入奖品
  public function addItem(Prize $item) {
    $this->items[$item->getId()] = $item;
    return $this;
  }
 
  # 删除奖品
  public function removeItem($itemId) {
    if (isset($this->items[$itemId])) {
      unset($this->items[$itemId]);
    }
    return $this;
  }
 
  # 更新奖品
  public function updateItem(Prize $item) {
    if (isset($this->items[$item->getId()])) {
      $this->items[$item->getId()] = $item;
    }
    return $this;
  }
 
  # 获取所有奖品
  public function getItems() {
    return $this->items;
  }
 
  # 所有所有可用奖品(如果权重为0,说明这个奖品永远不可能抽到)
  public function getVisibleItems() {
    $items = array();
    foreach ($this->items as $item) {
      if ($item->getWeight()) {
        $items[$item->getId()] = $item;
      }
    }
    return $items;
  }
 
  # Countable::count
  public function count() {
    return count($this->items);
  }
 
  # IteratorAggregate::getIterator()
  public function getIterator() {
    return new ArrayIterator($this->items);
  }
}
 
/**
 * 简单的抽奖类
 */
class SimpleTurn {
  # 奖池
  protected $poll = null;
   
  public function __construct(PrizePoll $poll) {
    if ($poll) {
      $this->setPoll($poll);
    }
  }
 
  # 抽奖
  public function run(PrizePoll $poll) {
    $poll = $poll ? $poll : $this->poll;
    if ( ! $poll) {
      throw new Exception('奖池未初始化');
    }
 
    if ($poll->count() <= 0) {
      throw new Exception('奖池为空');
    }
 
    $items = $poll->getVisibleItems();
    if (count($items) <= 0) {
      throw new Exception('奖池为空');
    }
 
    $sum = 0;
    foreach ($items as $item) {
      $start = $sum + 1;
      $sum += $item->getWeight();
      $end = $sum;
 
      # 设置奖品的权重范围区间
      $item->setRange($start, $end);
    }
 
    # 随机数
    $rand = $this->getRandNum(1, $sum);
 
    # 区间段判断
    foreach ($items as $item) {
      if ($item->inRange($rand)) {
        return $item;
      }
    }
    return null;
  }
 
  # 获取随机数
  public function getRandNum($min, $max) {
    return mt_rand($min ? $min : 1, $max);
  }
 
  # 设置奖池
  public function setPoll(PrizePoll $poll) {
    $this->poll = $poll;
  }
}
 
# 示例
try {
  $prizePoll = new PrizePoll();
  $prizePoll->addItem(new Prize(1, 5))
    ->addItem(new Prize(2, 6))
    ->addItem(new Prize(3, 7))
    ->addItem(new Prize(4, 2));
 
  $turn = new SimpleTurn($prizePoll);
  $prize = $turn->run();
  var_dump($prize);
} catch (Exception $e) {
  print_r($e);
}
PHP 相关文章推荐
PHP 简易输出CSV表格文件的方法详解
Jun 20 PHP
解析array splice的移除数组中指定键的值,返回一个新的数组
Jul 02 PHP
PHP中的Memcache详解
Apr 05 PHP
PHP取余函数介绍MOD(x,y)与x%y
May 15 PHP
PHP实现的简易版图片相似度比较
Jan 07 PHP
php实现Mysql简易操作类
Oct 11 PHP
php实现CSV文件导入和导出
Oct 24 PHP
php获取图片信息的方法详解
Dec 10 PHP
Yii2.0预定义的别名功能小结
Jul 04 PHP
PHP删除二维数组中相同元素及数组重复值的方法示例
May 05 PHP
PHP实现的抓取小说网站内容功能示例
Jun 27 PHP
tp5框架前台无限极导航菜单类实现方法分析
Mar 29 PHP
php实现给一张图片加上水印效果
Jan 02 #PHP
前端必学之PHP语法基础
Jan 01 #PHP
WordPress中登陆后关闭登陆页面及设置用户不可见栏目
Dec 31 #PHP
WordPress中获取指定分类及其子分类下的文章数目
Dec 31 #PHP
Swoole-1.7.22 版本已发布,修复PHP7相关问题
Dec 31 #PHP
WordPress中给媒体文件添加分类和标签的PHP功能实现
Dec 31 #PHP
简单了解将WordPress中的工具栏移到底部的小技巧
Dec 31 #PHP
You might like
刚才在简化php的库,结果发现很多东西
2006/12/31 PHP
php使用websocket示例详解
2014/03/12 PHP
php计算税后工资的方法
2015/07/28 PHP
学习PHP的数组总结【经验】
2016/05/05 PHP
PHP实现自动发送邮件功能代码(qq 邮箱)
2017/08/18 PHP
php 读取文件夹下所有图片、文件的实例
2018/10/17 PHP
获取JavaScript用户自定义类的类名称的代码
2007/03/08 Javascript
javascript 字符串连接的性能问题(多浏览器)
2008/11/18 Javascript
Javascript创建Silverlight Plugin以及自定义nonSilverlight和lowSilverlight样式
2010/06/28 Javascript
关于javascript中的typeof和instanceof介绍
2012/12/04 Javascript
javascript返回顶部效果(自写代码)
2013/01/06 Javascript
控制页面按钮在后台执行期间不重复提交的JS方法
2013/06/24 Javascript
JS 按钮点击触发(兼容IE、火狐)
2013/08/07 Javascript
基于JavaScript实现轮播图代码
2016/07/14 Javascript
浅析$(function) ready和onload 的区别
2016/09/03 Javascript
jQuery实现文字自动横移
2017/01/08 Javascript
Angular2平滑升级到Angular4的步骤详解
2017/03/29 Javascript
vue组件如何被其他项目引用
2017/04/13 Javascript
vue升级之路之vue-router的使用教程
2018/08/14 Javascript
Angular Excel 导入与导出的实现代码
2019/04/17 Javascript
[01:05:29]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster BO3 第二场 1月24日
2021/03/11 DOTA
Python决策树分类算法学习
2017/12/22 Python
python线程池threadpool实现篇
2018/04/27 Python
便捷提取python导入包的属性方法
2018/10/15 Python
Python批量删除只保留最近几天table的代码实例
2019/04/01 Python
numpy.where() 用法详解
2019/05/27 Python
python 实现手机自动拨打电话的方法(通话压力测试)
2019/08/08 Python
使用Python进行防病毒免杀解析
2019/12/13 Python
判断Threading.start新线程是否执行完毕的实例
2020/05/02 Python
Becextech新西兰:数码单反相机和手机在线商店
2018/04/27 全球购物
PHP如何调用MYSQL存储过程
2014/05/30 面试题
社区工作者先进事迹
2014/01/18 职场文书
大学生创业事迹材料
2014/12/30 职场文书
Python+Appium实现自动抢微信红包
2021/05/21 Python
Python使用Kubernetes API访问集群
2021/05/30 Python
Android中View.post和Handler.post的关系
2022/06/05 Java/Android