PHP一文带你搞懂游戏中的抽奖算法

作者:PHP开源社区 时间:2024-06-05 09:38:21 

前言

没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。

希望:所以说,树倒了,没有一片雪花是无辜的,抽奖都是假的,只有人家想让你中和不想让你中,如果大家觉得文章有帮助,欢迎点赞。

一、初始化奖品

  • id 奖品的id

  • pid 奖品的自定义id

  • type 奖品类型,1、虚拟奖品 2、实物奖品 3、礼包码 待扩充

  • name 奖品名称

  • total 奖品总数

  • chance 获奖概率/抽奖基数10000

  • daynum 每日数量限制

  • pay 充值限制

<?php
$prize = [
   ['id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],
   ['id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
   ['id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
   ['id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]
];

 奖品详情应该从数据库中读出来

奖品详情应该加入缓存,避免数据库的压力

二、谢谢参与

<?php
$thanks_prize = [
   'id' => 0,
   'pid' => 0,
   'type' => 1,
   'name' => '谢谢参与'
];

为填充剩余概率的奖品

三、过滤抽奖、如充值条件

<?php
$pay_total = 7000;
foreach ($prize as $key => $value) {
   if($value['pay'] > $pay_total) unset($prize[$key]);
}

初步过滤一些必要因素,比如充值,角色创建时间等

四、重组概率

<?php
$now_chance = array_sum(array_column($prize, 'chance'));
$remain_chance = 10000 - $now_chance;
$prize[] = ['id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];

$award = [];
$num = 0;
foreach ($prize as $_v) {
   $num += $_v['chance'];
   $award[] = ['id' => $_v['id'], 'pid' => $_v['pid'], 'type' => $_v['type'], 'name' => $_v['name'], 'total' => $_v['total'], 'chance' => $num, 'daynum' => $_v['daynum'], 'pay' => $_v['pay']];
}

初步过滤后,重构新的抽奖信息,加入谢谢参与

第二步重组概率

五、进行抽奖

<?php
$rand = mt_rand(1, 10000);
$result = [];
foreach ($award as $_k => $_v) {
   if ($_k == 0) {
       if ($rand > 0 && $rand <= $_v['chance']) {
           $result = $_v;
           break;
       }
   } else {
       if ($rand > $award[$_k - 1]['chance'] && $rand <= $_v['chance']) {
           $result = $_v;
           break;
       }
   }
}

开始抽奖,并返回抽中的结果

六、过滤回调

<?php
//此处应该查询数据库,查看该奖品已经抽中的数量
$yet_num = 50;
if($result['pid'] != 0 && $yet_num > $result['total']) {
   $result = $thanks_prize;
}

//此处应该查询数据库,查看该奖品今日已经抽中的数量
$yet_today_num = 50;
if($result['pid'] != 0 && $yet_today_num > $result['daynum']) {
   $result = $thanks_prize;
}

二次过滤,奖品总数的限制以及奖品的每日限制等 

七、最终抽奖结果

<?php
//删除敏感字段
unset($result['total'],$result['chance'],$result['daynum'],$result['pay']);

//返回最终抽奖结果
echo json_encode([
   'prize' => $award,
   'rand' => $rand,
   'result' => $result
]);

八、抽奖封装成类

<?php
/**
* Created by PhpStorm.
* User: autofelix
* Date: 2020/10/30
* Time: 13:14
* Desc: 抽奖算法
*/

class Lottery
{
   /**
    * 概率基数
    * @var int
    */
   private $total_chance = 10000;

/**
    * 谢谢参与奖励
    * @var array
    */
   private $thanks_prize = [
       'id' => 0,
       'pid' => 0,
       'type' => 1,
       'name' => '谢谢参与'
   ];

/**
    * 奖池
    * @var array
    */
   private $prize = [
       ['id' => 1, 'pid' => 11, 'type' => 1, 'name' => '典藏英雄', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 2000 ],
       ['id' => 2, 'pid' => 12, 'type' => 1, 'name' => '史诗皮肤', 'total' => 40, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
       ['id' => 3, 'pid' => 13, 'type' => 1, 'name' => '钻石奖励', 'total' => 80, 'chance' => 1000, 'daynum' => 10, 'pay' => 4000 ],
       ['id' => 4, 'pid' => 14, 'type' => 1, 'name' => '荣耀水晶', 'total' => 20, 'chance' => 1000, 'daynum' => 10, 'pay' => 8000 ]
   ];

/**
    * Lottery constructor.
    */
   public function __construct()
{
   }

/**
    * @return int
    */
   private function get_user_pay()
{
       //这里应该调用接口,返回用户正确的充值信息
       return 3000;
   }

/**
    * 重构奖池、重组概率
    * @return array
    */
   private function init_lottery_pond()
{
       $award = [];

//充值限制
       $user_pay = $this->get_user_pay();
       foreach ($this->prize as $key => $value) {
           if($value['pay'] <= $user_pay) unset($this->prize[$key]);
       }

//加入谢谢惠顾
       $now_chance = array_sum(array_column($this->prize, 'chance'));
       $remain_chance = $this->total_chance - $now_chance;
       $this->prize[] = ['id' => 0, 'pid' => 0, 'type' => 1, 'name' => '谢谢参与', 'total' => 0, 'chance' => $remain_chance, 'daynum' => 0, 'pay' => 0];

//重组概率
       $num = 0;
       foreach ($this->prize as $_v) {
           $num += $_v['chance'];
           $award[] = ['id' => $_v['id'], 'pid' => $_v['pid'], 'type' => $_v['type'], 'name' => $_v['name'], 'total' => $_v['total'], 'chance' => $num, 'daynum' => $_v['daynum'], 'pay' => $_v['pay']];
       }

return $award;
   }

/**
    * 获取抽奖结果
    * @return array
    */
   public function get_prize()
{
       $award = $this->init_lottery_pond();
       $rand = mt_rand(1, $this->total_chance);
       $result = [];
       foreach ($award as $_k => $_v) {
           if ($_k == 0) {
               if ($rand > 0 && $rand <= $_v['chance']) {
                   $result = $_v;
                   break;
               }
           } else {
               if ($rand > $award[$_k - 1]['chance'] && $rand <= $_v['chance']) {
                   $result = $_v;
                   break;
               }
           }
       }

$result = $this->filter($result);
       return $result;
   }

/**
    * 抽奖过滤回调函数
    * @param $result
    * @return array
    */
   public function filter($result)
{
       //奖品总数限制,此处应该查数据库
       $yet_num = 50;
       if($result['pid'] != 0 && $yet_num > $result['total']) {
           $result = $this->thanks_prize;
       }

//奖品每日数量限制,此处应该查数据库
       $yet_today_num = 50;
       if($result['pid'] != 0 && $yet_today_num > $result['daynum']) {
           $result = $this->thanks_prize;
       }

//不暴露敏感信息
       unset($result['total'], $result['chance'], $result['daynum'], $result['pay'] );
       return $result;
   }

private function __clone()
{
   }
}

echo json_encode((new Lottery())->get_prize());

来源:https://mp.weixin.qq.com/s/19u6Ag06IntC_2ohijhRhg

标签:PHP,抽奖,算法
0
投稿

猜你喜欢

  • python怎么自定义捕获错误

    2022-05-25 02:57:35
  • ASP程序员面试题

    2011-09-15 20:51:20
  • 基于python的opencv图像处理实现对斑马线的检测示例

    2021-07-30 23:02:44
  • apache部署python程序出现503错误的解决方法

    2022-01-12 20:37:21
  • Python中列表(list)操作方法汇总

    2023-11-12 06:16:33
  • pandas按条件筛选数据的实现

    2021-10-04 03:07:54
  • SQL Server 2008 清空删除日志文件(瞬间缩小日志到几M)

    2024-01-21 16:20:52
  • asp实现在线人数统计代码

    2008-08-10 18:35:00
  • firefox浏览器不支持innerText的解决方法

    2024-04-10 10:51:42
  • Python中的通函数numpy.ufunc详解

    2023-09-03 22:52:08
  • python3使用pandas获取股票数据的方法

    2023-01-04 15:01:15
  • 基于python计算滚动方差(标准差)talib和pd.rolling函数差异详解

    2023-04-09 17:28:45
  • 利用20行Python 代码实现加密通信

    2023-04-22 06:18:54
  • 自动完成JS类(纯JS, Ajax模式)

    2024-05-11 09:41:59
  • python3.5的包存放的具体路径

    2023-11-27 21:11:21
  • python 实现语音聊天机器人的示例代码

    2021-03-24 14:36:07
  • PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解

    2023-01-10 23:36:00
  • Js实现仿msn的右下角popup提示窗口

    2007-12-27 20:30:00
  • 利用Python写一个爬妹子的爬虫

    2021-07-22 12:44:51
  • Golang异常处理之defer,panic,recover的使用详解

    2023-08-06 14:20:09
  • asp之家 网络编程 m.aspxhome.com