这两天在微信群中玩了一个抢红包游戏,游戏规则如下:
1. 参与者可以选择发红包或者抢红包,红包需为30-100之间的整10倍数,每个红包人数为9人。
2. 发红包者可以设定一个0-9间任意末尾数为炸弹,凡是领完红包金额末尾为该数字的,需要返还发红包者1.2倍的金额,其余的正常领取红包。
例如30-3,如果有领红包者为5.03、0.33、6.73之类以3为末尾的红包金额,就需要返还发红包者30*1.2=36元。
我大致看了一下知乎上关于微信的算法,本来是想total-0.01*(n-1)作为可领取红包总金额,但是实际操作了一下发现实际红包差额太大,将随机金额数缩小了范围,比如100元10人的红包 上限就定在(100/10)*2,后来有发现最后2个红包可能会超出总金额,又对倒数第二个红包加了限制,如下是php代码,运算结果也会贴在下方。
代码不是很优雅,望见谅
<?php
class RedPacket{
public $total = 30 ; //总金额
public $least = 0.01; //人均最少
public $num = 9; //红包人数
public $sum = 0; //可红包领取金额
public static $a0 = 0; //0
public static $a1 = 0; //1
public static $a2 = 0; //2
public static $a3 = 0; //3
public static $a4 = 0; //4
public static $a5 = 0; //5
public static $a6 = 0; //6
public static $a7 = 0; //7
public static $a8 = 0; //8
public static $a9 = 0; //9
public function SendRedPacket(){
//循环9次领取红包
for($i=1;$i<10;$i++) {
//计算可发红包金额 每人最少0.01元
$this->sum = $this->total - ($this->num - $i) * $this->least;
//判断是否是最后一个红包
if ($i < 9) {
$redpacket = rand(1, ($this->sum * 100) / ($this->num - $i) * 2) / 100;
//判断发出的红包总计如果超出总和,则重新计算
if (($this->total - $redpacket) < 0) {
$redpacket = rand(1, ($this->sum * 100) / ($this->num - $i)) / 100;
}
$this->total -= $redpacket;
} else {
//最后一个红包就是剩余金额
$redpacket = $this->total;
$this->total = 30;
}
$red = sprintf('%.2f', $redpacket);
//截取红包金额末位
$number = substr($red, -1, 1);
switch ($number) {
case 0:
self::$a0++;
break;
case 1:
self::$a1++;
break;
case 2:
self::$a2++;
break;
case 3:
self::$a3++;
break;
case 4:
self::$a4++;
break;
case 5:
self::$a5++;
break;
case 6:
self::$a6++;
break;
case 7:
self::$a7++;
break;
case 8:
self::$a8++;
break;
case 9:
self::$a9++;
break;
}
}
}
public function Show(){
//显示各数字概率
echo '0: '.((self::$a0)).'%'."<br/>".
'1: '.((self::$a1)).'%'."<br/>".
'2: '.((self::$a2)).'%'."<br/>".
'3: '.((self::$a3)).'%'."<br/>".
'4: '.((self::$a4)).'%'."<br/>".
'5: '.((self::$a5)).'%'."<br/>".
'6: '.((self::$a6)).'%'."<br/>".
'7: '.((self::$a7)).'%'."<br/>".
'8: '.((self::$a8)).'%'."<br/>".
'9: '.((self::$a9)).'%'."<br/>";
}
}
$red = new RedPacket();
//设置发包次数
for($i=0;$i<100000;$i++){
$red->SendRedPacket();
}
//展示红包数
$red->Show();
以下是我循环10万次结果总结出的数据:
0: 88.405%
1: 91.235%
2: 91.51%
3: 90.684%
4: 90.814%
5: 89.692%
6: 90.132%
7: 89.337%
8: 89.333%
9: 88.858%
以上数据仅根据我的算法得出,实际和微信的还有差距,总体每个数字的概率还是趋近于90%,可能还是因为算法问题会有部分差异。
感觉在php中,对于算法的需求并没有那么大,所以偶尔敲敲玩玩还是蛮不错的。