今天学习ThinkPHP6,不知道写什么鬼,于是想了想,快过年了,整个抢红包的功能。百度了几种,亲测有效的3种,保存到这里,万一哪天用上了!
展示一下结果:
1、封装公共方法
<?php
// 应用公共文件
/**
* 随机抢红包 - 方法1
* 整数红包
* @param number total 红包金额
* @param int num 拆成的个数
* @return array
*/
function open_int_red($total, $num) {
$min=1;//每个人最少能收到1元
$sub_arr = [];
for ($i=1;$i<$num;$i++)
{
$safe_total=($total-($num-$i)*$min)/($num-$i);//随机安全上限
$money=mt_rand($min,$safe_total);
$total=$total-$money;
//echo '第'.$i.'个红包:领'.$money.' 元,余额:'.$total.' 元 <br/>';
$sub_arr[] = $money;
}
//echo '00第'.$num.'个红包:'.$total.' 元,余额:0 元';
array_push($sub_arr, $total);
return $sub_arr;
}
/**
* 随机抢红包 - 方法2
* 保留2位小数点红包
* @param number total 红包金额
* @param int num 拆成的个数
* @return array
*/
function open_float_red($total, $num) {
$min=0.01;//每个人最少能收到0.01元
$sub_arr = [];
for ($i=1;$i<$num;$i++)
{
$safe_total=($total-($num-$i)*$min)/($num-$i);//随机安全上限
$money=mt_rand($min*100,$safe_total*100)/100;
$total=$total-$money;
//echo '第'.$i.'个红包:领'.$money.' 元,余额:'.$total.' 元 <br/>';
$sub_arr[] = $money;
}
//echo '00第'.$num.'个红包:'.$total.' 元,余额:0 元';
array_push($sub_arr, $total);
return $sub_arr;
}
/********************************* 抢红包方法3:封装开始 ***************************************/
/**
* 功能:求一个数的平方
*/
function _sqr($n){
return $n*$n;
}
/**
* 功能:生产min和max之间的随机数,但是概率不是平均的,从min到max方向概率逐渐减小。
* 先平方,然后产生一个平方值范围内的随机数,再开方,这样就产生了一种“膨胀”再“收缩”的效果。
* @param $point_min 每个小红包的最小额
* @param $point_max 每个小红包的最大额
* @return int
*/
function _xRandom($point_min,$point_max){
$sqr = intval(_sqr($point_max-$point_min));
$rand_num = rand(0, ($sqr-1));
return intval(sqrt($rand_num));
}
/**
* 功能:产生红包
* @param $total_point 红包总额
* @param $total_people 红包个数
* @param $point_max 每个小红包的最大额
* @param $point_min 每个小红包的最小额
* @return array 存放生成的每个小红包的值的一维数组
*/
function _getBonus($total_point, $total_people, $point_max, $point_min) {
$result = array();
$average = $total_point / $total_people;
if($point_max < $average){
for ($i = 0; $i < $total_people; $i++){
$result[$i] = 5;
}
return $result;
}
for ($i = 0; $i < $total_people; $i++) {
//因为小红包的数量通常是要比大红包的数量要多的,因为这里的概率要调换过来。
//当随机数>平均值,则产生小红包
//当随机数<平均值,则产生大红包
if (rand($point_min, $point_max) > $average) {
// 在平均线上加积分
$temp = $point_min + _xRandom($point_min, $average);
$result[$i] = $temp;
$total_point -= $temp;
} else {
// 在平均线上减钱
$temp = $point_max - _xRandom($average, $point_max);
$result[$i] = $temp;
$total_point -= $temp;
}
}
// 如果还有余积分,则尝试加到小红包里,如果加不进去,则尝试下一个。
while ($total_point > 0) {
for ($i = 0; $i < $total_people; $i++) {
if ($total_point > 0 && $result[$i] < $point_max) {
$result[$i]++;
$total_point--;
}
}
}
// 如果积分是负数了,还得从已生成的大于最小红包的红包中抽取回来
while ($total_point < 0) {
for ($i = 0; $i < $total_people; $i++) {
if ($total_point < 0 && $result[$i] > $point_min) {
$result[$i]--;
$total_point++;
}
}
}
return $result;
}
/********************************* 抢红包方法3:封装结束 ***************************************/
2、调用上面的方法:
public function index()
{
// 1、抢红包
// $result = open_int_red(1000,20);
// $a = array_sum($result);
// dump($a);
// dump($result);die;
// 2、抢红包方法
$a = _getBonus(1000,50,200,1);
dump(array_sum($a));
dump($a);die;
return View::fetch('login');
}