[code snippet]微信随机红包算法实现

class RedEnvelopeError(ValueError):
    """
    红包赋值错误
    """


class RedEnvelope:

    def __init__(self, name=None):
        self.name = 'red_envelope:{}'.format(uuid.uuid1().hex) if name is None else name

    def generate(self, total_amount=10000, count=10, min_amount=100, max_amount=20000, shuffle=False, unique=True):
        """
        :param total_amount: 红包总金额,单位为分
        :param count: 红包总个数
        :param min_amount: 最小红包金额,单位为分,不可小于100,默认100
        :param max_amount: 最大红包金额,单位为分,不可大于20000,默认20000
        :param shuffle: 打乱顺序
        :param unique: 是否可重复领取
        """
        remain_amount = total_amount - count * min_amount
        if count == 0 or max_amount < min_amount or remain_amount < 0:
            raise RedEnvelopeError

        red_envelopes = []
        for remain_count in range(count, 0, -1):
            if remain_count == 1:
                last_amount = min(max_amount, total_amount - sum(red_envelopes))
                red_envelopes.append(last_amount)
                break
            amount = random.random() * (remain_amount * 2 / remain_count)
            if remain_amount <= amount:
                amount = 0
            amount = min(max_amount - min_amount, amount)
            remain_amount -= amount
            amount = int(amount + min_amount)
            red_envelopes.append(amount)

        if shuffle:
            random.shuffle(red_envelopes)

为了保证不会出现领取的红包比0还小的情况,也就是说要保证每个人都能至少领到min_amount大小的红包,所以只对排除“低保”后的金额remain_amount做随机。

针对最后一个红包,要把所有剩余的金额全拿走,防止剩余。

实际分配的金额amount既不能比剩余金额remain_amount大,也不能超过max_amount - min_amount

参考:

微信红包的随机算法是怎样实现的?
陈鹏先生的代码大致意思是这样的:假设有100元钱,分给十个人。那么第一个人获得红包大小怎么计算呢?100/10 = 10元。这是期望值。从0.01到20的区间中(其中20=10乘以2)随机抽取一个数,就是第一个人获得红包的大小。假设第一个人获得了15元,那么剩下的85元平均分给9个人,这九个人平均获得红包大小为9.4元,那么第二个人的红包大小均匀分布于0.01元到18.80元的区间中,依次类推。算法保证最后一个人至少抽到0.01元。
作者:Mr.L
链接:https://www.zhihu.com/question/22625187/answer/85431684
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:([code snippet]微信随机红包算法实现)