Backend Development 13 min read

Analysis and Implementation of Various WeChat Red Packet Distribution Algorithms in PHP

This article examines four common WeChat red packet distribution algorithms—simple random, double‑mean, line‑segment division, and array_rand optimization—explaining their principles, PHP implementations, performance characteristics, and how to verify randomness, providing code samples and comparative analysis for developers.

DevOps
DevOps
DevOps
Analysis and Implementation of Various WeChat Red Packet Distribution Algorithms in PHP

The article introduces the problem of distributing WeChat red packets fairly and presents a catalog of five algorithmic approaches: ordinary random method, double‑mean algorithm, line‑segment division algorithm, verification of array_rand randomness, and a performance comparison.

1. Ordinary Random Method

This method treats the remaining amount as the maximum interval for a random draw, which can lead to unfairness because early recipients may receive large amounts while later users get little or nothing.

// Remaining‑value random method, simple logic but decreasing interval leads to unfairness
$res = LeftMoneyRedbag($Moneys, $userNums, $isEveryHave);
function LeftMoneyRedbag($Moneys, $userNums, $isEveryHave = 1, $baseMoney = 1) {
    if ($Moneys <= 0 || $userNums <= 0) {
        return ['code' => -3, 'msg' => 'Invalid amount or user count'];
    }
    if ($isEveryHave && $userNums > $Moneys) {
        return ['code' => -4, 'msg' => 'Insufficient red packets'];
    }
    if ($isEveryHave) {
        $Moneys = $Moneys - ($userNums * $baseMoney);
    }
    $userMoney = [];
    $leftMoneys = $Moneys;
    $leftUserNums = $userNums;
    while ($leftUserNums > 1) {
        $RandVal = 0;
        if ($leftMoneys > 0) {
            $RandVal = mt_rand(0, $leftMoneys);
            $leftMoneys -= $RandVal;
        }
        $userMoney[] = $isEveryHave ? ($baseMoney + $RandVal) : $RandVal;
        $leftUserNums--;
    }
    $userMoney[] = $isEveryHave ? ($baseMoney + $leftMoneys) : $leftMoneys;
    return ['code' => 0, 'msg' => "success", 'redbag' => $userMoney];
}

2. Double‑Mean Algorithm

This algorithm sets the maximum random interval to twice the average of the remaining amount, producing a more balanced distribution. It can be extended to triple‑mean or quadruple‑mean for greater randomness.

function doubleMeanRedbag($Moneys, $userNums, $isEveryHave = 1, $baseMoney = 1) {
    if ($Moneys <= 0 || $userNums <= 0) {
        return ['code' => -3, 'msg' => 'Invalid amount or user count'];
    }
    if ($isEveryHave && $userNums > $Moneys) {
        return ['code' => -4, 'msg' => 'Insufficient red packets'];
    }
    if ($isEveryHave) {
        $Moneys = $Moneys - ($userNums * $baseMoney);
    }
    $userMoney = [];
    $leftMoneys = $Moneys;
    $leftUserNums = $userNums;
    while ($leftUserNums > 1) {
        $RandVal = 0;
        if ($leftMoneys > 0) {
            $doubleMeans = ceil($leftMoneys / $leftUserNums * 2);
            $RandVal = mt_rand(0, $doubleMeans);
            $leftMoneys -= $RandVal;
        }
        $userMoney[] = $isEveryHave ? ($baseMoney + $RandVal) : $RandVal;
        $leftUserNums--;
    }
    $userMoney[] = $isEveryHave ? ($baseMoney + $leftMoneys) : $leftMoneys;
    return ['code' => 0, 'msg' => "success", 'redbag' => $userMoney];
}

3. Line‑Segment Division Algorithm

The idea is to view the total amount as a line segment and randomly pick N‑1 cut points, then the distances between consecutive points become each user’s share. The basic version suffers from cut‑point collisions when the number of users approaches the total amount.

function lineSegmentRedbag($Moneys, $userNums, $isEveryHave = 1, $baseMoney = 1) {
    if ($Moneys <= 0 || $userNums <= 0) {
        return ['code' => -3, 'msg' => 'Invalid amount or user count'];
    }
    if ($isEveryHave && $userNums > $Moneys) {
        return ['code' => -4, 'msg' => 'Insufficient red packets'];
    }
    $cutPoints = [];
    $pointNums = $userNums - 1;
    while ($pointNums > 0) {
        $randVal = $isEveryHave ? mt_rand(1, $Moneys - 1) : mt_rand(0, $Moneys);
        if (in_array($randVal, $cutPoints)) {
            continue; // collision, retry
        }
        $cutPoints[] = $randVal;
        $pointNums--;
    }
    sort($cutPoints);
    $lastVal = 0;
    $userMoney = [];
    foreach ($cutPoints as $RandPoint) {
        $userMoney[] = $RandPoint - $lastVal;
        $lastVal = $RandPoint;
    }
    $userMoney[] = $Moneys - $lastVal;
    return ['code' => 0, 'msg' => "success", 'redbag' => $userMoney];
}

3.2 Optimized Version Using array_rand

By converting the amount into an array and using array_rand to pick multiple indices at once, the algorithm obtains unique cut points without manual collision handling, improving performance dramatically.

function lineSegmentOptimize($Moneys, $userNums, $isEveryHave = 1) {
    if ($Moneys <= 0 || $userNums <= 0) {
        return ['code' => -3, 'msg' => 'Invalid amount or user count'];
    }
    if ($isEveryHave && $userNums > $Moneys) {
        return ['code' => -4, 'msg' => 'Insufficient red packets'];
    }
    $MoneysArr = $isEveryHave ? array_fill(1, $Moneys - 1, 0) : array_fill(0, $Moneys + 1, 0);
    if ($userNums == 1) {
        return ['code' => 0, 'msg' => "success", 'redbag' => [$Moneys]];
    }
    $cutPoints = array_rand($MoneysArr, $userNums - 1);
    sort($cutPoints);
    $lastVal = 0;
    $userMoney = [];
    foreach ($cutPoints as $randPoint) {
        $userMoney[] = $randPoint - $lastVal;
        $lastVal = $randPoint;
    }
    $userMoney[] = $Moneys - $lastVal;
    return ['code' => 0, 'msg' => "success", 'redbag' => $userMoney];
}

4. Verifying array_rand Randomness

A test repeatedly draws multiple indices from a range and records occurrence counts, confirming that array_rand returns unique values and covers the full interval, including both ends.

function checkRand($range, $num) {
    $statiArr = array_fill(0, $range, 0);
    $sourceArr = range(0, $range - 1);
    for ($i = 0; $i < $num; $i++) {
        $indexArr = array_rand($sourceArr, 4);
        foreach ($indexArr as $index) {
            $statiArr[$index]++;
        }
    }
    return $statiArr;
}

5. Performance Comparison

The article measures execution time for the plain line‑segment algorithm versus the optimized version and the double‑mean method, showing that the optimized line‑segment approach is the fastest, even beating double‑mean.

function microTime_float() {
    list($usec, $sec) = explode(' ', microtime());
    return ((float)$usec + (float)$sec);
}
$starTime = microTime_float();
for ($i = 0; $i < 100000; $i++) {
    lineSegmentRedbag($Moneys, $userNums, $isEveryHave);
    // lineSegmentOptimize(...);
    // doubleMeanRedbag(...);
}
$endTime = microTime_float();
$diff = $endTime - $starTime;
echo "Line segment time diff: " . $diff . "
";

Graphs included in the original article illustrate that the optimized line‑segment algorithm has a larger random interval than double‑mean and that its performance remains stable even when the number of users approaches the total amount.

Conclusion

The four algorithms each have trade‑offs between fairness, randomness, and computational cost. The optimized line‑segment method using array_rand offers the best balance for large‑scale red‑packet distribution.

Promotional Note

The article ends with a promotion for a free technical book giveaway and a training program on R&D efficiency (DevOps), encouraging readers to share the poster, collect likes, and sign up before the deadline.

BackendPerformancealgorithmPHPRed Packetrandomness
DevOps
Written by

DevOps

Share premium content and events on trends, applications, and practices in development efficiency, AI and related technologies. The IDCF International DevOps Coach Federation trains end‑to‑end development‑efficiency talent, linking high‑performance organizations and individuals to achieve excellence.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.