├── README.md ├── Redpaper.class.php ├── hongbao.php └── test.php /README.md: -------------------------------------------------------------------------------- 1 | # 抽奖算法和红包算法 2 | 简介:抽奖算法,抽奖算法适合老虎机,刮刮卡,大转盘,摇一摇,九宫格抽奖等等.搜集来自网络 3 | 红包算法也是来自网络,目前来说是不错的两个算法. 4 | #### 说明 5 | 算法主要是用在后台开发中,不管是什么抽奖,都属于数学问题,这个算法被很多游戏使用. 6 | #### 更新 7 | 8 | 红包算法更新,发送一个正常返回,比如0.01元发1个人,1元发一个人和1元发100人正常返回0.01每人 9 | 10 | 2018-8-7 11 | 新增另一个红包算法 12 | 此红包算法可以设置最大值 最小值 13 | -------------------------------------------------------------------------------- /Redpaper.class.php: -------------------------------------------------------------------------------- 1 | rewardMoney = $rewardMoney * 100 - $rewardNum * $min; 18 | $this->rewardNum = $rewardNum; 19 | #计算出发出红包的平均概率值、精确到小数4位。 20 | $avgRand = 1 / $this->rewardNum; 21 | $randArr = array(); 22 | #定义生成的数据总合sum 23 | $sum = 0; 24 | $t_count = 0; 25 | while ($t_count < $rewardNum) { 26 | #随机产出四个区间的额度 27 | $c = rand(1, 100); 28 | if ($c < 15) { 29 | $t = round(sqrt(mt_rand(1, 1500))); 30 | } else if ($c < 65) { 31 | $t = round(sqrt(mt_rand(1500, 6500))); 32 | } else if ($c < 95) { 33 | $t = round(sqrt(mt_rand(6500, 9500))); 34 | } else { 35 | $t = round(sqrt(mt_rand(9500, 10000))); 36 | } 37 | ++$t_count; 38 | $sum += $t; 39 | $randArr[] = $t; 40 | } 41 | 42 | #计算当前生成的随机数的平均值,保留4位小数 43 | $randAll = round($sum / $rewardNum, 4); 44 | 45 | #为将生成的随机数的平均值变成我们要的1/N,计算一下每个随机数要除以的总基数mixrand。此处可以约等处理,产生的误差后边会找齐 46 | #总基数 = 均值/平均概率 47 | $mixrand = round($randAll / $avgRand, 4); 48 | 49 | #对每一个随机数进行处理,并乘以总金额数来得出这个红包的金额。 50 | $rewardArr = array(); 51 | foreach ($randArr as $key => $randVal) { 52 | #单个红包所占比例randVal 53 | $randVal = round($randVal / $mixrand, 4); 54 | #算出单个红包金额 55 | $single = floor($this->rewardMoney * $randVal); 56 | #小于最小值直接给最小值 57 | if ($single < $min) { 58 | $single += $min; 59 | } 60 | #大于最大值直接给最大值 61 | if ($single > $max) { 62 | $single = $max; 63 | } 64 | #将红包放入结果数组 65 | $rewardArr[] = $single; 66 | } 67 | 68 | #对比红包总数的差异、将差值放在第一个红包上 69 | $rewardAll = array_sum($rewardArr); 70 | $rewardArr[0] = $rewardMoney * 100 - ($rewardAll - $rewardArr[0]);#此处应使用真正的总金额rewardMoney,$rewardArr[0]可能小于0 71 | 72 | #第一个红包小于0时,做修正 73 | if ($rewardArr[0] < 0) { 74 | rsort($rewardArr); 75 | $this->add($rewardArr, $min); 76 | } 77 | 78 | rsort($rewardArr); 79 | #随机生成的最大值大于指定最大值 80 | if ($rewardArr[0] > $max) { 81 | #差额 82 | $diff = 0; 83 | foreach ($rewardArr as $k => &$v) { 84 | if ($v > $max) { 85 | $diff += $v - $max; 86 | $v = $max; 87 | } else { 88 | break; 89 | } 90 | } 91 | $transfer = round($diff / ($this->rewardNum - $k + 1)); 92 | $this->diff($diff, $rewardArr, $max, $min, $transfer, $k); 93 | } 94 | return $rewardArr; 95 | } 96 | 97 | #处理所有超过最大值的红包 98 | public function diff($diff, &$rewardArr, $max, $min, $transfer, $k) 99 | { 100 | #将多余的钱均摊给小于最大值的红包 101 | for ($i = $k; $i < $this->rewardNum; $i++) { 102 | #造随机值 103 | if ($transfer > $min * 20) { 104 | $aa = rand($min, $min * 20); 105 | if ($i % 2) { 106 | $transfer += $aa; 107 | } else { 108 | $transfer -= $aa; 109 | } 110 | } 111 | if ($rewardArr[$i] + $transfer > $max) continue; 112 | if ($diff - $transfer < 0) { 113 | $rewardArr[$i] += $diff; 114 | $diff = 0; 115 | break; 116 | } 117 | $rewardArr[$i] += $transfer; 118 | $diff -= $transfer; 119 | } 120 | if ($diff > 0) { 121 | $i++; 122 | $this->diff($diff, $rewardArr, $max, $min, $transfer, $k); 123 | } 124 | } 125 | 126 | #第一个红包小于0,从大红包上往下减 127 | public function add(&$rewardArr, $min) 128 | { 129 | foreach ($rewardArr as &$re) { 130 | $dev = floor($re / $min); 131 | if ($dev > 2) { 132 | $transfer = $min * floor($dev / 2); 133 | $re -= $transfer; 134 | $rewardArr[$this->rewardNum - 1] += $transfer; 135 | } elseif ($dev == 2) { 136 | $re -= $min; 137 | $rewardArr[$this->rewardNum - 1] += $min; 138 | } else { 139 | break; 140 | } 141 | } 142 | if ($rewardArr[$this->rewardNum - 1] > $min || $rewardArr[$this->rewardNum - 1] == $min) { 143 | return; 144 | } else { 145 | $this->add($rewardArr, $min); 146 | } 147 | } 148 | public function random_red($total, $num, $max, $min) 149 | { 150 | #总共要发的红包金额,留出一个最大值; 151 | $total = $total - $max; 152 | $result_merge = $this->splitReward($total, $num, $max - 0.01, $min); 153 | sort($result_merge); 154 | $result_merge[1] = $result_merge[1] + $result_merge[0]; 155 | $result_merge[0] = $max * 100; 156 | foreach ($result_merge as &$v) { 157 | $v = floor($v) / 100; 158 | } 159 | return $result_merge; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /hongbao.php: -------------------------------------------------------------------------------- 1 | '.print_r($arr,TRUE).''; 5 | } 6 | require_once('Redpaper.class.php'); 7 | $total = 1; 8 | $num = 100; 9 | $max = 0.01; 10 | $min = 0.01; 11 | $a = new Redpaper(); 12 | $arr = $a->random_red($total, $num, $max, $min); 13 | dump($arr); 14 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | '.print_r($arr,TRUE).''; 5 | } 6 | 7 | /*概率算法 8 | proArr array(100,200,300,400) 9 | */ 10 | function get_rand($proArr) { 11 | $result = ''; 12 | $proSum = array_sum($proArr); 13 | foreach ($proArr as $key => $proCur) { 14 | $randNum = mt_rand(1, $proSum); 15 | if ($randNum <= $proCur) { 16 | $result = $key; 17 | break; 18 | } else { 19 | $proSum -= $proCur; 20 | } 21 | } 22 | unset ($proArr); 23 | return $result; 24 | } 25 | /* 26 | 获取中奖 27 | */ 28 | function get_prize(){ 29 | $prize_arr = array( 30 | array('id'=>1,'prize'=>'平板电脑','v'=>1), 31 | array('id'=>2,'prize'=>'数码相机','v'=>1), 32 | array('id'=>3,'prize'=>'音箱设备','v'=>1), 33 | array('id'=>4,'prize'=>'4G优盘','v'=>1), 34 | array('id'=>5,'prize'=>'10Q币','v'=>1), 35 | array('id'=>6,'prize'=>'下次没准就能中哦','v'=>95), 36 | ); 37 | foreach ($prize_arr as $key => $val) { 38 | $arr[$val['id']] = $val['v']; 39 | } 40 | $ridk = get_rand($arr); //根据概率获取奖项id 41 | 42 | $res['yes'] = $prize_arr[$ridk-1]['prize']; //中奖项 43 | unset($prize_arr[$ridk-1]); //将中奖项从数组中剔除,剩下未中奖项 44 | shuffle($prize_arr); //打乱数组顺序 45 | for($i=0;$i