分红包函数 | 青训营笔记

127 阅读3分钟

这是我参与「第五届青训营」笔记创作活动的第 15 天

前言

相信大家在日常使用微信或者其他社交软件的时候,都会遇到“抢红包”这一功能,那么这样一个分红包的函数究竟是如何实现的呢?其中究竟是不是完全随机分配呢,本次将结合青训营主题课程为大家介绍其中的两个分配红包的方法,切西瓜法和抽牌法。

设计方法

1. 切西瓜法

切西瓜法,顾名思义可以大概了解到,我们在切西瓜的时候都会尽量使每一个西瓜大小均分,切西瓜函数正是借用了这一方法

首先,需要找到当前数额的最大值,找到最大值后将其再次“切分”,使其变得更小一些,这样的方法可以大致的保证的我们设计的分红包中每一个红包的数额都是差不多的,代码如下所示

/**
 * '切蛋糕'函数
 * @param {Number} amount 
 * @param {String} count 
 * @returns 
 */
function generate(amount, count) {
    let ret = [amount]

    while (count > 1) {
        //跳出最大的蛋糕
        let cake = Math.max(...ret),
            //找出蛋糕的位置
            index = ret.indexOf(cake),
            //“切蛋糕”
            part = 1 + Math.floor((cake / 2) * Math.random()),
            //切完蛋糕后的剩余值
            rest = cake - part;
        //切完后的样子
        ret.splice(index, 1, part, rest)

        count--
    }
    return ret 
}

如上,我们需要传入两个参数,分别是总的金额数量以及需要分出的红包个数,随后就按刚刚说到的,将最大值不断切分,直到满足count的数量

2. 抽牌法

刚刚我们用到的切西瓜法,从函数中可以看出分配的金额是比较均匀的,但是一般情况下,我们需要红包分配的金额不那么均匀,这样才能达到“刺激”的目的

于是我们可以使用抽牌的方法,我们首先定义一个抽牌函数

/**
 * 抽牌函数 每次使用next方法可以调用一次
 */
function* draw(cards) {
    const c = [...cards]

    for (let i = c.length; i > 0; i--){
        const pIndex = Math.floor(Math.random() * i);
        [c[pIndex], c[i - 1]] = [c[i - 1], c[pIndex]]
        yield c[i - 1]
    }
}

抽牌函数的内容相信大家都能理解到,接下来我们接着定义一个generate函数来完成分红包的功能

/**
 * 分红包函数
 * @param {Number} amount 
 * @param {Number} count 
 * @returns 
 */
function generate(amount, count) {
    if (count <= 1) return [amount]
    const cards = Array(amount - 1).fill(0).map((_, i) => i + 1)
    const pick = draw(cards)
    const result = []
    for (let i = 0; i < count - 1; i++){
        result.push(pick.next().value)
    }
    result.sort((a, b) => a - b)
    result.push(amount)
    for (let i = result.length - 1; i > 0; i--){
        result[i] = result[i] - result[i - 1]
    }
    return result
}

由上所示,我们通过next方法可以从抽牌函数中获取到对应的数值,最后通过一轮for循环拿到每一个红包的数额,全部加起来刚好为amount的数值

总结

本篇文章为大家简单介绍了分红包函数的两个不同的方法,其中第一个分出来的数额更趋向平均化,第二个函数的数值纯凭运气来获得更高的数额,更满足对于抢红包这一机制的要求。在青训营的课程当中,针对这两个函数给出了非常详细的解释,包括设计思路以及代码风格设计等等,非常值得大家参考学习~