# 编程
# 红包
作者 / 橱柜扫地僧
去看了《流浪地球》,中国人到了任何时候都想着放烟花嘞 🤔,
不过这已经是一部很好的科幻片了:
建议都去看看
除了烟花,春节怕是离不开红包。春节红包满天飞,在好友群里面可以抢到最大的红包也算是一件高兴的事情了。对于微信红包机制的研究很多,这里就展示一种基于 Redis 实现简单的红包分配算法,逻辑简单,5分钟就可以看完。
下载代码
https://github.com/woojean/demos/tree/master/redis-hongbao
/**
* 生成红包函数
* $totalMoney 总金额
* $num 红包数量
* $min 红包最小值
*/function gen($totalMoney, $num, $min='0.01'){
// 分配结果 $ret = [];
// 剩余红包金额 $remainMoney = $totalMoney;
for ( $i = 1; $i < $num; $i++) {
// 剩余红包数量 $remainNum = $num-$i;
// 当前可领取的红包的最大值 $remainMax = ($remainMoney-$remainNum*$min)/$remainNum;
$allocateMoney = mt_rand($min*100, $remainMax*100)/100;
$remainMoney = $remainMoney-$allocateMoney;
$ret[$i] = array(
'allocation' => $allocateMoney,
'remainder' => $remainMoney
);
}
// 处理最后一个 $ret[$num] = [
'allocation'=>$remainMoney,
'remainder'=>0
];
return $ret;}// ======================= demo ========================// 红包总金额$totalMoney = 10; // 红包总数$num = 10; $redis = new Redis();$redis->connect('127.0.0.1', 6379);// 库存队列$mapStock = 'queue_stock'; // 已抢队列 uid => hongbao$mapGrab = 'queue_grab'; // 剩余红包索引
$listIndexs = 'list_indexs'; $allocated = $redis->hlen($mapGrab);if($allocated == $num){
echo '已抢光!';
exit;}$inited = $redis->hlen($mapStock);// 如果索引尚未生成,生成红包库存if( 0 == $inited ){
// 生成红包库存 $stock = gen($totalMoney,$num);
// 存储红包索引 foreach($stock as $index => $hongbao){
$redis->hset($mapStock, $index, json_encode($hongbao));
$redis->lpush($listIndexs,$index);
}}// 获取用户ID$uid = intval($_GET['uid']);if( $uid < 1){
echo '用户ID非法!';
exit;}// 判断用户是否已经抢过红包$participated = $redis->hexists($mapGrab,$uid);if($participated){
echo '不能重复参加!';
exit;}// 分配红包给用户(原子操作,关键!)$index = $redis->lpop($listIndexs);if(intval($index) < 1){
echo '已抢光!';
exit;}// todo 操作失败后,将红包的索引push回去$hongbao = $redis->hget($mapStock, $index);$redis->hset($mapGrab, $uid, json_encode($hongbao));echo $uid.' -> ' . json_encode($hongbao);