自己手头上一个棋牌项目,之前运行一直正常,奇怪的是最近几天客户一直反应说系统发出的牌居然好几幅发到手上是一样的,更奇怪的是同桌的其他玩家手头上也拿到了相同的牌。于是经过仔细分析研究,可能是因为前几天升级了服务器上最新的PHP版本有关。
我们先来看下原先发牌的基本实现原理
因为一副牌用数组表示, 所以我们可以通过用PHP自带的 shuffle() 打乱数组的函数实现随机发牌的效果
//打乱一副牌
public static function cardsUpset($cards)
{
$rand = mt_rand(1,100); //为了达到更加随机的效果 我们随机一个洗牌次数
for($i=0;$i<$rand;$i++){ //根据随机洗牌次数进行洗牌
shuffle($cards);
}
return $cards;
}
以上代码看似正常,但是在PHP7.3.4的版本环境下,根据记录的日志,出现的重复率居然极高,于是上网查找了相关资料,发现PHP7有个新的随机数函数 random_int() ,并且官网建议替代 mt_rand() 函数使用。 如下图
既然官网说这个函数可以用于扑克游戏的发牌 ,那么就用这个随机函数写一个自定义的发牌方法就可以了。
思路是这样的,通过 random_int 的随机数 每次获取一个当前数组 0到数组最大值之间的随机数,将随机内容放入新的数组,删除随机索引,重新排序。
//打乱一副牌
public static function cardsUpset($cards){
$tmpCards = $cards; //复制一副牌作为缓存变量
$newCards = []; //新键一个空数组作为
$count = count($tmpCards); //获取数组最大数量进行遍历
for($i=0;$i<$count;$i++){ //遍历所有的数字
sort($tmpCards); //强制排序缓存牌
$max = count($tmpCards); //判断缓存牌里数组的最大数量
$index = random_int(1,$max); //生成一个随机的索引
$index--; //由于数组从 0表示 所以需要把索引减1
$newCards[]=$tmpCards[$index]; //将内容放入新的数组里
unset($tmpCards[$index]); //删除缓存数组当前索引记录
}
return $newCards;
}
通过以上方法我们实现了多次随机发牌的逻辑,并且把牌打得更散。