实现仿照微信发红包功能的抢红包算法需要考虑以下几个步骤:
确定红包金额范围:根据总金额和总人数,确定红包的金额范围,确保每个人能抢到最低为0.01的金额,且金额相对均衡。
生成随机金额:在确定的金额范围内,生成每个人抢到的随机金额,确保金额相对均衡。
金额分配:根据生成的随机金额,分配给每个人。
下面是一个简单的PHP代码示例,实现上述功能:
function distributeRedPacket($totalAmount, $totalPeople) {
// 确保每个人能抢到最低为0.01的金额
$minAmount = 0.01;
// 计算红包可分配的金额范围
$maxAmount = $totalAmount / $totalPeople * 2;
// 初始化红包金额数组
$redPacket = [];
// 遍历分配每个人的红包金额
for ($i = 0; $i < $totalPeople; $i++) {
// 如果是最后一个人,保证剩余的金额都分配给他
if ($i == $totalPeople - 1) {
$redPacket[$i] = round($totalAmount, 2);
} else {
// 生成随机金额,确保均衡
$randomAmount = mt_rand($minAmount * 100, $maxAmount * 100) / 100;
// 确保剩余金额足够分配给剩下的人
$totalAmount -= $randomAmount;
$maxAmount = $totalAmount / ($totalPeople - $i - 1) * 2;
$redPacket[$i] = round($randomAmount, 2);
}
}
return $redPacket;
}
// 示例调用
$totalAmount = 10; // 总金额
$totalPeople = 5; // 总人数
$redPacket = distributeRedPacket($totalAmount, $totalPeople);
print_r($redPacket);
演进:均衡分配(凑合)
假设:3个人抢20元的红包。
操作:甲抢到6.66,乙抢到6.66,丙兜底抢剩余的的6.68。
结论:算法简单,但随机性差点。
function red_envelope($money, $person) {
$div = bcdiv($money, $person, 2);
for($i = 1; $i <= $person; $i++) {
$res[$i] = $person === $i ? $money - $div * ($i - 1) : $div;
}
return $res;
}
演进:二倍均值法(推荐)
假设:假设10个人抢100元红包。
操作:取0.01~(剩余金额 / 剩余人数 * 2)之间的随机数(2为常数,用于影响结果使其趋向平均值),最后一人兜底剩余金额。
结论:二倍均值法理论上可实现相对均衡的随机金额。
function red_envelope($money, $person) {
$arr = [];
for($i = 0; $i < $person; $i ++) {
$arr[$i] = $money;
if($person !== ($i + 1)) {
$arr[$i] = bcdiv(mt_rand(1, intval($money / ($person - $i) * 200)), 100, 2);
$money = bcsub($money, $arr[$i] , 2);
}
}
return $arr;
}
理想情况下平均每人金额在10元上下,以下是模拟:
第几人 | 下限随机金额 | 上限随机金额 | 上限随机金额算法 | 理论平均金额 | 实际随机金额 |
---|---|---|---|---|---|
1 | 0.01 | 20.00 | 100 / 10 * 2 | 10.00 | 12.25 |
2 | 0.01 | 19.50 | 87.75 / 9 * 2 | 9.76 | 6.87 |
3 | 0.01 | 20.22 | 80.88 / 8 * 2 | 10.12 | 11.22 |
4 | 0.01 | 19.90 | 69.66 / 7 * 2 | 9.96 | 10.01 |
5 | 0.01 | 19.88 | 59.65 / 6 * 2 | 9.95 | 0.85 |
6 | 0.01 | 23.52 | 58.80 / 5 * 2 | 11.77 | 19.56 |
7 | 0.01 | 19.62 | 39.24 / 4 * 2 | 9.81 | 4.23 |
8 | 0.01 | 23.34 | 35.01 / 3 * 2 | 11.68 | 9.85 |
9 | 0.01 | 25.16 | 25.16 / 2 * 2 | 12.59 | 12.59 |
10 | 无 | 无 | 无 | 无 | 12.57 |