• 抽奖活动 算法设计


    场景

    • 线上抽奖
    • 活动方设定了奖品数量,不允许超发

    项目变数

    • 参与人数未知
    • 活动持续时间未知(活动方可能根据活动热度增减时间,以月为单位)
    • 可预见的『老板需求』:活动人数太多了,临时增加1个大奖 & 无数个小奖。或者大奖太少,临时增加出大奖概率刺激活动效果。

    举例:奖池设定

    • 一等奖: 2个
    • 二等奖:30个
    • 三等奖:500个
    • 四等奖:20000个

    实现方案讨论

    • rand 程序随机? 可能会超发,据说有策划团队已经赔过钱了
    • 提前把奖品数量转化为数据库的记录。用户抽奖时,利用数据库的随机查询 select * from 奖池表 where status = '未被抽中' order by rand() limit 0,1 。问题:记录数太多,调整(增减)奖品数量不灵活,方案不优雅

    最终方案

    • 每次开奖结果:rand(1, 当时的奖品总数) ,具体看代码
    • 优势:随时增减奖池数量,没有关联其它表(灵活、解耦),不会超发

    代码

    <?php
    // 设置的奖品信息
    $priceInfo = [
        '102'  => 3, // 奖品id,奖品数量
        '203'  => 10,
        '3092' => 100,
    ];
    
    // 抽奖函数
    function getPrice(&$priceInfo)
    {
        if (!array_sum($priceInfo)) {
            return 0; //奖池已空
        }
        $randId = rand(1, array_sum($priceInfo)); // 170
    
        $i = 0;
        foreach ($priceInfo as $id => $num) {
            $i += $num;
            if ($i >= $randId) {
                $priceInfo[$id]--;
                return $id;
            }
        }
    }
    // 模拟100次抽奖
    for ($i = 0; $i < 130; $i++) {
        echo "
     中奖ID: " . getPrice($priceInfo);
    }
    
    //剩余的奖品
    echo "
     奖池状态:
    ";
    print_r($priceInfo);
    
  • 相关阅读:
    go ERROR invalid character '<' looking for beginning of value
    C#实现将网址生成二维码图片
    二、WPF入门教程——Bingding学习
    一、WPF入门教程——创建WPF项目
    C#实现DataTable行列转置
    VBS整蛊代码
    Task.WhenAll和Task.WhenAny
    Task.WaitAll和Task.WaitAny
    CancellationTokenSource
    组合ContinueWith
  • 原文地址:https://www.cnblogs.com/dormscript/p/14486090.html
Copyright © 2020-2023  润新知