<?php
namespace redpacket;
/**
* @Author: renakeji
* @Date: 2018-04-02 16:52:26
* @Last Modified by: renakeji
* @Last Modified time: 2018-04-02 16:52:36
*/
class OptionDTO
{/*{{{*/
//红包总金额
public $totalMoney;
//红包数量
public $num;
//范围开始
public $rangeStart;
//范围结算
public $rangeEnd;
//生成红包策略
public $builderStrategy;
//随机红包剩余规则
public $randFormatType; //Can_Left:不修数据,可以有剩余;No_Left:不能有剩余
public static function create($totalMoney,$num,$rangeStart,$rangEnd,
$builderStrategy,$randFormatType = 'No_Left')
{/*{{{*/
$self = new self();
$self->num = $num;
$self->rangeStart = $rangeStart;
$self->rangeEnd = $rangEnd;
$self->totalMoney = $totalMoney;
$self->builderStrategy = $builderStrategy;
$self->randFormatType = $randFormatType;
return $self;
}/*}}}*/
}
<?php
namespace redpacket;
/**
* @Author: renakeji
* @Date: 2018-04-02 15:43:25
* @Last Modified by: renakeji
* @Last Modified time: 2018-04-02 16:42:26
*/
//固定等额红包策略
class EqualPackageStrategy
{/*{{{*/
//单个红包金额
public $oneMoney;
//数量
public $num;
public function __construct($option = null)
{
$this->setOption($option);
}
public function setOption(OptionDTO $option)
{
$this->oneMoney = $option->rangeStart;
$this->num = $option->num;
}
public function create()
{/*{{{*/
$data = array();
if(false == $this->isCanBuilder())
{
return $data;
}
$data = array();
if(false == is_int($this->num) || $this->num <= 0)
{
return $data;
}
for($i = 1;$i <= $this->num;$i++)
{
$data[$i] = $this->fx($i);
}
return $data;
}/*}}}*/
/**
* 等额红包的方程是一条直线
*
* @param mixed $x
* @access public
* @return void
*/
public function fx($x)
{/*{{{*/
return $this->oneMoney;
}/*}}}*/
/**
* 是否能固定红包
*
* @access public
* @return void
*/
public function isCanBuilder()
{/*{{{*/
if(false == is_int($this->num) || $this->num <= 0)
{
return false;
}
if(false == is_numeric($this->oneMoney) || $this->oneMoney <= 0)
{
return false;
}
//单个红包小于1分
if($this->oneMoney < 0.01)
{
return false;
}
return true;
}/*}}}*/
}/*}}}*/
<?php
namespace redpacket;
//随机红包策略(三角形)
class RandTrianglePackageStrategy
{
//总额
public $totalMoney;
//红包数量
public $num;
//随机红包最小值
public $minMoney;
//随机红包最大值
public $maxMoney;
//修数据方式:NO_LEFT: 红包总额 = 预算总额;CAN_LEFT: 红包总额 <= 预算总额
public $formatType;
//预算剩余金额
public $leftMoney;
public function __construct($option = null)
{
$this->setOption($option);
}
public function setOption($option)
{
$this->totalMoney = $option->totalMoney;
$this->num = $option->num;
$this->formatType = $option->randFormatType;
$this->minMoney = $option->rangeStart;
$this->maxMoney = $option->rangeEnd;
$this->leftMoney = $this->totalMoney;
}
/**
* 创建随机红包
*
* @access public
* @return void
*/
public function create()
{
$data = array();
if(false == $this->isCanBuilder())
{
return $data;
}
$leftMoney = $this->leftMoney;
for($i = 1;$i <= $this->num;$i++)
{
$data[$i] = $this->fx($i);
$leftMoney = $leftMoney - $data[$i];
}
//修数据
list($okLeftMoney,$okData) = $this->format($leftMoney,$data);
//随机排序
shuffle($okData);
$this->leftMoney = $okLeftMoney;
return $okData;
}
/**
* 是否能够发随机红包
*
* @access public
* @return void
*/
public function isCanBuilder()
{
if(false == is_int($this->num) || $this->num <= 0)
{
return false;
}
if(false == is_numeric($this->totalMoney) || $this->totalMoney <= 0)
{
return false;
}
//均值
$avgMoney = $this->totalMoney / 1.0 / $this->num;
//均值小于最小值
if($avgMoney < $this->minMoney )
{
return false;
}
return true;
}
/**
* 获取剩余金额
*
* @access public
* @return void
*/
public function getLeftMoney()
{
return $this->leftMoney;
}
/**
* 随机红包生成函数。三角函数。[(1,0.01),($num/2,$avgMoney),($num,0.01)]
*
* @param mixed $x,1 <= $x <= $this->num;
* @access public
* @return void
*/
public function fx($x)
{
if(false == $this->isCanBuilder())
{
return 0;
}
if($x < 1 || $x > $this->num)
{
return 0;
}
$x1 = 1;
$y1 = $this->minMoney;
//我的峰值
$y2 = $this->maxMoney;
//中间点
$x2 = ceil($this->num / 1.0 / 2);
//最后点
$x3 = $this->num;
$y3 = $this->minMoney;
//当x1,x2,x3都是1的时候(竖线)
if($x1 == $x2 && $x2 == $x3)
{
return $y2;
}
// '/_\'三角形状的线性方程
//'/'部分
if($x1 != $x2 && $x >= $x1 && $x <= $x2)
{
$y = 1.0 * ($x - $x1) / ($x2 - $x1) * ($y2 - $y1) + $y1;
return number_format($y, 2, '.', '');
}
//'\'形状
if($x2 != $x3 && $x >= $x2 && $x <= $x3)
{
$y = 1.0 * ($x - $x2) / ($x3 - $x2) * ($y3 - $y2) + $y2;
return number_format($y, 2, '.', '');
}
return 0;
}
/**
* 格式化修红包数据
*
* @param mixed $leftMoney
* @param array $data
* @access public
* @return void
*/
private function format($leftMoney,array $data)
{
//不能发随机红包
if(false == $this->isCanBuilder())
{
return array($leftMoney,$data);
}
//红包剩余是0
if(0 == $leftMoney)
{
return array($leftMoney,$data);
}
//数组为空
if(count($data) < 1)
{
return array($leftMoney,$data);
}
//如果是可以有剩余,并且$leftMoney > 0
if('Can_Left' == $this->formatType
&& $leftMoney > 0)
{
return array($leftMoney,$data);
}
//我的峰值
$myMax = $this->maxMoney;
// 如果还有余钱,则尝试加到小红包里,如果加不进去,则尝试下一个。
while($leftMoney > 0)
{
$found = 0;
foreach($data as $key => $val)
{
//减少循环优化
if($leftMoney <= 0)
{
break;
}
//预判
$afterLeftMoney = (double)$leftMoney - 0.01;
$afterVal = (double)$val + 0.01;
if( $afterLeftMoney >= 0 && $afterVal <= $myMax)
{
$found = 1;
$data[$key] = number_format($afterVal,2,'.','');
$leftMoney = $afterLeftMoney;
//精度
$leftMoney = number_format($leftMoney,2,'.','');
}
}
//如果没有可以加的红包,需要结束,否则死循环
if($found == 0)
{
break;
}
}
//如果$leftMoney < 0 ,说明生成的红包超过预算了,需要减少部分红包金额
while($leftMoney < 0)
{
$found = 0;
foreach($data as $key => $val)
{
if($leftMoney >= 0)
{
break;
}
//预判
$afterLeftMoney = (double)$leftMoney + 0.01;
$afterVal = (double)$val - 0.01;
if( $afterLeftMoney <= 0 && $afterVal >= $this->minMoney)
{
$found = 1;
$data[$key] = number_format($afterVal,2,'.','');
$leftMoney = $afterLeftMoney;
$leftMoney = number_format($leftMoney,2,'.','');
}
}
//如果一个减少的红包都没有的话,需要结束,否则死循环
if($found == 0)
{
break;
}
}
return array($leftMoney,$data);
}
}
<?php
namespace redpacket;
use redpacket\OptionDTO;
use redpacket\EqualPackageStrategy;
use redpacket\RandTrianglePackageStrategy;
/**
* 随机红包+固定红包算法[策略模式]
*/
class redpacket
{/*{{{*/
public static function equal($money,$num,$start,$end)
{
//固定红包
$dto = OptionDTO::create($money,$num,$start,$end);
$EqualPackageStrategy = new EqualPackageStrategy($dto);
$data = $EqualPackageStrategy->create();
return $data;
}
public static function rand($money,$num,$start,$end)
{
//随机红包[修数据]
$dto = OptionDTO::create($money,$num,$start,$end,'NO_LEFT');
$RandTrianglePackageStrategy = new RandTrianglePackageStrategy($dto);
$data = $RandTrianglePackageStrategy->create();
return $data;
}
public static function randcanleft($money,$num,$start,$end)
{
//随机红包[不修数据]
$dto = OptionDTO::create($money,$num,$start,$end,'Can_Left');
$RandTrianglePackageStrategy = new RandTrianglePackageStrategy($dto);
$data = $RandTrianglePackageStrategy->create();
return $data;
}
}
本文为看恩吧原创文章,转载无需和我联系,但请注明来自knsay.com