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写的serv-u的web申请账号的程序
Oct 09 PHP
PHP5中使用DOM控制XML实现代码
May 07 PHP
探讨如何把session存入数据库
Jun 07 PHP
php中0,null,empty,空,false,字符串关系的详细介绍
Jun 20 PHP
PHP+memcache实现消息队列案例分享
May 21 PHP
PHP常用数组函数介绍
Jul 28 PHP
PHP中file_exists()判断中文文件名无效的解决方法
Nov 12 PHP
php提示Failed to write session data错误的解决方法
Dec 17 PHP
PHP基于Closure类创建匿名函数的方法详解
Aug 17 PHP
kindeditor 加入七牛云上传的实例讲解
Nov 12 PHP
php用户名的密码加密更安全的方法
Jun 21 PHP
PHP 对象继承原理与简单用法示例
Apr 21 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 - Html Transfer Code
2006/10/09 PHP
用PHP调用Oracle存储过程的方法
2008/09/12 PHP
php实现改变图片直接打开为下载的方法
2015/04/14 PHP
php函数重载的替代方法--伪重载详解
2015/05/08 PHP
PHP实现阿里大鱼短信验证的实例代码
2017/07/10 PHP
Mootools 1.2教程 输入过滤第一部分(数字)
2009/09/15 Javascript
javascript Array.sort() 跨浏览器下需要考虑的问题
2009/12/07 Javascript
IE之动态添加DOM节点触发window.resize事件
2010/07/27 Javascript
window.open关于浏览器拦截问题分析及解决方法
2013/02/05 Javascript
以JSON形式将JS中Array对象数组传至后台的方法
2014/01/06 Javascript
JavaScript实现复制或剪切内容到剪贴板功能的方法
2016/05/23 Javascript
Bootstrap中的Dropdown下拉菜单更改为悬停(hover)触发
2016/08/31 Javascript
jQuery实现简洁的轮播图效果实例
2016/09/07 Javascript
javascript ASCII和Hex互转的实现方法
2016/12/27 Javascript
Vue+axios 实现http拦截及路由拦截实例
2017/04/25 Javascript
Bootstrap里的文件分别代表什么意思及其引用方法
2017/05/01 Javascript
jquery实现简单实用的轮播器
2017/05/23 jQuery
JS计算两个时间相差分钟数的方法示例
2018/01/10 Javascript
javascrit中undefined和null的区别详解
2019/04/07 Javascript
jquery登录的异步验证操作示例
2019/05/09 jQuery
JS前端知识点总结之页面加载事件,数组操作,DOM节点操作,循环和分支
2019/07/04 Javascript
vue中如何实现后台管理系统的权限控制的方法步骤
2019/09/05 Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
2020/02/14 Javascript
Python的Django框架中的Context使用
2015/07/15 Python
Python聊天室实例程序分享
2016/01/05 Python
局域网内python socket实现windows与linux间的消息传送
2019/04/19 Python
python 下 CMake 安装配置 OPENCV 4.1.1的方法
2019/09/30 Python
OpenCV4.1.0+VS2017环境配置的方法步骤
2020/07/09 Python
应届生体育教师自荐信
2013/10/03 职场文书
童装店创业计划书
2014/01/09 职场文书
装修致歉信
2014/01/15 职场文书
高中语文课后反思
2014/04/27 职场文书
北京颐和园导游词
2015/01/30 职场文书
学生会副主席竞选稿
2015/11/19 职场文书
python保存大型 .mat 数据文件报错超出 IO 限制的操作
2021/05/10 Python
Oracle锁表解决方法的详细记录
2022/06/05 Oracle