版权声明:希望不要抄袭,可以借鉴。 https://blog.csdn.net/weixin_37616043/article/details/83185622
将一个数分成若干份,并且以不返回的抽奖方式来产生暴击数(算法)
简介:现象好多商城有领钻石,类似于挖矿;也就是伪区块链(实例:网易星球);我做一个项目要求是:一个用户获得一定数的钻石;将这个数随机分成60份(后台可以变),没份数要保留五位小数,这60份数中大小需要控制最大和最小数不要相差很大,并且40份中随机产生一个暴击,这要在暴击概率内,这暴击数是平均数的几倍;倍数后台可以变,暴击率后台也可以变,产生暴击数但是60份还是保持不变;(描述不是很好)PHP代码如下:
$sql="select * from wemall_block_chain_config where id=1"; $block_chain_config = $mysqli -> query($sql); $configlist=$block_chain_config -> fetch_assoc();
//区块链凌晨数据处理
$today_time=strtotime(date("Y-m-d"));//今天凌晨时间戳
$add_time=intval($today_time)+(3*60);//今天凌晨时间戳+3分钟
$strtime=time();//当前时间
if($configlist['c_time']<$today_time) {
//阻止一天在规定时间中重复执行
if ($strtime >= $today_time ) {
//确保凌晨执行程序
$min_multiple = $configlist['min_multiple'];//暴击最小倍数
$max_multiple = $configlist['max_multiple'];//暴击最大倍数
$today_bear_num = $configlist['today_bear_num'];//当日平台总发放的钻石数
$probability = $configlist['probability'] / 100;//暴击概率
$set_bear_power = $configlist['bear_power'];//超过这个数才可以参加暴击
$equal_division = $configlist['equal_division'];//钻石随机划分多少份
//获取平台所有用户的总动力
$sql = "SELECT sum(number) as just_total FROM wemall_bear_power_log WHERE ctime < '$today_time' and is_income=1";//总增加动力值
$just_total = $mysqli->query($sql);
$just_total = $just_total->fetch_assoc();
$sql = "SELECT sum(number) as negative_total FROM wemall_bear_power_log WHERE ctime < '$today_time' and is_income=2";//总减少动力值
$negative_total = $mysqli->query($sql);
$negative_total = $negative_total->fetch_assoc();
$total_list=$just_total['just_total']-$negative_total['negative_total'];//总增加动力值-总减少动力值(净总动力值)
if ($total_list) {
$total = $total_list;//平台所有用户的净总动力值(昨天以前的)
}else{
$total = 0;
}
//获得暴击人数
if ($today_bear_num <= 25) {
$canshu = ($today_bear_num / 2) - 1;
$lists = getsum($canshu, $today_bear_num, $today_bear_num);
if ($lists > $probability) {
$result = 0;
} else if ($lists == $probability) {
$result = $canshu;
} else if ($lists < $probability) {
$result = getnum(1, 1, $today_bear_num, $today_bear_num, $probability);
}
} else {
$result = getnum(1, 1, $today_bear_num, $today_bear_num, $probability);
}
$riot_number = $result;//暴击人数
$sql = "SELECT id FROM wemall_user ORDER BY id asc";
$userlist = $mysqli->query($sql);
while ($userlists = $userlist->fetch_assoc()) {
//获取暴击数组
if ($userlists['id']) {
//单个用户动力值
$user_ids = $userlists['id'];
$sql = "SELECT sum(number) as just_total FROM wemall_bear_power_log WHERE ctime < '$today_time' and user_id='$user_ids' and is_income=1";//个人总增加动力值
$person_just_total = $mysqli->query($sql);
$person_just_total = $person_just_total->fetch_assoc();
$sql = "SELECT sum(number) as negative_total FROM wemall_bear_power_log WHERE ctime < '$today_time' and user_id='$user_ids' and is_income=2";//总减少动力值
$person_negative_total = $mysqli->query($sql);
$person_negative_total = $person_negative_total->fetch_assoc();
$person_total_list=$person_just_total['just_total']-$person_negative_total['negative_total'];//总收入-总支出
if ($person_total_list) {
$person_total = $person_total_list;//用户的净总动力值(昨天以前的)
} else {
$person_total = 0;
}
if ($person_total > $set_bear_power) {
//生成暴击数组
$sql = "select violent_data,c_time from wemall_block_chain_config where id=1";
$violent_data = $mysqli->query($sql);
$violent_data = $violent_data->fetch_assoc();
if ($violent_data['c_time'] < $strtime) {
//老的数据
$arrlist['attack'] = mt_rand($min_multiple, $max_multiple);
$arrlist['v'] = $person_total;
$arrlist['user_id'] = $user_ids;
$arr[] = $arrlist;
$arr = json_encode($arr);
$sql = "UPDATE wemall_block_chain_config SET violent_data='$arr',c_time='$strtime' WHERE id=1";
$update_data = $mysqli->query($sql);
if (!$update_data) {
$mysqli->rollback();
$result = false;
exit;
}
} else {
//新数据
if ($violent_data['violent_data']) {
//有数据的
$arrlist['attack'] = mt_rand($min_multiple, $max_multiple);
$arrlist['v'] = $person_total;
$arrlist['user_id'] = $user_ids;
$arralist = json_decode($violent_data['violent_data'], true);
$arralist[] = $arrlist;
$arr = json_encode($arralist);
$sql = "UPDATE wemall_block_chain_config SET violent_data='$arr',c_time='$strtime' WHERE id=1";
$update_data = $mysqli->query($sql);
if (!$update_data) {
$mysqli->rollback();
$result = false;
exit;
}
} else {
//没有数据
$arrlist['attack'] = mt_rand($min_multiple, $max_multiple);
$arrlist['v'] = $person_total;
$arrlist['user_id'] = $user_ids;
$arr[] = $arrlist;
$arr = json_encode($arr);
$sql = "UPDATE wemall_block_chain_config SET violent_data='$arr',c_time='$strtime' WHERE id=1";
$update_data = $mysqli->query($sql);
if (!$update_data) {
$mysqli->rollback();
$result = false;
exit;
}
}
}
}
}
}
//获取暴击人的user_id,暴击倍数。数组
$sql = "select violent_data,c_time from wemall_block_chain_config where id=1";
$violent_datas = $mysqli->query($sql);
$violent_datas = $violent_datas->fetch_assoc();
$prize_arr = json_decode($violent_datas['violent_data'], true);
$attack_list = array();
for ($i = 0; $i < $riot_number; $i++) {
if ($violent_datas['c_time'] <= $strtime) {
$list_data = get_violent_attack($prize_arr);
if ($list_data['no']) {
$prize_arr = $list_data['no'];
}
if ($list_data['yes']) {
$attack_list[] = $list_data['yes'];
}
}
}
//生成获得钻石随机分成设定等分
$sql = "SELECT id,openid,bear_power FROM wemall_user ORDER BY id asc";
$today_user = $mysqli->query($sql);
while ($today_users = $today_user->fetch_assoc()) {
if ($today_users['openid']){
//用户存在
$user_id = $today_users['id'];//用户id
//单个用户动力值
$sql = "SELECT sum(number) as just_total FROM wemall_bear_power_log WHERE ctime < '$today_time' and user_id='$user_id' and is_income=1";//个人总收入
$person_just_total = $mysqli->query($sql);
$person_just_total = $person_just_total->fetch_assoc();
$sql = "SELECT sum(number) as negative_total FROM wemall_bear_power_log WHERE ctime < '$today_time' and user_id='$user_id' and is_income=2";//个人总支出
$person_negative_total = $mysqli->query($sql);
$person_negative_total = $person_negative_total->fetch_assoc();
$person_total_list=$person_just_total['just_total']-$person_negative_total['negative_total'];//总收入-总支出
if ($person_total_list) {
$person_total = $person_total_list;//用户的净总动力值(昨天以前的)
} else {
$person_total = 0;
}
if ($person_total) {
//用户总动力大于0
$person_bear_num = $person_total / $total * $today_bear_num;//该用户当日获得的钻石额为:(10/1000)x100;
//参加暴击计算
if (count($attack_list) > 0) {
//有暴击人
$flag=0;
foreach ($attack_list as $key => $vals) {
if ($vals['user_id'] == $user_id) {
$flag=$vals['attack'];
break;
}
}
if ($flag) {
$attack_num =sprintf("%.5f",($person_bear_num / $equal_division) * $flag);//暴击的钻石数
$arr_l['val'] = $attack_num;
$arr_l['state'] = 1;
$arr_l['multiple'] =2;
$new_person_bear_num = $person_bear_num - $attack_num;//除去暴击的钻石数量在随机划分
$data_bear = getBearNum($new_person_bear_num,$equal_division - 1);
$data_bear[] = $arr_l;
$bear_num = json_encode($data_bear);
$sql = "INSERT INTO wemall_block_chain_list (user_id,ctime,bear_num,multiple) VALUES ('$user_id','$strtime','$bear_num','$flag')";
$row = $mysqli->query($sql);
if (!$row) {
$mysqli->rollback();
$result = false;
exit;
}
}else{
//不是暴击用户
//把获得钻石按设置的随机划分多少份
$data_bear = getBearNum($person_bear_num,$equal_division);
$bear_num = json_encode($data_bear);
$sql = "INSERT INTO wemall_block_chain_list (user_id,ctime,bear_num) VALUES ('$user_id','$strtime','$bear_num')";
$row = $mysqli->query($sql);
if (!$row) {
$mysqli->rollback();
$result = false;
exit;
}
}
}else{
//暴击人数为空
//把获得钻石按设置的随机划分多少份
$data_bear = getBearNum($person_bear_num,$equal_division);
$bear_num = json_encode($data_bear);
$sql = "INSERT INTO wemall_block_chain_list (user_id,ctime,bear_num) VALUES ('$user_id','$strtime','$bear_num')";
$row = $mysqli->query($sql);
if (!$row) {
$mysqli->rollback();
$result = false;
exit;
}
}
}
}
}
}
}
}
$mysqli->commit();
$mysqli -> close();
function getsum($m,$sum_num,$sum_one){
//计算暴击人数
//$sum_num每天产出钻石数量 $sum_one每天产出钻石数量
for($op=$m-1;$op>=1;$op--){
$sum_one--;
$sum_num=$sum_num*$sum_one;
}
$sum_two=$m;
for($pl=$m-1;$pl>0;$pl--){
$sum_two=$sum_two*$pl;
}
if($sum_two&&$sum_num){
$result=$sum_two*$m/$sum_num;
}else{
$result=false;
}
return $result;
}
function getnum($list=1,$i=1,$sum_num,$sum_one,$probability){
if($list<$probability){
return $i-1;
}else{
$lists=getsum($i,$sum_num,$sum_one);
$i++;
return(getnum($lists,$i,$sum_num,$sum_one,$probability));
}
}
function getBearNum($total,$div) {
//获取昨天钻石数随机分成规定份数 //$total待划分的数字 //$div分成的份数
$area = ($total/$div)*0.9; //各份数间允许的最大差值
$average =sprintf("%.5f",$total/$div);
$sum = 0;
// $result = array_fill( 1, $div, 0 );
$result=array();
for( $i = 1; $i < $div; $i++ ){
//根据已产生的随机数情况,调整新随机数范围,以保证各份间差值在指定范围内
if( $sum > 0 ){
$max = 0;
$min = 0 - $area/2;
}elseif( $sum < 0 ){
$min = 0;
$max =$area/2;
}else{
$max =$area/2;
$min = 0-$area/2;
}
//产生各份的份额
$random =sprintf("%.5f",$min + mt_rand()/mt_getrandmax() * ($max - $min)) ;
if($average + $random<0){
$sum=$sum-$random;
$result[$i-1]['val']=sprintf("%.5f",$average-$random);
$result[$i-1]['state']=1;//1 未领取 2已领
$result[$i-1]['multiple'] =1;//1 没有暴击 2暴击
}else{
$sum+=$random;
$result[$i-1]['val']=sprintf("%.5f",$average+$random);
$result[$i-1]['state']=1;//1 未领取 2已领
$result[$i-1]['multiple'] =1;//1 没有暴击 2暴击
}
}
//最后一份的份额由前面的结果决定,以保证各份的总和为指定值
$result[$div-1]['val']=sprintf("%.5f",$average-$sum);
$result[$div-1]['state']=1;
$result[$div-1]['multiple'] =1;//1 没有暴击 2暴击
//结果呈现
// $list['value_max']=max($result); //获取最大值
// $list['sum']=array_sum($result);
return $result;
}
function get_rand($arr){
//抽取用户
$pro_sum=array_sum($arr);
$rand_num=mt_rand(1,$pro_sum);
$tmp_num=0;
foreach($arr as $k=>$val)
{
if($rand_num<=$val+$tmp_num)
{
$n=$k;
break;
}else
{
$tmp_num+=$val;
}
}
return $n;
}
/** 每次前端页面的请求,PHP循环奖项设置数组,
* 通过概率计算函数get_rand获取抽中的奖项id。
* 将中奖奖品保存在数组$res['yes']中,
* 而剩下的未中奖的信息保存在$res['no']中,
* 最后输出json个数数据给前端页面。
*/
function get_violent_attack($prize_arr){
//根据熊力大小按概率抽取暴击的用户
foreach ($prize_arr as $key => $val) {
$arr[$key+1] = $val['v'];
}
$rid =get_rand($arr); //根据概率获取奖项id
$res['yes'] = $prize_arr[$rid-1]; //中奖项
unset($prize_arr[$rid-1]); //将中奖项从数组中剔除,剩下未中奖项
shuffle($prize_arr); //打乱数组顺序
for($i=0;$i<count($prize_arr);$i++){
$pr[] = $prize_arr[$i];
}
$res['no'] = $pr;//除去中奖的没中用户
return $res;
}
代码已经在项目运行正常,有不懂的逻辑和算法可以加我的qq:3358756537: