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 相关文章推荐
关于Appserv无法打开localhost问题的解决方法
Oct 16 PHP
PHP stream_context_create()作用和用法分析
Mar 29 PHP
深入理解PHP原理之错误抑制与内嵌HTML分析
May 02 PHP
php连接数据库代码应用分析
May 29 PHP
数组与类使用PHP的可变变量名需要的注意的问题
Jun 20 PHP
php制作文本式留言板
Mar 18 PHP
PHP判断用户是否已经登录(跳转到不同页面或者执行不同动作)
Sep 22 PHP
php mysql数据库操作类(实例讲解)
Aug 06 PHP
PHP实现从上往下打印二叉树的方法
Jan 18 PHP
Yii2处理密码加密及验证的方法
May 12 PHP
PHP cookie,session的使用与用户自动登录功能实现方法分析
Jun 05 PHP
laravel dingo API返回自定义错误信息的实例
Sep 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
星际争霸秘籍
2020/03/04 星际争霸
PHP 日志缩略名的创建函数代码
2010/05/26 PHP
根据key删除数组中指定的元素实现方法
2017/03/02 PHP
PHP实现抽奖功能实例代码
2020/06/30 PHP
php慢查询日志和错误日志使用详解
2021/02/27 PHP
JS中如何设置readOnly的值
2013/12/25 Javascript
Js判断CSS文件加载完毕的具体实现
2014/01/17 Javascript
Javascript字符串对象的常用方法简明版
2014/06/26 Javascript
Node.js中调用mysql存储过程示例
2014/12/20 Javascript
jquery通过load获取文件的内容并跳到锚点的方法
2015/01/29 Javascript
js实现非常简单的焦点图切换特效实例
2015/05/07 Javascript
javascript实现tab切换的四种方法
2015/11/05 Javascript
javascript如何实现暂停功能
2015/11/06 Javascript
jquery基本选择器匹配多个元素的实现方法
2016/09/05 Javascript
浅谈jQuery绑定事件会叠加的解决方法和心得总结
2016/10/26 Javascript
JavaScript &amp; jQuery完美判断图片是否加载完毕
2017/01/08 Javascript
node.js的事件机制
2017/02/08 Javascript
JS 60秒后重新发送验证码的实例讲解
2017/07/26 Javascript
Vue from-validate 表单验证的示例代码
2017/09/26 Javascript
JS获取并处理php数组的方法实例分析
2018/09/04 Javascript
微信小程序开发摇一摇功能
2019/11/22 Javascript
原生小程序封装跑马灯效果
2020/10/21 Javascript
python基础教程之基本内置数据类型介绍
2014/02/20 Python
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
使用python turtle画高达
2020/01/19 Python
通过python检测字符串的字母
2020/02/18 Python
解决使用python print打印函数返回值多一个None的问题
2020/04/09 Python
css3的图形3d翻转效果应用示例
2014/04/08 HTML / CSS
html5.2 dialog简介详解
2018/02/27 HTML / CSS
日本语毕业生自荐信
2014/02/01 职场文书
《窗前的气球》教学反思
2014/04/07 职场文书
检察机关个人对照检查材料
2014/09/15 职场文书
升职自荐信范文
2015/03/27 职场文书
婚宴来宾致辞
2015/07/28 职场文书
导游词之杭州岳王庙
2019/11/13 职场文书
如何用threejs实现实时多边形折射
2021/05/07 Javascript